Sfoglia il codice sorgente

Added the my port of Lua regex and expose to strings as two new functions "gsub","gmatch" with near same functionality of string.gsub and string.gmatch from Lua.
Because squirrel do not allow return multiple values gmatch accepet a function that will receive the matches to process.
Ex:
some_string.gmatch("(%d+)", function(num){ print(num);});

mingodad 13 anni fa
parent
commit
1142e5f27e
4 ha cambiato i file con 825 aggiunte e 2 eliminazioni
  1. 4 2
      squirrel/Makefile
  2. 591 0
      squirrel/lua-regex.c
  3. 87 0
      squirrel/lua-regex.h
  4. 143 0
      squirrel/sqbaselib.cpp

+ 4 - 2
squirrel/Makefile

@@ -18,7 +18,8 @@ OBJS= \
 	sqtable.o \
 	sqtable.o \
 	sqmem.o \
 	sqmem.o \
 	sqvm.o \
 	sqvm.o \
-	sqclass.o
+	sqclass.o \
+	lua-regex.o
 	
 	
 SRCS= \
 SRCS= \
 	sqapi.cpp \
 	sqapi.cpp \
@@ -32,7 +33,8 @@ SRCS= \
 	sqtable.cpp \
 	sqtable.cpp \
 	sqmem.cpp \
 	sqmem.cpp \
 	sqvm.cpp \
 	sqvm.cpp \
-	sqclass.cpp
+	sqclass.cpp \
+	lua-regex.c
 
 
 	
 	
 	
 	

+ 591 - 0
squirrel/lua-regex.c

