diff --git a/dap-sdk/core/include/dap_fnmatch.h b/dap-sdk/core/include/dap_fnmatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..9afaba94581823c6ae1c909b7d18cce9a712c2b5
--- /dev/null
+++ b/dap-sdk/core/include/dap_fnmatch.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _FNMATCH_H
+#define _FNMATCH_H  1
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* We #undef these before defining them because some losing systems
+   (HP-UX A.08.07 for example) define these in <unistd.h>.  */
+#undef  FNM_PATHNAME
+#undef  FNM_NOESCAPE
+#undef  FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'.  */
+#define FNM_PATHNAME    (1 << 0) /* No wildcard can ever match `/'.  */
+#define FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
+#define FNM_PERIOD  (1 << 2) /* Leading `.' is matched only explicitly.  */
+
+#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
+# define FNM_FILE_NAME   FNM_PATHNAME   /* Preferred GNU name.  */
+# define FNM_LEADING_DIR (1 << 3)   /* Ignore `/...' after a match.  */
+# define FNM_CASEFOLD    (1 << 4)   /* Compare without regard to case.  */
+# define FNM_EXTMATCH    (1 << 5)   /* Use ksh-like extended matching. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
+#define FNM_NOMATCH 1
+
+/* This value is returned if the implementation does not support
+   `fnmatch'.  Since this is not the case here it will never be
+   returned but the conformance test suites still require the symbol
+   to be defined.  */
+#ifdef _XOPEN_SOURCE
+# define FNM_NOSYS  (-1)
+#endif
+
+/* Match NAME against the filename pattern PATTERN,
+   returning zero if it matches, FNM_NOMATCH if not.  */
+extern int dap_fnmatch (const char *__pattern, const char *__name, int __flags);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/dap-sdk/core/include/dap_fnmatch_loop.h b/dap-sdk/core/include/dap_fnmatch_loop.h
new file mode 100644
index 0000000000000000000000000000000000000000..550b5d80164380aea6aecbb092cd3dcbf60004c1
--- /dev/null
+++ b/dap-sdk/core/include/dap_fnmatch_loop.h
@@ -0,0 +1,1223 @@
+/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "dap_fnmatch.h"
+
+struct STRUCT
+{
+  const char *pattern;
+  const char *string;
+  int no_leading_period;
+};
+
+#define L_func(CS)  CS
+/* Global variable.  */
+static int posixly_correct;
+#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+   it matches, nonzero if not.  */
+static int FCT (const char *pattern, const char *string,
+        const char *string_end, int no_leading_period, int flags,
+        struct STRUCT *ends, size_t alloca_used);
+static int EXT (int opt, const char *pattern, const char *string,
+        const char *string_end, int no_leading_period, int flags,
+        size_t alloca_used);
+static const char *END (const char *patternp);
+
+static int
+FCT (const char *pattern, const char *string, const char *string_end,
+     int no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used)
+{
+  const char *p = pattern, *n = string;
+  unsigned char c;
+#ifdef _LIBC
+# if WIDE_CHAR_VERSION
+  const char *collseq = (const char *)
+    _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+# else
+  const unsigned char *collseq = (const unsigned char *)
+    _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+# endif
+#endif
+
+  while ((c = *p++) != '\0')
+    {
+      int new_no_leading_period = 0;
+      c = FOLD (c);
+
+      switch (c)
+    {
+    case '?':
+      if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+        {
+          int res = EXT (c, p, n, string_end, no_leading_period,
+                 flags, alloca_used);
+          if (res != -1)
+        return res;
+        }
+
+      if (n == string_end)
+        return FNM_NOMATCH;
+      else if (*n == '/' && (flags & FNM_FILE_NAME))
+        return FNM_NOMATCH;
+      else if (*n == '.' && no_leading_period)
+        return FNM_NOMATCH;
+      break;
+
+    case '\\':
+      if (!(flags & FNM_NOESCAPE))
+        {
+          c = *p++;
+          if (c == '\0')
+        /* Trailing \ loses.  */
+        return FNM_NOMATCH;
+          c = FOLD (c);
+        }
+      if (n == string_end || FOLD ((unsigned char) *n) != c)
+        return FNM_NOMATCH;
+      break;
+
+    case '*':
+      if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+        {
+          int res = EXT (c, p, n, string_end, no_leading_period,
+                 flags, alloca_used);
+          if (res != -1)
+        return res;
+        }
+      else if (ends != NULL)
+        {
+          ends->pattern = p - 1;
+          ends->string = n;
+          ends->no_leading_period = no_leading_period;
+          return 0;
+        }
+
+      if (n != string_end && *n == '.' && no_leading_period)
+        return FNM_NOMATCH;
+
+      for (c = *p++; c == '?' || c == '*'; c = *p++)
+        {
+          if (*p == '(' && (flags & FNM_EXTMATCH) != 0)
+        {
+          const char *endp = END (p);
+          if (endp != p)
+            {
+              /* This is a pattern.  Skip over it.  */
+              p = endp;
+              continue;
+            }
+        }
+
+          if (c == '?')
+        {
+          /* A ? needs to match one character.  */
+          if (n == string_end)
+            /* There isn't another character; no match.  */
+            return FNM_NOMATCH;
+          else if (*n == '/'
+               && __builtin_expect (flags & FNM_FILE_NAME, 0))
+            /* A slash does not match a wildcard under
+               FNM_FILE_NAME.  */
+            return FNM_NOMATCH;
+          else
+            /* One character of the string is consumed in matching
+               this ? wildcard, so *??? won't match if there are
+               less than three characters.  */
+            ++n;
+        }
+        }
+
+      if (c == '\0')
+        /* The wildcard(s) is/are the last element of the pattern.
+           If the name is a file name and contains another slash
+           this means it cannot match, unless the FNM_LEADING_DIR
+           flag is set.  */
+        {
+          int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
+
+          if (flags & FNM_FILE_NAME)
+        {
+          if (flags & FNM_LEADING_DIR)
+            result = 0;
+          else
+            {
+              if (MEMCHR (n, '/', string_end - n) == NULL)
+            result = 0;
+            }
+        }
+
+          return result;
+        }
+      else
+        {
+          const char *endp;
+          struct STRUCT end;
+
+          end.pattern = NULL;
+          endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? '/' : '\0',
+                 string_end - n);
+          if (endp == NULL)
+        endp = string_end;
+
+          if (c == '['
+          || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0
+              && (c == '@' || c == '+' || c == '!')
+              && *p == '('))
+        {
+          int flags2 = ((flags & FNM_FILE_NAME)
+                ? flags : (flags & ~FNM_PERIOD));
+
+          for (--p; n < endp; ++n, no_leading_period = 0)
+            if (FCT (p, n, string_end, no_leading_period, flags2,
+                 &end, alloca_used) == 0)
+              goto found;
+        }
+          else if (c == '/' && (flags & FNM_FILE_NAME))
+        {
+          while (n < string_end && *n != '/')
+            ++n;
+          if (n < string_end && *n == '/'
+              && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags,
+                   NULL, alloca_used) == 0))
+            return 0;
+        }
+          else
+        {
+          int flags2 = ((flags & FNM_FILE_NAME)
+                ? flags : (flags & ~FNM_PERIOD));
+
+          if (c == '\\' && !(flags & FNM_NOESCAPE))
+            c = *p;
+          c = FOLD (c);
+          for (--p; n < endp; ++n, no_leading_period = 0)
+            if (FOLD ((unsigned char) *n) == c
+            && (FCT (p, n, string_end, no_leading_period, flags2,
+                 &end, alloca_used) == 0))
+              {
+              found:
+            if (end.pattern == NULL)
+              return 0;
+            break;
+              }
+          if (end.pattern != NULL)
+            {
+              p = end.pattern;
+              n = end.string;
+              no_leading_period = end.no_leading_period;
+              continue;
+            }
+        }
+        }
+
+      /* If we come here no match is possible with the wildcard.  */
+      return FNM_NOMATCH;
+
+    case '[':
+      {
+        /* Nonzero if the sense of the character class is inverted.  */
+        const char *p_init = p;
+        const char *n_init = n;
+        int not;
+        char cold;
+        unsigned char fn;
+
+        if (posixly_correct == 0)
+          posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+        if (n == string_end)
+          return FNM_NOMATCH;
+
+        if (*n == '.' && no_leading_period)
+          return FNM_NOMATCH;
+
+        if (*n == L_func('/') && (flags & FNM_FILE_NAME))
+          /* `/' cannot be matched.  */
+          return FNM_NOMATCH;
+
+        not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
+        if (not)
+          ++p;
+
+        fn = FOLD ((unsigned char) *n);
+
+        c = *p++;
+        for (;;)
+          {
+        if (!(flags & FNM_NOESCAPE) && c == L_func('\\'))
+          {
+            if (*p == L_func('\0'))
+              return FNM_NOMATCH;
+            c = FOLD ((unsigned char) *p);
+            ++p;
+
+            goto normal_bracket;
+          }
+        else if (c == L_func('[') && *p == L_func(':'))
+          {
+            /* Leave room for the null.  */
+            char str[CHAR_CLASS_MAX_LENGTH + 1];
+            size_t c1 = 0;
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+            wctype_t wt;
+#endif
+            const char *startp = p;
+
+            for (;;)
+              {
+            if (c1 == CHAR_CLASS_MAX_LENGTH)
+              /* The name is too long and therefore the pattern
+                 is ill-formed.  */
+              return FNM_NOMATCH;
+
+            c = *++p;
+            if (c == L_func(':') && p[1] == L_func(']'))
+              {
+                p += 2;
+                break;
+              }
+            if (c < L_func('a') || c >= L_func('z'))
+              {
+                /* This cannot possibly be a character class name.
+                   Match it as a normal range.  */
+                p = startp;
+                c = L_func('[');
+                goto normal_bracket;
+              }
+            str[c1++] = c;
+              }
+            str[c1] = L_func('\0');
+
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+            wt = IS_CHAR_CLASS (str);
+            if (wt == 0)
+              /* Invalid character class name.  */
+              return FNM_NOMATCH;
+
+# if defined _LIBC && ! WIDE_CHAR_VERSION
+            /* The following code is glibc specific but does
+               there a good job in speeding up the code since
+               we can avoid the btowc() call.  */
+            if (_ISCTYPE ((unsigned char) *n, wt))
+              goto matched;
+# else
+            if (ISWCTYPE (BTOWC ((unsigned char) *n), wt))
+              goto matched;
+# endif
+#else
+            if ((STREQ (str, L_func("alnum")) && ISALNUM ((unsigned char) *n))
+            || (STREQ (str, L_func("alpha")) && ISALPHA ((unsigned char) *n))
+            || (STREQ (str, L_func("blank")) && ISBLANK ((unsigned char) *n))
+            || (STREQ (str, L_func("cntrl")) && ISCNTRL ((unsigned char) *n))
+            || (STREQ (str, L_func("digit")) && ISDIGIT ((unsigned char) *n))
+            || (STREQ (str, L_func("graph")) && ISGRAPH ((unsigned char) *n))
+            || (STREQ (str, L_func("lower")) && ISLOWER ((unsigned char) *n))
+            || (STREQ (str, L_func("print")) && ISPRINT ((unsigned char) *n))
+            || (STREQ (str, L_func("punct")) && ISPUNCT ((unsigned char) *n))
+            || (STREQ (str, L_func("space")) && ISSPACE ((unsigned char) *n))
+            || (STREQ (str, L_func("upper")) && ISUPPER ((unsigned char) *n))
+            || (STREQ (str, L_func("xdigit")) && ISXDIGIT ((unsigned char) *n)))
+              goto matched;
+#endif
+            c = *p++;
+          }
+#ifdef _LIBC
+        else if (c == L_func('[') && *p == L_func('='))
+          {
+            /* It's important that STR be a scalar variable rather
+               than a one-element array, because GCC (at least 4.9.2
+               -O2 on x86-64) can be confused by the array and
+               diagnose a "used initialized" in a dead branch in the
+               findidx function.  */
+            unsigned char str;
+            uint32_t nrules =
+              _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+            const char *startp = p;
+
+            c = *++p;
+            if (c == L_func('\0'))
+              {
+            p = startp;
+            c = L_func('[');
+            goto normal_bracket;
+              }
+            str = c;
+
+            c = *++p;
+            if (c != L_func('=') || p[1] != L_func(']'))
+              {
+            p = startp;
+            c = L_func('[');
+            goto normal_bracket;
+              }
+            p += 2;
+
+            if (nrules == 0)
+              {
+            if ((unsigned char) *n == str)
+              goto matched;
+              }
+            else
+              {
+            const int32_t *table;
+# if WIDE_CHAR_VERSION
+            const int32_t *weights;
+            const wint_t *extra;
+# else
+            const unsigned char *weights;
+            const unsigned char *extra;
+# endif
+            const int32_t *indirect;
+            int32_t idx;
+            const unsigned char *cp = (const unsigned char *) &str;
+
+# if WIDE_CHAR_VERSION
+            table = (const int32_t *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
+            weights = (const int32_t *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
+            extra = (const wint_t *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
+            indirect = (const int32_t *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
+# else
+            table = (const int32_t *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+            weights = (const unsigned char *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+            extra = (const unsigned char *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+            indirect = (const int32_t *)
+              _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+# endif
+
+            idx = FINDIDX (table, indirect, extra, &cp, 1);
+            if (idx != 0)
+              {
+                /* We found a table entry.  Now see whether the
+                   character we are currently at has the same
+                   equivalance class value.  */
+                int len = weights[idx & 0xffffff];
+                int32_t idx2;
+                const unsigned char *np = (const unsigned char *) n;
+
+                idx2 = FINDIDX (table, indirect, extra,
+                        &np, string_end - n);
+                if (idx2 != 0
+                && (idx >> 24) == (idx2 >> 24)
+                && len == weights[idx2 & 0xffffff])
+                  {
+                int cnt = 0;
+
+                idx &= 0xffffff;
+                idx2 &= 0xffffff;
+
+                while (cnt < len
+                       && (weights[idx + 1 + cnt]
+                       == weights[idx2 + 1 + cnt]))
+                  ++cnt;
+
+                if (cnt == len)
+                  goto matched;
+                  }
+              }
+              }
+
+            c = *p++;
+          }
+#endif
+        else if (c == L_func('\0'))
+          {
+            /* [ unterminated, treat as normal character.  */
+            p = p_init;
+            n = n_init;
+            c = L_func('[');
+            goto normal_match;
+          }
+        else
+          {
+            int is_range = 0;
+
+#ifdef _LIBC
+            int is_seqval = 0;
+
+            if (c == L_func('[') && *p == L_func('.'))
+              {
+            uint32_t nrules =
+              _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+            const char *startp = p;
+            size_t c1 = 0;
+
+            while (1)
+              {
+                c = *++p;
+                if (c == L_func('.') && p[1] == L_func(']'))
+                  {
+                p += 2;
+                break;
+                  }
+                if (c == '\0')
+                  return FNM_NOMATCH;
+                ++c1;
+              }
+
+            /* We have to handling the symbols differently in
+               ranges since then the collation sequence is
+               important.  */
+            is_range = *p == L_func('-') && p[1] != L_func('\0');
+
+            if (nrules == 0)
+              {
+                /* There are no names defined in the collation
+                   data.  Therefore we only accept the trivial
+                   names consisting of the character itself.  */
+                if (c1 != 1)
+                  return FNM_NOMATCH;
+
+                if (!is_range && *n == startp[1])
+                  goto matched;
+
+                cold = startp[1];
+                c = *p++;
+              }
+            else
+              {
+                int32_t table_size;
+                const int32_t *symb_table;
+                const unsigned char *extra;
+                int32_t idx;
+                int32_t elem;
+# if WIDE_CHAR_VERSION
+                char *wextra;
+# endif
+
+                table_size =
+                  _NL_CURRENT_WORD (LC_COLLATE,
+                        _NL_COLLATE_SYMB_HASH_SIZEMB);
+                symb_table = (const int32_t *)
+                  _NL_CURRENT (LC_COLLATE,
+                       _NL_COLLATE_SYMB_TABLEMB);
+                extra = (const unsigned char *)
+                  _NL_CURRENT (LC_COLLATE,
+                       _NL_COLLATE_SYMB_EXTRAMB);
+
+                for (elem = 0; elem < table_size; elem++)
+                  if (symb_table[2 * elem] != 0)
+                {
+                  idx = symb_table[2 * elem + 1];
+                  /* Skip the name of collating element.  */
+                  idx += 1 + extra[idx];
+# if WIDE_CHAR_VERSION
+                  /* Skip the byte sequence of the
+                     collating element.  */
+                  idx += 1 + extra[idx];
+                  /* Adjust for the alignment.  */
+                  idx = (idx + 3) & ~3;
+
+                  wextra = (char *) &extra[idx + 4];
+
+                  if (/* Compare the length of the sequence.  */
+                      c1 == wextra[0]
+                      /* Compare the wide char sequence.  */
+                      && WMEMCMP (startp + 1, &wextra[1],
+                          c1) == 0)
+                    /* Yep, this is the entry.  */
+                    break;
+# else
+                  if (/* Compare the length of the sequence.  */
+                      c1 == extra[idx]
+                      /* Compare the byte sequence.  */
+                      && memcmp (startp + 1,
+                         &extra[idx + 1], c1) == 0)
+                    /* Yep, this is the entry.  */
+                    break;
+# endif
+                }
+
+                if (elem < table_size)
+                  {
+                /* Compare the byte sequence but only if
+                   this is not part of a range.  */
+                if (! is_range
+
+# if WIDE_CHAR_VERSION
+                    && WMEMCMP (n, &wextra[1], c1) == 0
+# else
+                    && memcmp (n, &extra[idx + 1], c1) == 0
+# endif
+                    )
+                  {
+                    n += c1 - 1;
+                    goto matched;
+                  }
+
+                /* Get the collation sequence value.  */
+                is_seqval = 1;
+# if WIDE_CHAR_VERSION
+                cold = wextra[1 + wextra[idx]];
+# else
+                idx += 1 + extra[idx];
+                /* Adjust for the alignment.  */
+                idx = (idx + 3) & ~3;
+                cold = *((int32_t *) &extra[idx]);
+# endif
+
+                c = *p++;
+                  }
+                else if (c1 == 1)
+                  {
+                /* No valid character.  Match it as a
+                   single byte.  */
+                if (!is_range && *n == startp[1])
+                  goto matched;
+
+                cold = startp[1];
+                c = *p++;
+                  }
+                else
+                  return FNM_NOMATCH;
+              }
+              }
+            else
+#endif
+              {
+            c = FOLD (c);
+              normal_bracket:
+
+            /* We have to handling the symbols differently in
+               ranges since then the collation sequence is
+               important.  */
+            is_range = (*p == L_func('-') && p[1] != L_func('\0')
+                    && p[1] != L_func(']'));
+
+            if (!is_range && c == fn)
+              goto matched;
+
+            /* This is needed if we goto normal_bracket; from
+               outside of is_seqval's scope.  */
+            //is_seqval = 0;
+            cold = c;
+            c = *p++;
+              }
+
+            if (c == L_func('-') && *p != L_func(']'))
+              {
+#if _LIBC
+            /* We have to find the collation sequence
+               value for C.  Collation sequence is nothing
+               we can regularly access.  The sequence
+               value is defined by the order in which the
+               definitions of the collation values for the
+               various characters appear in the source
+               file.  A strange concept, nowhere
+               documented.  */
+            uint32_t fcollseq;
+            uint32_t lcollseq;
+            unsigned char cend = *p++;
+
+# if WIDE_CHAR_VERSION
+            /* Search in the `names' array for the characters.  */
+            fcollseq = __collseq_table_lookup (collseq, fn);
+            if (fcollseq == ~((uint32_t) 0))
+              /* XXX We don't know anything about the character
+                 we are supposed to match.  This means we are
+                 failing.  */
+              goto range_not_matched;
+
+            if (is_seqval)
+              lcollseq = cold;
+            else
+              lcollseq = __collseq_table_lookup (collseq, cold);
+# else
+            fcollseq = collseq[fn];
+            lcollseq = is_seqval ? cold : collseq[(unsigned char) cold];
+# endif
+
+            is_seqval = 0;
+            if (cend == L_func('[') && *p == L_func('.'))
+              {
+                uint32_t nrules =
+                  _NL_CURRENT_WORD (LC_COLLATE,
+                        _NL_COLLATE_NRULES);
+                const char *startp = p;
+                size_t c1 = 0;
+
+                while (1)
+                  {
+                c = *++p;
+                if (c == L_func('.') && p[1] == L_func(']'))
+                  {
+                    p += 2;
+                    break;
+                  }
+                if (c == '\0')
+                  return FNM_NOMATCH;
+                ++c1;
+                  }
+
+                if (nrules == 0)
+                  {
+                /* There are no names defined in the
+                   collation data.  Therefore we only
+                   accept the trivial names consisting
+                   of the character itself.  */
+                if (c1 != 1)
+                  return FNM_NOMATCH;
+
+                cend = startp[1];
+                  }
+                else
+                  {
+                int32_t table_size;
+                const int32_t *symb_table;
+                const unsigned char *extra;
+                int32_t idx;
+                int32_t elem;
+# if WIDE_CHAR_VERSION
+                char *wextra;
+# endif
+
+                table_size =
+                  _NL_CURRENT_WORD (LC_COLLATE,
+                            _NL_COLLATE_SYMB_HASH_SIZEMB);
+                symb_table = (const int32_t *)
+                  _NL_CURRENT (LC_COLLATE,
+                           _NL_COLLATE_SYMB_TABLEMB);
+                extra = (const unsigned char *)
+                  _NL_CURRENT (LC_COLLATE,
+                           _NL_COLLATE_SYMB_EXTRAMB);
+
+                for (elem = 0; elem < table_size; elem++)
+                  if (symb_table[2 * elem] != 0)
+                    {
+                      idx = symb_table[2 * elem + 1];
+                      /* Skip the name of collating
+                     element.  */
+                      idx += 1 + extra[idx];
+# if WIDE_CHAR_VERSION
+                      /* Skip the byte sequence of the
+                     collating element.  */
+                      idx += 1 + extra[idx];
+                      /* Adjust for the alignment.  */
+                      idx = (idx + 3) & ~3;
+
+                      wextra = (char *) &extra[idx + 4];
+
+                      if (/* Compare the length of the
+                         sequence.  */
+                      c1 == wextra[0]
+                      /* Compare the wide char sequence.  */
+                      && WMEMCMP (startp + 1, &wextra[1],
+                              c1) == 0)
+                    /* Yep, this is the entry.  */
+                    break;
+# else
+                      if (/* Compare the length of the
+                         sequence.  */
+                      c1 == extra[idx]
+                      /* Compare the byte sequence.  */
+                      && memcmp (startp + 1,
+                             &extra[idx + 1], c1) == 0)
+                    /* Yep, this is the entry.  */
+                    break;
+# endif
+                    }
+
+                if (elem < table_size)
+                  {
+                    /* Get the collation sequence value.  */
+                    is_seqval = 1;
+# if WIDE_CHAR_VERSION
+                    cend = wextra[1 + wextra[idx]];
+# else
+                    idx += 1 + extra[idx];
+                    /* Adjust for the alignment.  */
+                    idx = (idx + 3) & ~3;
+                    cend = *((int32_t *) &extra[idx]);
+# endif
+                  }
+                else if (c1 == 1)
+                  {
+                    cend = startp[1];
+                    c = *p++;
+                  }
+                else
+                  return FNM_NOMATCH;
+                  }
+              }
+            else
+              {
+                if (!(flags & FNM_NOESCAPE) && cend == L_func('\\'))
+                  cend = *p++;
+                if (cend == L_func('\0'))
+                  return FNM_NOMATCH;
+                cend = FOLD (cend);
+              }
+
+            /* XXX It is not entirely clear to me how to handle
+               characters which are not mentioned in the
+               collation specification.  */
+            if (
+# if WIDE_CHAR_VERSION
+                lcollseq == 0xffffffff ||
+# endif
+                lcollseq <= fcollseq)
+              {
+                /* We have to look at the upper bound.  */
+                uint32_t hcollseq;
+
+                if (is_seqval)
+                  hcollseq = cend;
+                else
+                  {
+# if WIDE_CHAR_VERSION
+                hcollseq =
+                  __collseq_table_lookup (collseq, cend);
+                if (hcollseq == ~((uint32_t) 0))
+                  {
+                    /* Hum, no information about the upper
+                       bound.  The matching succeeds if the
+                       lower bound is matched exactly.  */
+                    if (lcollseq != fcollseq)
+                      goto range_not_matched;
+
+                    goto matched;
+                  }
+# else
+                hcollseq = collseq[cend];
+# endif
+                  }
+
+                if (lcollseq <= hcollseq && fcollseq <= hcollseq)
+                  goto matched;
+              }
+# if WIDE_CHAR_VERSION
+              range_not_matched:
+# endif
+#else
+            /* We use a boring value comparison of the character
+               values.  This is better than comparing using
+               `strcoll' since the latter would have surprising
+               and sometimes fatal consequences.  */
+            unsigned char cend = *p++;
+
+            if (!(flags & FNM_NOESCAPE) && cend == L_func('\\'))
+              cend = *p++;
+            if (cend == L_func('\0'))
+              return FNM_NOMATCH;
+
+            /* It is a range.  */
+            if (cold <= fn && fn <= cend)
+              goto matched;
+#endif
+
+            c = *p++;
+              }
+          }
+
+        if (c == L_func(']'))
+          break;
+          }
+
+        if (!not)
+          return FNM_NOMATCH;
+        break;
+
+      matched:
+        /* Skip the rest of the [...] that already matched.  */
+        while ((c = *p++) != L_func (']'))
+          {
+        if (c == L_func('\0'))
+          /* [... (unterminated) loses.  */
+          return FNM_NOMATCH;
+
+        if (!(flags & FNM_NOESCAPE) && c == L_func('\\'))
+          {
+            if (*p == L_func('\0'))
+              return FNM_NOMATCH;
+            /* XXX 1003.2d11 is unclear if this is right.  */
+            ++p;
+          }
+        else if (c == L_func('[') && *p == L_func(':'))
+          {
+            int c1 = 0;
+            const char *startp = p;
+
+            while (1)
+              {
+            c = *++p;
+            if (++c1 == CHAR_CLASS_MAX_LENGTH)
+              return FNM_NOMATCH;
+
+            if (*p == L_func(':') && p[1] == L_func(']'))
+              break;
+
+            if (c < L_func('a') || c >= L_func('z'))
+              {
+                p = startp - 2;
+                break;
+              }
+              }
+            p += 2;
+          }
+        else if (c == L_func('[') && *p == L_func('='))
+          {
+            c = *++p;
+            if (c == L_func('\0'))
+              return FNM_NOMATCH;
+            c = *++p;
+            if (c != L_func('=') || p[1] != L_func(']'))
+              return FNM_NOMATCH;
+            p += 2;
+          }
+        else if (c == L_func('[') && *p == L_func('.'))
+          {
+            while (1)
+              {
+            c = *++p;
+            if (c == L_func('\0'))
+              return FNM_NOMATCH;
+
+            if (c == L_func('.') && p[1] == L_func(']'))
+              break;
+              }
+            p += 2;
+          }
+          }
+        if (not)
+          return FNM_NOMATCH;
+      }
+      break;
+
+    case L_func('+'):
+    case L_func('@'):
+    case L_func('!'):
+      if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+        {
+          int res = EXT (c, p, n, string_end, no_leading_period, flags,
+                 alloca_used);
+          if (res != -1)
+        return res;
+        }
+      goto normal_match;
+
+    case L_func('/'):
+      if (NO_LEADING_PERIOD (flags))
+        {
+          if (n == string_end || c != (unsigned char) *n)
+        return FNM_NOMATCH;
+
+          new_no_leading_period = 1;
+          break;
+        }
+      /* FALLTHROUGH */
+    default:
+    normal_match:
+      if (n == string_end || c != FOLD ((unsigned char) *n))
+        return FNM_NOMATCH;
+    }
+
+      no_leading_period = new_no_leading_period;
+      ++n;
+    }
+
+  if (n == string_end)
+    return 0;
+
+  if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L_func('/'))
+    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
+    return 0;
+
+  return FNM_NOMATCH;
+}
+
+
+const char *
+END (const char *pattern)
+{
+  const char *p = pattern;
+
+  while (1)
+    if (*++p == L_func('\0'))
+      /* This is an invalid pattern.  */
+      return pattern;
+    else if (*p == L_func('['))
+      {
+    /* Handle brackets special.  */
+    if (posixly_correct == 0)
+      posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+    /* Skip the not sign.  We have to recognize it because of a possibly
+       following ']'.  */
+    if (*++p == L_func('!') || (posixly_correct < 0 && *p == L_func('^')))
+      ++p;
+    /* A leading ']' is recognized as such.  */
+    if (*p == L_func(']'))
+      ++p;
+    /* Skip over all characters of the list.  */
+    while (*p != L_func(']'))
+      if (*p++ == L_func('\0'))
+        /* This is no valid pattern.  */
+        return pattern;
+      }
+    else if ((*p == L_func('?') || *p == L_func('*') || *p == L_func('+') || *p == L_func('@')
+          || *p == L_func('!')) && p[1] == L_func('('))
+      {
+    p = END (p + 1);
+    if (*p == L_func('\0'))
+      /* This is an invalid pattern.  */
+      return pattern;
+      }
+    else if (*p == L_func(')'))
+      break;
+
+  return p + 1;
+}
+
+
+static int
+EXT (int opt, const char *pattern, const char *string, const char *string_end,
+     int no_leading_period, int flags, size_t alloca_used)
+{
+  const char *startp;
+  int level;
+  struct patternlist
+  {
+    struct patternlist *next;
+    char malloced;
+    char str[0];
+  } *list = NULL;
+  struct patternlist **lastp = &list;
+  size_t pattern_len = STRLEN (pattern);
+  int any_malloced = 0;
+  const char *p;
+  const char *rs;
+  int retval = 0;
+
+  /* Parse the pattern.  Store the individual parts in the list.  */
+  level = 0;
+  for (startp = p = pattern + 1; level >= 0; ++p)
+    if (*p == L_func('\0'))
+      {
+    /* This is an invalid pattern.  */
+    retval = -1;
+    goto out;
+      }
+    else if (*p == L_func('['))
+      {
+    /* Handle brackets special.  */
+    if (posixly_correct == 0)
+      posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+    /* Skip the not sign.  We have to recognize it because of a possibly
+       following ']'.  */
+    if (*++p == L_func('!') || (posixly_correct < 0 && *p == L_func('^')))
+      ++p;
+    /* A leading ']' is recognized as such.  */
+    if (*p == L_func(']'))
+      ++p;
+    /* Skip over all characters of the list.  */
+    while (*p != L_func(']'))
+      if (*p++ == L_func('\0'))
+        {
+          /* This is no valid pattern.  */
+          retval = -1;
+          goto out;
+        }
+      }
+    else if ((*p == L_func('?') || *p == L_func('*') || *p == L_func('+') || *p == L_func('@')
+          || *p == L_func('!')) && p[1] == L_func('('))
+      /* Remember the nesting level.  */
+      ++level;
+    else if (*p == L_func(')'))
+      {
+    if (level-- == 0)
+      {
+        /* This means we found the end of the pattern.  */
+#define NEW_PATTERN \
+        struct patternlist *newp;                         \
+        size_t slen = (opt == '?' || opt == '@'             \
+               ? pattern_len : (p - startp + 1));             \
+        slen = sizeof (struct patternlist) + (slen * sizeof (char));      \
+        int malloced = ! __libc_use_alloca (alloca_used + slen);          \
+        if (__builtin_expect (malloced, 0))                   \
+          {                                   \
+        newp = malloc (slen);                         \
+        if (newp == NULL)                         \
+          {                               \
+            retval = -2;                          \
+            goto out;                             \
+          }                               \
+        any_malloced = 1;                         \
+          }                                   \
+        else                                  \
+          newp = alloca_account (slen, alloca_used);              \
+        newp->next = NULL;                            \
+        newp->malloced = malloced;                        \
+        *((char *) MEMPCPY (newp->str, startp, p - startp)) = L_func('\0');    \
+        *lastp = newp;                            \
+        lastp = &newp->next
+        NEW_PATTERN;
+      }
+      }
+    else if (*p == L_func('|'))
+      {
+    if (level == 0)
+      {
+        NEW_PATTERN;
+        startp = p + 1;
+      }
+      }
+  assert (list != NULL);
+  assert (p[-1] == L_func(')'));
+#undef NEW_PATTERN
+
+  switch (opt)
+    {
+    case '*':
+      if (FCT (p, string, string_end, no_leading_period, flags, NULL,
+           alloca_used) == 0)
+    goto success;
+      /* FALLTHROUGH */
+
+    case '+':
+      do
+    {
+      for (rs = string; rs <= string_end; ++rs)
+        /* First match the prefix with the current pattern with the
+           current pattern.  */
+        if (FCT (list->str, string, rs, no_leading_period,
+             flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
+             NULL, alloca_used) == 0
+        /* This was successful.  Now match the rest with the rest
+           of the pattern.  */
+        && (FCT (p, rs, string_end,
+             rs == string
+             ? no_leading_period
+             : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
+             flags & FNM_FILE_NAME
+             ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0
+            /* This didn't work.  Try the whole pattern.  */
+            || (rs != string
+            && FCT (pattern - 1, rs, string_end,
+                rs == string
+                ? no_leading_period
+                : (rs[-1] == '/' && NO_LEADING_PERIOD (flags)
+                   ? 1 : 0),
+                flags & FNM_FILE_NAME
+                ? flags : flags & ~FNM_PERIOD, NULL,
+                alloca_used) == 0)))
+          /* It worked.  Signal success.  */
+          goto success;
+    }
+      while ((list = list->next) != NULL);
+
+      /* None of the patterns lead to a match.  */
+      retval = FNM_NOMATCH;
+      break;
+
+    case '?':
+      if (FCT (p, string, string_end, no_leading_period, flags, NULL,
+           alloca_used) == 0)
+    goto success;
+      /* FALLTHROUGH */
+
+    case '@':
+        do {
+            /* I cannot believe it but `strcat' is actually acceptable
+             here.  Match the entire string with the prefix from the
+             pattern list and the rest of the pattern following the
+             pattern list.  */
+            if(FCT(STRCAT(list->str, p), string, string_end,
+                    no_leading_period,
+                    flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
+                    NULL, alloca_used) == 0)
+                /* It worked.  Signal success.  */
+                goto success;
+        } while((list = list->next) != NULL);
+
+        /* None of the patterns lead to a match.  */
+        retval = FNM_NOMATCH;
+        break;
+
+    case '!':
+      for (rs = string; rs <= string_end; ++rs)
+    {
+      struct patternlist *runp;
+
+      for (runp = list; runp != NULL; runp = runp->next)
+        if (FCT (runp->str, string, rs,  no_leading_period,
+             flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
+             NULL, alloca_used) == 0)
+          break;
+
+      /* If none of the patterns matched see whether the rest does.  */
+      if (runp == NULL
+          && (FCT (p, rs, string_end,
+               rs == string
+               ? no_leading_period
+               : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
+               flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
+               NULL, alloca_used) == 0))
+        /* This is successful.  */
+        goto success;
+    }
+
+      /* None of the patterns together with the rest of the pattern
+     lead to a match.  */
+      retval = FNM_NOMATCH;
+      break;
+
+    default:
+      assert (! "Invalid extended matching operator");
+      retval = -1;
+      break;
+    }
+
+ success:
+ out:
+  if (any_malloced)
+    while (list != NULL)
+      {
+    struct patternlist *old = list;
+    list = list->next;
+    if (old->malloced)
+      free (old);
+      }
+
+  return retval;
+}
+
+
+#undef FOLD
+#undef FCT
+#undef EXT
+#undef END
+#undef STRUCT
+#undef MEMPCPY
+#undef MEMCHR
+#undef STRCOLL
+#undef STRLEN
+#undef STRCAT
+#undef L
+#undef BTOWC
+#undef WIDE_CHAR_VERSION
+#undef FINDIDX
diff --git a/dap-sdk/core/include/dap_strfuncs.h b/dap-sdk/core/include/dap_strfuncs.h
index c581294cb9df00d18df510e4425c3e4f8787414e..79f00942eaeb5050de51017e3d9ab36b2cd165e6 100755
--- a/dap-sdk/core/include/dap_strfuncs.h
+++ b/dap-sdk/core/include/dap_strfuncs.h
@@ -13,6 +13,7 @@
 #include <string.h>
 
 #include "dap_math_ops.h"
+#include "dap_fnmatch.h"
 
 #define dap_return_if_fail(expr)            {if(!(expr)) {return;}}
 #define dap_return_val_if_fail(expr,val)    {if(!(expr)) {return (val);}}
diff --git a/dap-sdk/core/src/dap_fnmatch.c b/dap-sdk/core/src/dap_fnmatch.c
new file mode 100644
index 0000000000000000000000000000000000000000..21096cf46828208d76ad0e0e54158b6f36eabf37
--- /dev/null
+++ b/dap-sdk/core/src/dap_fnmatch.c
@@ -0,0 +1,435 @@
+/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "dap_fnmatch.h"
+
+
+
+/* For platform which support the ISO C amendement 1 functionality we
+   support user defined character classes.  */
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
+//# include <wchar.h>
+//# include <wctype.h>
+
+# define __libc_use_alloca(n) false
+# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
+# define extend_alloca_account(buf, len, newlen, avar) \
+    ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
+
+
+
+/* We need some of the locale data (the collation sequence information)
+   but there is no interface to get this information in general.  Therefore
+   we support a correct implementation only in glibc.  */
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# include "../locale/coll-lookup.h"
+# include <shlib-compat.h>
+
+# define CONCAT(a,b) __CONCAT(a,b)
+# define mbsrtowcs __mbsrtowcs
+# define fnmatch __fnmatch
+extern int fnmatch (const char *pattern, const char *string, int flags);
+#endif
+
+/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set.  */
+#define NO_LEADING_PERIOD(flags) \
+  ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+//#if defined _LIBC || !defined __GNU_LIBRARY__
+
+# if defined STDC_HEADERS || !defined isascii
+#  define ISASCII(c) 1
+# else
+#  define ISASCII(c) isascii(c)
+# endif
+
+# ifdef isblank
+#  define ISBLANK(c) (ISASCII (c) && isblank (c))
+# else
+#  define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+# endif
+# ifdef isgraph
+#  define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+# else
+#  define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+# endif
+
+# define ISPRINT(c) (ISASCII (c) && isprint (c))
+# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+# define ISALNUM(c) (ISASCII (c) && isalnum (c))
+# define ISALPHA(c) (ISASCII (c) && isalpha (c))
+# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+# define ISLOWER(c) (ISASCII (c) && islower (c))
+# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+# define ISSPACE(c) (ISASCII (c) && isspace (c))
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* The GNU C library provides support for user-defined character classes
+   and the functions from ISO C amendement 1.  */
+#  ifdef CHARCLASS_NAME_MAX
+#   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+#  else
+/* This shouldn't happen but some implementation might still have this
+   problem.  Use a reasonable default value.  */
+#   define CHAR_CLASS_MAX_LENGTH 256
+#  endif
+
+#  ifdef _LIBC
+#   define IS_CHAR_CLASS(string) __wctype (string)
+#  else
+#   define IS_CHAR_CLASS(string) wctype (string)
+#  endif
+
+#  ifdef _LIBC
+#   define ISWCTYPE(WC, WT) __iswctype (WC, WT)
+#  else
+#   define ISWCTYPE(WC, WT) iswctype (WC, WT)
+#  endif
+
+#  if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
+/* In this case we are implementing the multibyte character handling.  */
+#   define HANDLE_MULTIBYTE 1
+#  endif
+
+# else
+#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#  define IS_CHAR_CLASS(string)                           \
+   (STREQ (string, "alpha") || STREQ (string, "upper")                \
+    || STREQ (string, "lower") || STREQ (string, "digit")             \
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")            \
+    || STREQ (string, "space") || STREQ (string, "print")             \
+    || STREQ (string, "punct") || STREQ (string, "graph")             \
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+# endif
+
+
+/* This function doesn't exist on most systems.  */
+
+# if !defined HAVE___STRCHRNUL && !defined _LIBC
+static char *
+__strchrnul (const char *s, int c)
+{
+  char *result = strchr (s, c);
+  if (result == NULL)
+    result = strchr (s, '\0');
+  return result;
+}
+# endif
+
+# if HANDLE_MULTIBYTE && !defined HAVE___STRCHRNUL && !defined _LIBC
+static wchar_t *
+__wcschrnul (const wchar_t *s, wint_t c)
+{
+  wchar_t *result = wcschr (s, c);
+  if (result == NULL)
+    result = wcschr (s, '\0');
+  return result;
+}
+# endif
+
+/* Note that this evaluates C many times.  */
+# ifdef _LIBC
+#  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
+# else
+#  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+# endif
+# define FCT    internal_fnmatch
+# define EXT    ext_match
+# define END    end_pattern
+# define STRUCT fnmatch_struct
+//# define L(CS)  CS
+# ifdef _LIBC
+#  define BTOWC(C)  __btowc (C)
+# else
+#  define BTOWC(C)  btowc (C)
+# endif
+# define STRLEN(S) strlen(S)
+# define STRCAT(D, S) strcat (D, S)
+# define MEMPCPY(D, S, N) __mempcpy (D, S, N)
+# define MEMCHR(S, C, N) memchr (S, C, N)
+# define STRCOLL(S1, S2) strcoll (S1, S2)
+# define WIDE_CHAR_VERSION 0
+//# include <locale/weight.h>
+# define FINDIDX findidx
+# include "dap_fnmatch_loop.h"
+
+
+# if HANDLE_MULTIBYTE
+/* Note that this evaluates C many times.  */
+#  ifdef _LIBC
+#   define FOLD(c) ((flags & FNM_CASEFOLD) ? __towlower (c) : (c))
+#  else
+#   define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? towlower (c) : (c))
+#  endif
+#  define CHAR  wchar_t
+#  define UCHAR wint_t
+#  define INT   wint_t
+#  define FCT   internal_fnwmatch
+#  define EXT   ext_wmatch
+#  define END   end_wpattern
+#  define STRUCT fnwmatch_struct
+#  define L(CS) L##CS
+#  define BTOWC(C)  (C)
+#  define STRLEN(S) __wcslen (S)
+#  define STRCAT(D, S) __wcscat (D, S)
+#  define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
+#  define MEMCHR(S, C, N) __wmemchr (S, C, N)
+#  define STRCOLL(S1, S2) wcscoll (S1, S2)
+#  ifdef _LIBC
+#   define WMEMCMP(S1, S2, N) __wmemcmp (S1, S2, N)
+#  else
+#   define WMEMCMP(S1, S2, N) wmemcmp (S1, S2, N)
+#  endif
+#  define WIDE_CHAR_VERSION 1
+/* Change the name the header defines so it doesn't conflict with
+   the <locale/weight.h> version included above.  */
+#  define findidx findidxwc
+#  include <locale/weightwc.h>
+#  undef findidx
+#  define FINDIDX findidxwc
+
+#  undef IS_CHAR_CLASS
+/* We have to convert the wide character string in a multibyte string.  But
+   we know that the character class names consist of alphanumeric characters
+   from the portable character set, and since the wide character encoding
+   for a member of the portable character set is the same code point as
+   its single-byte encoding, we can use a simplified method to convert the
+   string to a multibyte character string.  */
+static wctype_t
+is_char_class (const wchar_t *wcs)
+{
+  char s[CHAR_CLASS_MAX_LENGTH + 1];
+  char *cp = s;
+
+  do
+    {
+      /* Test for a printable character from the portable character set.  */
+#  ifdef _LIBC
+      if (*wcs < 0x20 || *wcs > 0x7e
+      || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
+    return (wctype_t) 0;
+#  else
+      switch (*wcs)
+    {
+    case L' ': case L'!': case L'"': case L'#': case L'%':
+    case L'&': case L'\'': case L'(': case L')': case L'*':
+    case L'+': case L',': case L'-': case L'.': case L'/':
+    case L'0': case L'1': case L'2': case L'3': case L'4':
+    case L'5': case L'6': case L'7': case L'8': case L'9':
+    case L':': case L';': case L'<': case L'=': case L'>':
+    case L'?':
+    case L'A': case L'B': case L'C': case L'D': case L'E':
+    case L'F': case L'G': case L'H': case L'I': case L'J':
+    case L'K': case L'L': case L'M': case L'N': case L'O':
+    case L'P': case L'Q': case L'R': case L'S': case L'T':
+    case L'U': case L'V': case L'W': case L'X': case L'Y':
+    case L'Z':
+    case L'[': case L'\\': case L']': case L'^': case L'_':
+    case L'a': case L'b': case L'c': case L'd': case L'e':
+    case L'f': case L'g': case L'h': case L'i': case L'j':
+    case L'k': case L'l': case L'm': case L'n': case L'o':
+    case L'p': case L'q': case L'r': case L's': case L't':
+    case L'u': case L'v': case L'w': case L'x': case L'y':
+    case L'z': case L'{': case L'|': case L'}': case L'~':
+      break;
+    default:
+      return (wctype_t) 0;
+    }
+#  endif
+
+      /* Avoid overrunning the buffer.  */
+      if (cp == s + CHAR_CLASS_MAX_LENGTH)
+    return (wctype_t) 0;
+
+      *cp++ = (char) *wcs++;
+    }
+  while (*wcs != L'\0');
+
+  *cp = '\0';
+
+#  ifdef _LIBC
+  return __wctype (s);
+#  else
+  return wctype (s);
+#  endif
+}
+#  define IS_CHAR_CLASS(string) is_char_class (string)
+
+#  include "fnmatch_loop.c"
+# endif
+
+
+int dap_fnmatch (const char *pattern, const char *string, int flags)
+{
+# if HANDLE_MULTIBYTE
+  if (__builtin_expect (MB_CUR_MAX, 1) != 1)
+    {
+      mbstate_t ps;
+      size_t n;
+      const char *p;
+      wchar_t *wpattern_malloc = NULL;
+      wchar_t *wpattern;
+      wchar_t *wstring_malloc = NULL;
+      wchar_t *wstring;
+      size_t alloca_used = 0;
+
+      /* Convert the strings into wide characters.  */
+      memset (&ps, '\0', sizeof (ps));
+      p = pattern;
+#ifdef _LIBC
+      n = __strnlen (pattern, 1024);
+#else
+      n = strlen (pattern);
+#endif
+      if (__glibc_likely (n < 1024))
+    {
+      wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t),
+                         alloca_used);
+      n = mbsrtowcs (wpattern, &p, n + 1, &ps);
+      if (__glibc_unlikely (n == (size_t) -1))
+        /* Something wrong.
+           XXX Do we have to set `errno' to something which mbsrtows hasn't
+           already done?  */
+        return -1;
+      if (p)
+        {
+          memset (&ps, '\0', sizeof (ps));
+          goto prepare_wpattern;
+        }
+    }
+      else
+    {
+    prepare_wpattern:
+      n = mbsrtowcs (NULL, &pattern, 0, &ps);
+      if (__glibc_unlikely (n == (size_t) -1))
+        /* Something wrong.
+           XXX Do we have to set `errno' to something which mbsrtows hasn't
+           already done?  */
+        return -1;
+      if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t)))
+        {
+          __set_errno (ENOMEM);
+          return -2;
+        }
+      wpattern_malloc = wpattern
+        = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t));
+      assert (mbsinit (&ps));
+      if (wpattern == NULL)
+        return -2;
+      (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
+    }
+
+      assert (mbsinit (&ps));
+#ifdef _LIBC
+      n = __strnlen (string, 1024);
+#else
+      n = strlen (string);
+#endif
+      p = string;
+      if (__glibc_likely (n < 1024))
+    {
+      wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t),
+                        alloca_used);
+      n = mbsrtowcs (wstring, &p, n + 1, &ps);
+      if (__glibc_unlikely (n == (size_t) -1))
+        {
+          /* Something wrong.
+         XXX Do we have to set `errno' to something which
+         mbsrtows hasn't already done?  */
+        free_return:
+          free (wpattern_malloc);
+          return -1;
+        }
+      if (p)
+        {
+          memset (&ps, '\0', sizeof (ps));
+          goto prepare_wstring;
+        }
+    }
+      else
+    {
+    prepare_wstring:
+      n = mbsrtowcs (NULL, &string, 0, &ps);
+      if (__glibc_unlikely (n == (size_t) -1))
+        /* Something wrong.
+           XXX Do we have to set `errno' to something which mbsrtows hasn't
+           already done?  */
+        goto free_return;
+      if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t)))
+        {
+          free (wpattern_malloc);
+          __set_errno (ENOMEM);
+          return -2;
+        }
+
+      wstring_malloc = wstring
+        = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t));
+      if (wstring == NULL)
+        {
+          free (wpattern_malloc);
+          return -2;
+        }
+      assert (mbsinit (&ps));
+      (void) mbsrtowcs (wstring, &string, n + 1, &ps);
+    }
+
+      int res = internal_fnwmatch (wpattern, wstring, wstring + n,
+                   flags & FNM_PERIOD, flags, NULL,
+                   alloca_used);
+
+      free (wstring_malloc);
+      free (wpattern_malloc);
+
+      return res;
+    }
+# endif  /* mbstate_t and mbsrtowcs or _LIBC.  */
+
+  return internal_fnmatch (pattern, string, string + strlen (string),
+               flags & FNM_PERIOD, flags, NULL, 0);
+}
+
+# ifdef _LIBC
+#  undef fnmatch
+versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
+#  if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
+strong_alias (__fnmatch, __fnmatch_old)
+compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
+#  endif
+libc_hidden_ver (__fnmatch, fnmatch)
+# endif
+
+//#endif  /* _LIBC or not __GNU_LIBRARY__.  */
diff --git a/modules/global-db/dap_chain_global_db_driver_cdb.c b/modules/global-db/dap_chain_global_db_driver_cdb.c
index 88221e95d522ec66d094e9a1011ea756c765a9ea..5adb80c769556202b7ef59097e40dbfd349b38b6 100644
--- a/modules/global-db/dap_chain_global_db_driver_cdb.c
+++ b/modules/global-db/dap_chain_global_db_driver_cdb.c
@@ -32,7 +32,7 @@
 
 #include "dap_common.h"
 #include "dap_hash.h"