@@ -0,0 +1,591 @@
+/******************************************************************************
+* Copyright (C) 1994-2008 Lua.org, PUC-Rio.  All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+/*
+Adapted by Domingo Alvarez Duarte 2012
+http://code.google.com/p/lua-regex-standalone/
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "lua-regex.h"
+
+/* macro to `unsign' a character */
+#define uchar(c)    ((unsigned char)(c))
+
+#define L_ESC        '%'
+#define SPECIALS    "^$*+?.([%-"
+
+#define LUA_QL(x)    "'" x "'"
+#define LUA_QS        LUA_QL("%s")
+
+/* translate a relative string position: negative means back from end */
+static size_t posrelat (ptrdiff_t pos, size_t len) {
+  if (pos >= 0) return (size_t)pos;
+  else if (0u - (size_t)pos > len) return 0;
+  else return len - ((size_t)-pos) + 1;
+}
+
+
+static int check_capture (LuaMatchState *ms, int *l_out) {
+  int l;
+  *l_out -= '1';
+  l = *l_out;
+  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED){
+      ms->error = "invalid capture index";
+      return 0;
+  }
+  return 1;
+}
+
+static int capture_to_close (LuaMatchState *ms, int *level_out) {
+  int level = ms->level;
+  for (level--; level>=0; level--)
+    if (ms->capture[level].len == CAP_UNFINISHED) {
+        *level_out = level;
+        return 1;
+    }
+  ms->error = "invalid pattern capture";
+  return 0;
+}
+
+
+static int classend (LuaMatchState *ms, const char *p, const char **result) {
+  switch (*p++) {
+    case L_ESC: {
+      if (p == ms->p_end){
+          ms->error = "malformed pattern (ends with " LUA_QL("%%") ")";
+          return 0;
+      }
+      *result = p+1;
+      return 1;
+    }
+    case '[': {
+      if (*p == '^') p++;
+      do {  /* look for a `]' */
+        if (p == ms->p_end){
+            ms->error = "malformed pattern (missing " LUA_QL("]") ")";
+            return 0;
+        }
+        if (*(p++) == L_ESC && p < ms->p_end)
+          p++;  /* skip escapes (e.g. `%]') */
+      } while (*p != ']');
+      *result = p+1;
+      return 1;
+    }
+    default: {
+      *result = p;
+      return 1;
+    }
+  }
+}
+
+
+static int match_class (int c, int cl) {
+  int res;
+  switch (tolower(cl)) {
+    case 'a' : res = isalpha(c); break;
+    case 'c' : res = iscntrl(c); break;
+    case 'd' : res = isdigit(c); break;
+    case 'g' : res = isgraph(c); break;
+    case 'l' : res = islower(c); break;
+    case 'p' : res = ispunct(c); break;
+    case 's' : res = isspace(c); break;
+    case 'u' : res = isupper(c); break;
+    case 'w' : res = isalnum(c); break;
+    case 'x' : res = isxdigit(c); break;
+    case 'z' : res = (c == 0); break;  /* deprecated option */
+    default: return (cl == c);
+  }
+  return (islower(cl) ? res : !res);
+}
+
+
+static int matchbracketclass (int c, const char *p, const char *ec) {
+  int sig = 1;
+  if (*(p+1) == '^') {
+    sig = 0;
+    p++;  /* skip the `^' */
+  }
+  while (++p < ec) {
+    if (*p == L_ESC) {
+      p++;
+      if (match_class(c, uchar(*p)))
+        return sig;
+    }
+    else if ((*(p+1) == '-') && (p+2 < ec)) {
+      p+=2;
+      if (uchar(*(p-2)) <= c && c <= uchar(*p))
+        return sig;
+    }
+    else if (uchar(*p) == c) return sig;
+  }
+  return !sig;
+}
+
+
+static int singlematch (int c, const char *p, const char *ep) {
+  switch (*p) {
+    case '.': return 1;  /* matches any char */
+    case L_ESC: return match_class(c, uchar(*(p+1)));
+    case '[': return matchbracketclass(c, p, ep-1);
+    default:  return (uchar(*p) == c);
+  }
+}
+
+
+static const char *match (LuaMatchState *ms, const char *s, const char *p);
+
+
+static const char *matchbalance (LuaMatchState *ms, const char *s,
+                                   const char *p) {
+  if (p >= ms->p_end - 1){
+    ms->error = "malformed pattern "
+                      "(missing arguments to " LUA_QL("%%b") ")";
+    return NULL;
+  }
+  if (*s != *p) return NULL;
+  else {
+    int b = *p;
+    int e = *(p+1);
+    int cont = 1;
+    while (++s < ms->src_end) {
+      if (*s == e) {
+        if (--cont == 0) return s+1;
+      }
+      else if (*s == b) cont++;
+    }
+  }
+  return NULL;  /* string ends out of balance */
+}
+
+
+static const char *max_expand (LuaMatchState *ms, const char *s,
+                                 const char *p, const char *ep) {
+  ptrdiff_t i = 0;  /* counts maximum expand for item */
+  while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
+    i++;
+  /* keeps trying to match with the maximum repetitions */
+  while (i>=0) {
+    const char *res = match(ms, (s+i), ep+1);
+    if (res) return res;
+    i--;  /* else didn't match; reduce 1 repetition to try again */
+  }
+  return NULL;
+}
+
+
+static const char *min_expand (LuaMatchState *ms, const char *s,
+                                 const char *p, const char *ep) {
+  for (;;) {
+    const char *res = match(ms, s, ep+1);
+    if (res != NULL)
+      return res;
+    else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
+      s++;  /* try with one more repetition */
+    else return NULL;
+  }
+}
+
+
+static const char *start_capture (LuaMatchState *ms, const char *s,
+                                    const char *p, int what) {
+  const char *res;
+  int level = ms->level;
+  if (level >= LUA_REGEX_MAXCAPTURES) {
+      ms->error = "too many captures";
+      return NULL;
+  }
+  ms->capture[level].init = s;
+  ms->capture[level].len = what;
+  ms->level = level+1;
+  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
+    ms->level--;  /* undo capture */
+  return res;
+}
+
+
+static const char *end_capture (LuaMatchState *ms, const char *s,
+                                  const char *p) {
+  int l;
+  const char *res;
+  if(!capture_to_close(ms, &l)) return NULL;
+  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
+  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
+    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
+  return res;
+}
+
+
+static const char *match_capture (LuaMatchState *ms, const char *s, int l) {
+  size_t len;
+  if(check_capture(ms, &l)){
+      len = ms->capture[l].len;
+      if ((size_t)(ms->src_end-s) >= len &&
+          memcmp(ms->capture[l].init, s, len) == 0)
+        return s+len;
+  }
+  return NULL;
+}
+
+
+static const char *match (LuaMatchState *ms, const char *s, const char *p) {
+  init: /* using goto's to optimize tail recursion */
+  if (p == ms->p_end)  /* end of pattern? */
+    return s;  /* match succeeded */
+  switch (*p) {
+    case '(': {  /* start capture */
+      if (*(p+1) == ')')  /* position capture? */
+        return start_capture(ms, s, p+2, CAP_POSITION);
+      else
+        return start_capture(ms, s, p+1, CAP_UNFINISHED);
+    }
+    case ')': {  /* end capture */
+      return end_capture(ms, s, p+1);
+    }
+    case '$': {
+      if ((p+1) == ms->p_end)  /* is the `$' the last char in pattern? */
+        return (s == ms->src_end) ? s : NULL;  /* check end of string */
+      else goto dflt;
+    }
+    case L_ESC: {  /* escaped sequences not in the format class[*+?-]? */
+      switch (*(p+1)) {
+        case 'b': {  /* balanced string? */
+          s = matchbalance(ms, s, p+2);
+          if (s == NULL) return NULL;
+          p+=4; goto init;  /* else return match(ms, s, p+4); */
+        }
+        case 'f': {  /* frontier? */
+          const char *ep; char previous;
+          p += 2;
+          if (*p != '['){
+            ms->error = "missing " LUA_QL("[") " after "
+                               LUA_QL("%%f") " in pattern";
+            return NULL;
+          }
+          if(!classend(ms, p, &ep)) return NULL;  /* points to what is next */
+          previous = (s == ms->src_init) ? '\0' : *(s-1);
+          if (matchbracketclass(uchar(previous), p, ep-1) ||
+             !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
+          p=ep; goto init;  /* else return match(ms, s, ep); */
+        }
+        case '0': case '1': case '2': case '3':
+        case '4': case '5': case '6': case '7':
+        case '8': case '9': {  /* capture results (%0-%9)? */
+          s = match_capture(ms, s, uchar(*(p+1)));
+          if (s == NULL) return NULL;
+          p+=2; goto init;  /* else return match(ms, s, p+2) */
+        }
+        default: goto dflt;
+      }
+    }
+    default: dflt: {  /* pattern class plus optional suffix */
+      const char *ep;
+	  int m;
+      if(!classend(ms, p, &ep)) return NULL;  /* points to what is next */
+      m = s < ms->src_end && singlematch(uchar(*s), p, ep);
+      switch (*ep) {
+        case '?': {  /* optional */
+          const char *res;
+          if (m && ((res=match(ms, s+1, ep+1)) != NULL))
+            return res;
+          p=ep+1; goto init;  /* else return match(ms, s, ep+1); */
+        }
+        case '*': {  /* 0 or more repetitions */
+          return max_expand(ms, s, p, ep);
+        }
+        case '+': {  /* 1 or more repetitions */
+          return (m ? max_expand(ms, s+1, p, ep) : NULL);
+        }
+        case '-': {  /* 0 or more repetitions (minimum) */
+          return min_expand(ms, s, p, ep);
+        }
+        default: {
+          if (!m) return NULL;
+          s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */
+        }
+      }
+    }
+  }
+}
+
+
+static const char *lmemfind (const char *s1, size_t l1,
+                               const char *s2, size_t l2) {
+  if (l2 == 0) return s1;  /* empty strings are everywhere */
+  else if (l2 > l1) return NULL;  /* avoids a negative `l1' */
+  else {
+    const char *init;  /* to search for a `*s2' inside `s1' */
+    l2--;  /* 1st char will be checked by `memchr' */
+    l1 = l1-l2;  /* `s2' cannot be found after that */
+    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
+      init++;   /* 1st char is already checked */
+      if (memcmp(init, s2+1, l2) == 0)
+        return init-1;
+      else {  /* correct `l1' and `s1' to try again */
+        l1 -= init-s1;
+        s1 = init;
+      }
+    }
+    return NULL;  /* not found */
+  }
+}
+
+
+/* check whether pattern has no special characters */
+static int nospecials (const char *p, size_t l) {
+  size_t upto = 0;
+  do {
+    if (strpbrk(p + upto, SPECIALS))
+      return 0;  /* pattern has a special character */
+    upto += strlen(p + upto) + 1;  /* may have more after \0 */
+  } while (upto <= l);
+  return 1;  /* no special chars found */
+}
+
+
+static int str_find_aux (LuaMatchState *ms, int find, const char *s, int ls,
+                         const char *p, int lp, int init, int raw_find,
+                         luaregex_func_param fp, void *udata) {
+  int result;
+  ms->error = NULL;
+  if(ls < 0) ls = strlen(s);
+  if(lp < 0) lp = strlen(p);
+  init = posrelat(init, ls);
+  if (init < 0) init = 0;
+  else if (init > ls + 1) {  /* start after string's end? */
+    return 0; /* cannot find anything */
+  }
+
+do_again:
+  result = 0; /* not found */
+  /* explicit request or no special characters? */
+  if (find && (raw_find || nospecials(p, lp))) {
+    /* do a plain search */
+    const char *s2 = lmemfind(s + init, ls - init + 1, p, lp);
+    if (s2) {
+      int start_pos = ((int)(s2 - s));
+      ms->level = 1;
+      ms->capture[0].len = CAP_POSITION;
+      ms->capture[0].init = (const char *)start_pos;
+      result = start_pos + lp;
+    }
+  }
+  else {
+    const char *s1 = s + init;
+    int anchor = (*p == '^');
+    if (anchor) {
+      p++; lp--;  /* skip anchor character */
+    }
+    ms->src_init = s;
+    ms->src_end = s + ls;
+    ms->p_end = p + lp;
+    do {
+      const char *res;
+      ms->level = 0;
+      if ((res=match(ms, s1, p)) != NULL) {
+          result = (int)(res - s);
+          goto eofunc;
+      }
+    } while (s1++ < ms->src_end && !anchor);
+  }
+
+eofunc:
+
+  if(result){
+      int i;
+      for(i=0; i<ms->level; ++i){
+          if(ms->capture[i].len == CAP_UNFINISHED){
+              ms->error = "unfinished capture";
+              return 0;
+          }
+      }
+      if(fp && (*fp)(ms, udata, 0)) {
+          init = result;
+          if (init < ls) goto do_again;
+      }
+  }
+  return result;
+}
+
+
+int str_find (LuaMatchState *ms, const char *s, int ls,
+              const char *p, int lp, int init, int raw_find,
+              luaregex_func_param fp, void *udata) {
+  return str_find_aux(ms, 1, s, ls, p, lp, init, raw_find, fp, udata);
+}
+
+
+int str_match (LuaMatchState *ms, const char *s, int ls,
+               const char *p, int lp, int init, int raw_find,
+               luaregex_func_param fp, void *udata) {
+  return str_find_aux(ms, 0, s, ls, p, lp, init, raw_find, fp, udata);
+}
+
+
+#define NEW_SIZE(sz) (((sz/1024)+1)*1024)
+
+int char_buffer_add_char(LuaMatchState *ms, char_buffer_st **b, char c){
+    char_buffer_st *tmp = *b;
+    if(tmp->used+1 >= tmp->size){
+        int new_size = tmp->size+2048;
+        tmp = (char_buffer_st*)realloc(tmp, sizeof(char_buffer_st) + new_size);
+        if(!tmp){
+            ms->error = "not enough memory when reallocating";
+            return 0;
+        }
+        *b = tmp;
+        tmp->size = new_size;
+    }
+    tmp->buf[tmp->used++] = c;
+    return 1;
+}
+
+
+int char_buffer_add_str(LuaMatchState *ms, char_buffer_st **b, const char *str, int len){
+    char_buffer_st *tmp = *b;
+    if(len < 0) len = strlen(str);
+    if(tmp->used+len >= tmp->size){
+        size_t new_size = tmp->size + NEW_SIZE(len);
+        tmp = (char_buffer_st*)realloc(tmp, sizeof(char_buffer_st) + new_size);
+        if(!tmp){
+            ms->error = "not enough memory when reallocating";
+            return 0;
+        }
+        *b = tmp;
+        tmp->size = new_size;
+    }
+    memcpy(&tmp->buf[tmp->used], str, len);
+    tmp->used += len;
+    return 1;
+}
+
+
+static int add_value (LuaMatchState *ms, char_buffer_st **b, const char *s,
+                                       const char *e, const char *news, size_t lnews) {
+  size_t i;
+  for (i = 0; i < lnews; i++) {
+    if (news[i] != L_ESC){
+      if(!char_buffer_add_char(ms, b, news[i])) return 0;
+    }
+    else {
+      i++;  /* skip ESC */
+      if (!isdigit(uchar(news[i]))) {
+        if (news[i] != L_ESC){
+            ms->error = "invalid use of replacement string";
+            return 0;
+        }
+        if(!char_buffer_add_char(ms, b, news[i])) return 0;
+      }
+      else if (news[i] == '0'){
+          if(!char_buffer_add_str(ms, b, s, e - s)) return 0;
+      }
+      else {
+          int il = news[i] - '1';
+          if (il >= ms->level) {
+            if (il == 0){  /* ms->level == 0, too */
+              if(!char_buffer_add_str(ms, b, s, e - s)) return 0;  /* add whole match */
+            }
+            else{
+                ms->error = "invalid capture index";
+                return 0;
+            }
+          }
+          else {
+            ptrdiff_t cl = ms->capture[il].len;
+            if (cl == CAP_UNFINISHED) {
+                ms->error = "unfinished capture";
+                return 0;
+            }
+            if (cl == CAP_POSITION){
+                char buf[32];
+                snprintf(buf, sizeof(buf), "%d", ms->capture[il].init - ms->src_init + 1);
+                if(!char_buffer_add_str(ms, b, buf, strlen(buf))) return 0;
+            }
+            else
+              if(!char_buffer_add_str(ms, b, ms->capture[il].init, cl)) return 0;
+          }
+      }
+    }
+  }
+  return 1;
+}
+
+char_buffer_st *str_gsub (const char *src, int srcl, const char *p, int lp,
+                          const char *tr, int ltr, size_t max_s, const char **error_ptr,
+                          luaregex_func_param fp, void *udata) {
+  int anchor;
+  size_t n;
+  LuaMatchState ms;
+  char_buffer_st *b;
+  if(srcl < 0) srcl = strlen(src);
+  if(lp < 0) lp = strlen(p);
+  if(ltr < 0) ltr = strlen(tr);
+  if(max_s == 0) max_s = srcl+1;
+  anchor = (*p == '^');
+  n = NEW_SIZE(srcl);
+  b = (char_buffer_st*)malloc(sizeof(char_buffer_st) + n);
+  if(!b) return NULL;
+  b->size = n;
+  b->used = 0;
+
+  n = 0;
+  if (anchor) {
+    p++; lp--;  /* skip anchor character */
+  }
+  ms.error = 0;
+  ms.src_init = src;
+  ms.src_end = src+srcl;
+  ms.p_end = p + lp;
+  while (n < max_s) {
+    const char *e;
+    ms.level = 0;
+    e = match(&ms, src, p);
+    if(ms.error) goto free_and_null;
+    if (e) {
+      n++;
+      if(fp){
+          if(!(*fp)(&ms, udata, &b)) goto free_and_null;
+      }
+      else if(!add_value(&ms, &b, src, e, tr, ltr)) goto free_and_null;
+    }
+    if (e && e>src) /* non empty match? */
+      src = e;  /* skip it */
+    else if (src < ms.src_end){
+      if(!char_buffer_add_char(&ms, &b, *src++)) goto free_and_null;
+    }
+    else break;
+    if (anchor) break;
+  }
+  if(!char_buffer_add_str(&ms, &b, src, ms.src_end-src)) goto free_and_null;
+  b->buf[b->used] = '\0';
+  return b;
+
+free_and_null:
+  if(b) free(b);
+  if(error_ptr) *error_ptr = ms.error;
+  return NULL;
+}
+