-#include "dap_strfuncs.h"
+#include "dap_strfuncs.h" // #include <dap_fnmatch.h>
 #include "dap_chain_global_db_driver_cdb.h"
 #include "dap_file_utils.h"
 
@@ -471,11 +471,9 @@ dap_list_t* dap_db_driver_cdb_get_groups_by_mask(const char *a_group_mask)
     pthread_mutex_lock(&cdb_mutex);
     HASH_ITER(hh, s_cdb, cur_cdb, tmp)
     {
-        if(strstr(cur_cdb->local_group, a_group_mask)) {
-            if(!strstr(cur_cdb->local_group, ".del")) {
+        if(!dap_fnmatch(a_group_mask, cur_cdb->local_group, 0))
+            if(dap_fnmatch("*.del", cur_cdb->local_group, 0))
                 l_ret_list = dap_list_prepend(l_ret_list, dap_strdup(cur_cdb->local_group));
-            }
-        }
     }
     pthread_mutex_unlock(&cdb_mutex);
     return l_ret_list;
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index b53d161851272715acfbd852c6fb8a878afaadc1..2d70ab3709012f55d86fe2dca1ed3efb534bd70e 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1352,7 +1352,7 @@ int s_net_load(const char * a_net_name)
                 while(l_groups) {
                     char *l_group_name = l_groups->data;
                     // do not use groups with names like *.del
-                    if(!strstr(l_group_name, ".del")) {
+                    if(dap_fnmatch("*.del", l_group_name, 0)) {
                         const char *l_history_group = dap_chain_global_db_add_history_extra_group(l_group_name,
                                                         PVT(l_net)->gdb_sync_nodes_addrs,
                                                         &PVT(l_net)->gdb_sync_nodes_addrs_count);
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cdb_auth.c b/modules/service/vpn/dap_chain_net_srv_vpn_cdb_auth.c
index 7cb35668c6f5b2c63d5ffdfa118a0616ebfb7946..587121d1ab83328fc9c6c1fd73491333bb675ea5 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn_cdb_auth.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn_cdb_auth.c
@@ -282,47 +282,56 @@ int dap_chain_net_srv_vpn_cdb_auth_activate_serial(const char * a_serial_raw, co
         int l_res = 0;
         byte_t *l_pkey_raw = NULL;
         size_t l_pkey_raw_size = 0;
+        dap_enc_key_type_t l_key_type;
         {
-            // deserealize pkey
+            // verify sign
+            byte_t *l_sign_raw = NULL;
+            size_t l_sign_length = dap_strlen(a_sign);
+            l_sign_raw = DAP_NEW_Z_SIZE(byte_t, l_sign_length * 2);
+            size_t l_sign_raw_size = dap_enc_base64_decode(a_sign, l_sign_length, l_sign_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE);
+            dap_sign_t *l_sign = (dap_sign_t*) l_sign_raw; //dap_sign_pack(l_client_key, l_sign_raw, l_sign_raw_size, l_pkey_raw, l_pkey_length);
+            //get key type for pkey
+            dap_sign_type_t l_chain_sign_type;
+            l_chain_sign_type.raw = l_sign_raw_size > 0 ? l_sign->header.type.raw : SIG_TYPE_NULL;
+            l_key_type =  dap_sign_type_to_key_type(l_chain_sign_type);
+            size_t l_serial_len = dap_strlen(a_serial_raw);
+            l_res = dap_sign_verify(l_sign, a_serial_raw, l_serial_len);
+            if(!l_res){
+                DAP_DELETE(l_sign_raw);
+                return -2;//OP_CODE_LOGIN_INCORRECT_SIGN
+            }
+
+            // deserialize pkey
             dap_enc_key_t *l_client_key = NULL;
             size_t l_pkey_length = dap_strlen(a_pkey);
             l_pkey_raw = DAP_NEW_Z_SIZE(byte_t, l_pkey_length);
             memset(l_pkey_raw, 0, l_pkey_length);
             l_pkey_raw_size = dap_enc_base64_decode(a_pkey, l_pkey_length, l_pkey_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE);
-            l_client_key = dap_enc_key_new(DAP_ENC_KEY_TYPE_SIG_TESLA);
+            l_client_key = dap_enc_key_new(l_key_type); //DAP_ENC_KEY_TYPE_SIG_TESLA
             l_res = dap_enc_key_deserealize_pub_key(l_client_key, l_pkey_raw, l_pkey_raw_size);
-            // verify sign
-            if(!l_res) {
-                byte_t *l_sign_raw = NULL;
-                size_t l_sign_length = dap_strlen(a_sign);
-                l_sign_raw = DAP_NEW_Z_SIZE(byte_t, l_sign_length*2);
-                size_t l_sign_raw_size = dap_enc_base64_decode(a_sign, l_sign_length, l_sign_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE);
-                dap_sign_t *l_sign = (dap_sign_t*)l_sign_raw;//dap_sign_pack(l_client_key, l_sign_raw, l_sign_raw_size, l_pkey_raw, l_pkey_length);
-                size_t as = dap_sign_get_size(l_sign);
-                size_t l_serial_len = dap_strlen(a_serial_raw);
-                l_res = dap_sign_verify(l_sign, a_serial_raw, l_serial_len);
-                DAP_DELETE(l_sign_raw);
-            }
-            //dap_enc_key_deserealize_sign
-        }
-
-        // activate serial key
-        if(l_res==1) {
-            // added pkey to serial
-            l_serial_key->header.ext_size = l_pkey_raw_size;
-            l_serial_key = DAP_REALLOC(l_serial_key,dap_serial_key_len(l_serial_key));
-            l_serial_key->header.activated = time(NULL);
-            memcpy(l_serial_key->ext, l_pkey_raw, l_pkey_raw_size);
-            // save updated serial
-            if(dap_chain_global_db_gr_set(dap_strdup(l_serial_key->header.serial), l_serial_key,
-                    dap_serial_key_len(l_serial_key),
-                    s_group_serials_activated)) {
-                dap_chain_global_db_gr_del(l_serial_key->header.serial, s_group_serials);
-                l_ret = 0;// OK
+            // pkey from sign
+            size_t l_pkey_sign_size = 0;
+            uint8_t *l_pkey_sign = dap_sign_get_pkey(l_sign, &l_pkey_sign_size);
+            // activate serial key
+            if(l_pkey_sign_size == l_pkey_raw_size && !memcmp(l_pkey_sign, l_pkey_raw, l_pkey_sign_size)) {
+                // added pkey to serial
+                l_serial_key->header.ext_size = l_pkey_raw_size;
+                l_serial_key = DAP_REALLOC(l_serial_key, dap_serial_key_len(l_serial_key));
+                l_serial_key->header.activated = time(NULL);
+                l_serial_key->header.os = l_key_type;
+                memcpy(l_serial_key->ext, l_pkey_raw, l_pkey_raw_size);
+                // save updated serial
+                if(dap_chain_global_db_gr_set(dap_strdup(l_serial_key->header.serial), l_serial_key,
+                        dap_serial_key_len(l_serial_key),
+                        s_group_serials_activated)) {
+                    dap_chain_global_db_gr_del(l_serial_key->header.serial, s_group_serials);
+                    l_ret = 0; // OK
+                }
             }
-        }
-        else{
-            return -2;//OP_CODE_LOGIN_INCORRECT_SIGN
+            // bad pkey
+            else
+                l_ret = -2;//OP_CODE_LOGIN_INCORRECT_SIGN
+            DAP_DELETE(l_sign_raw);
         }
         DAP_DELETE(l_pkey_raw);
     }
@@ -352,7 +361,20 @@ int dap_chain_net_srv_vpn_cdb_auth_check_serial(const char * a_serial, const cha
         if((l_serial_key->header.activated + l_serial_key->header.expired) < time(NULL))
             l_ret = -4;
     }
-    DAP_DELETE(l_serial_key);
+    // check pkey
+    dap_enc_key_t *l_client_key = NULL;
+    size_t l_pkey_length = dap_strlen(a_pkey_b64);
+    byte_t *l_pkey_raw = DAP_NEW_Z_SIZE(byte_t, l_pkey_length);
+    memset(l_pkey_raw, 0, l_pkey_length);
+    size_t l_pkey_raw_size = dap_enc_base64_decode(a_pkey_b64, l_pkey_length, l_pkey_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE);
+    // pkey from sign
+    size_t l_pkey_sign_size = l_serial_key->header.ext_size;
+    uint8_t *l_pkey_sign = l_serial_key->ext;
+    // compare pkeys
+    if(l_pkey_sign_size != l_pkey_raw_size || memcmp(l_pkey_sign, l_pkey_raw, l_pkey_sign_size)) {
+        l_ret = -2;
+    }
+    DAP_DELETE(l_pkey_raw);
     return l_ret;
 }
 
@@ -1091,10 +1113,10 @@ static void s_http_enc_proc(enc_http_delegate_t *a_delegate, void * a_arg)
                             enc_http_reply_f(a_delegate, OP_CODE_NOT_FOUND_LOGIN_IN_DB);
                             *l_return_code = Http_Status_OK;
                             break;
-                        /*case -2:
-                            enc_http_reply_f(a_delegate, OP_CODE_LOGIN_INCORRECT_PSWD);
+                        case -2:
+                            enc_http_reply_f(a_delegate, OP_CODE_LOGIN_INCORRECT_SIGN);// incorrect pkey
                             *l_return_code = Http_Status_OK;
-                            break;*/
+                            break;
                         case -3:
                             enc_http_reply_f(a_delegate, OP_CODE_LOGIN_INACTIVE);
                             *l_return_code = Http_Status_OK;