+ 87 - 0
squirrel/lua-regex.h

@@ -0,0 +1,87 @@
+#ifndef LUA_REGEX_H
+#define LUA_REGEX_H
+
+/******************************************************************************
+* Copyright (C) 1994-2008 Lua.org, PUC-Rio.  All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+/*
+Adapted by Domingo Alvarez Duarte 2012
+http://code.google.com/p/lua-regex-standalone/
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <stddef.h>
+
+/*
+** maximum number of captures that a pattern can do during
+** pattern-matching. This limit is arbitrary.
+*/
+#define LUA_REGEX_MAXCAPTURES		32
+
+#define CAP_UNFINISHED	(-1)
+#define CAP_POSITION	(-2)
+
+typedef struct char_buffer_st {
+    size_t size, used;
+    char buf[1];
+} char_buffer_st;
+
+typedef struct LuaCapture {
+    const char *init;
+    ptrdiff_t len;
+} LuaCapture;
+
+typedef struct LuaMatchState {
+  const char *src_init;  /* init of source string */
+  const char *src_end;  /* end ('\0') of source string */
+  const char *p_end;  /* end ('\0') of pattern */
+  const char *error;
+  int level;  /* total number of captures (finished or unfinished) */
+  LuaCapture capture[LUA_REGEX_MAXCAPTURES];
+} LuaMatchState;
+
+typedef int (*luaregex_func_param)(LuaMatchState *ms, void *udata, char_buffer_st **b);
+
+int str_find (LuaMatchState *ms, const char *s, int ls,
+              const char *p, int lp, int init, int raw_find,
+              luaregex_func_param fp, void *udata);
+
+int str_match (LuaMatchState *ms, const char *s, int ls,
+               const char *p, int lp, int init, int raw_find,
+               luaregex_func_param fp, void *udata);
+
+char_buffer_st *str_gsub (const char *src, int srcl, const char *p, int lp,
+                          const char *tr, int ltr, size_t max_s, const char **error_ptr,
+                          luaregex_func_param fp, void *udata);
+
+int char_buffer_add_char(LuaMatchState *ms, char_buffer_st **b, char c);
+int char_buffer_add_str(LuaMatchState *ms, char_buffer_st **b, const char *str, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //LUA_REGEX_H

+ 143 - 0
squirrel/sqbaselib.cpp

@@ -964,12 +964,153 @@ static SQInteger string_find(HSQUIRRELVM v)
 STRING_TOFUNCZ(tolower)
 STRING_TOFUNCZ(tolower)
 STRING_TOFUNCZ(toupper)
 STRING_TOFUNCZ(toupper)
 
 
+//DAD start
+#include "lua-regex.h"
+
+static int process_string_gsub(LuaMatchState *ms, void *udata, char_buffer_st **b) {
+    const char *str;
+    SQInteger str_size;
+    HSQUIRRELVM v = (HSQUIRRELVM)udata;
+    SQObjectType rtype = sq_gettype(v, 3);
+    SQInteger top = sq_gettop(v);
+    int result = 1;
+    switch(rtype){
+        case OT_CLOSURE:{
+            sq_push(v, 3); //push the function
+            sq_pushroottable(v); //this
+            int i=0;
+            for(; i < ms->level; ++i){
+                sq_pushstring(v, ms->capture[i].init, ms->capture[i].len);
+            }
+            int rc = sq_call(v, i+1, SQTrue, SQTrue);
+            if(rc < 0) return rc;
+            if(SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
+                if(!char_buffer_add_str(ms, b, str, str_size)) {
+                    result = 0;
+                    break;
+                }
+            }
+        }
+        break;
+        case OT_ARRAY:{
+            for(int i=0; i < ms->level; ++i){
+                sq_pushinteger(v, i);
+                sq_get(v, 3);
+                if(SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
+                    if(!char_buffer_add_str(ms, b, str, str_size)) {
+                        result = 0;
+                        break;
+                    }
+                }
+                sq_pop(v, 1); //remove value
+            }
+        }
+        break;
+        case OT_TABLE:{
+            for(int i=0; i < ms->level; ++i){
+                sq_pushstring(v, ms->capture[i].init, ms->capture[i].len);
+                sq_get(v, 3);
+                if(SQ_SUCCEEDED(sq_getstr_and_size(v, -1, &str, &str_size))){
+                    if(!char_buffer_add_str(ms, b, str, str_size)) {
+                        result = 0;
+                        break;
+                    }
+                }
+                sq_pop(v, 1); //remove value
+            }
+        }
+    }
+    sq_settop(v, top); //restore the stack to it's original state
+    return result; //returning non zero means continue
+}
+
+static SQInteger string_gsub(HSQUIRRELVM v)
+{
+    const char *error_ptr;
+    SQ_FUNC_VARS(v);
+    SQ_GET_STRING(v, 1, src);
+    SQ_GET_STRING(v, 2, pattern);
+    SQ_OPT_INTEGER(v, 4, max_sub, 0);
+    SQObjectType rtype = sq_gettype(v, 3);
+    if(rtype == OT_STRING){
+        SQ_GET_STRING(v, 3, replacement);
+        char_buffer_st *buf = str_gsub (src, src_size, pattern, pattern_size,
+                              replacement, replacement_size, max_sub, &error_ptr, 0, 0);
+        if(buf){
+            sq_pushstring(v, buf->buf, buf->used);
+            free(buf);
+            return 1;
+        }
+        return sq_throwerror(v,error_ptr);
+    }
+    else
+    {
+        switch(rtype){
+            case OT_CLOSURE:
+            case OT_ARRAY:
+            case OT_TABLE:{
+                char_buffer_st *buf = str_gsub (src, src_size, pattern, pattern_size,
+                              0, 0, max_sub, &error_ptr, process_string_gsub, v);
+                if(buf){
+                    sq_pushstring(v, buf->buf, buf->used);
+                    free(buf);
+                    return 1;
+                }
+                return sq_throwerror(v,error_ptr);
+            }
+        }
+    }
+	return sq_throwerror(v,"invalid type for parameter 3 function/table/array/string expected");
+}
+
+static int process_string_gmatch(LuaMatchState *ms, void *udata, char_buffer_st **b) {
+    HSQUIRRELVM v = (HSQUIRRELVM)udata;
+    SQInteger top = sq_gettop(v);
+    int result = 1;
+    sq_pushroottable(v); //this en, function already on top of stack
+    int i=0;
+    for(; i < ms->level; ++i){
+        sq_pushstring(v, ms->capture[i].init, ms->capture[i].len);
+    }
+    int rc = sq_call(v, i+1, SQTrue, SQTrue);
+    if(rc < 0) return rc;
+    SQObjectType rtype = sq_gettype(v, -1);
+    if(rtype == OT_BOOL) {
+        SQBool b;
+        sq_getbool(v, -1, &b);
+        result = b == SQTrue;
+    }
+    else result = rtype != OT_NULL;
+
+    sq_settop(v, top); //restore the stack to it's original state
+    return result; //returning non zero means continue
+}
+
+static SQInteger string_gmatch(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS_NO_TOP(v);
+    SQ_GET_STRING(v, 1, src);
+    SQ_GET_STRING(v, 2, pattern);
+    SQInteger rtype = sq_gettype(v, 3);
+    if(rtype == OT_CLOSURE){
+        LuaMatchState ms;
+        memset(&ms, 0, sizeof(ms));
+        str_match(&ms, src, src_size, pattern, pattern_size,
+                0, 0, process_string_gmatch, v);
+        if(ms.error) return sq_throwerror(v, ms.error);
+        return 0;
+    }
+	return sq_throwerror(v,"invalid type for parameter 3 function expected");
+}
+
 static SQInteger string_getdelegate(HSQUIRRELVM v)
 static SQInteger string_getdelegate(HSQUIRRELVM v)
 {
 {
 	sq_pushobject(v,_ss(v)->_string_default_delegate);
 	sq_pushobject(v,_ss(v)->_string_default_delegate);
 	return 1;
 	return 1;
 }
 }
 
 
+//DAD end
+
 SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
 SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
 	{_SC("len"),default_delegate_len,1, _SC("s")},
 	{_SC("len"),default_delegate_len,1, _SC("s")},
 	{_SC("tointeger"),default_delegate_tointeger,-1, _SC("si")},
 	{_SC("tointeger"),default_delegate_tointeger,-1, _SC("si")},
@@ -977,6 +1118,8 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
 	{_SC("tostring"),default_delegate_tostring,1, _SC(".")},
 	{_SC("tostring"),default_delegate_tostring,1, _SC(".")},
 	{_SC("slice"),string_slice,-1, _SC(" s n  n")},
 	{_SC("slice"),string_slice,-1, _SC(" s n  n")},
 	{_SC("find"),string_find,-2, _SC("s s n ")},
 	{_SC("find"),string_find,-2, _SC("s s n ")},
+	{_SC("gsub"),string_gsub,-3, _SC("s s s|a|t|c n")},
+	{_SC("gmatch"),string_gmatch, 3, _SC("s s c")},
 	{_SC("tolower"),string_tolower,1, _SC("s")},
 	{_SC("tolower"),string_tolower,1, _SC("s")},
 	{_SC("toupper"),string_toupper,1, _SC("s")},
 	{_SC("toupper"),string_toupper,1, _SC("s")},
 	{_SC("weakref"),obj_delegate_weakref,1, NULL },
 	{_SC("weakref"),obj_delegate_weakref,1, NULL },