immunio 0.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +234 -0
- data/README.md +147 -0
- data/bin/immunio +5 -0
- data/lib/immunio.rb +29 -0
- data/lib/immunio/agent.rb +260 -0
- data/lib/immunio/authentication.rb +96 -0
- data/lib/immunio/blocked_app.rb +38 -0
- data/lib/immunio/channel.rb +432 -0
- data/lib/immunio/cli.rb +39 -0
- data/lib/immunio/context.rb +114 -0
- data/lib/immunio/errors.rb +43 -0
- data/lib/immunio/immunio_ca.crt +45 -0
- data/lib/immunio/logger.rb +87 -0
- data/lib/immunio/plugins/action_dispatch.rb +45 -0
- data/lib/immunio/plugins/action_view.rb +431 -0
- data/lib/immunio/plugins/active_record.rb +707 -0
- data/lib/immunio/plugins/active_record_relation.rb +370 -0
- data/lib/immunio/plugins/authlogic.rb +80 -0
- data/lib/immunio/plugins/csrf.rb +24 -0
- data/lib/immunio/plugins/devise.rb +40 -0
- data/lib/immunio/plugins/environment_reporter.rb +69 -0
- data/lib/immunio/plugins/eval.rb +51 -0
- data/lib/immunio/plugins/exception_handler.rb +55 -0
- data/lib/immunio/plugins/gems_tracker.rb +5 -0
- data/lib/immunio/plugins/haml.rb +36 -0
- data/lib/immunio/plugins/http_finisher.rb +50 -0
- data/lib/immunio/plugins/http_tracker.rb +203 -0
- data/lib/immunio/plugins/io.rb +96 -0
- data/lib/immunio/plugins/redirect.rb +42 -0
- data/lib/immunio/plugins/warden.rb +66 -0
- data/lib/immunio/processor.rb +234 -0
- data/lib/immunio/rails.rb +26 -0
- data/lib/immunio/request.rb +139 -0
- data/lib/immunio/rufus_lua_ext/ref.rb +27 -0
- data/lib/immunio/rufus_lua_ext/state.rb +157 -0
- data/lib/immunio/rufus_lua_ext/table.rb +137 -0
- data/lib/immunio/rufus_lua_ext/utils.rb +13 -0
- data/lib/immunio/version.rb +5 -0
- data/lib/immunio/vm.rb +291 -0
- data/lua-hooks/ext/all.c +78 -0
- data/lua-hooks/ext/bitop/README +22 -0
- data/lua-hooks/ext/bitop/bit.c +189 -0
- data/lua-hooks/ext/extconf.rb +38 -0
- data/lua-hooks/ext/libinjection/COPYING +37 -0
- data/lua-hooks/ext/libinjection/libinjection.h +65 -0
- data/lua-hooks/ext/libinjection/libinjection_html5.c +847 -0
- data/lua-hooks/ext/libinjection/libinjection_html5.h +54 -0
- data/lua-hooks/ext/libinjection/libinjection_sqli.c +2301 -0
- data/lua-hooks/ext/libinjection/libinjection_sqli.h +295 -0
- data/lua-hooks/ext/libinjection/libinjection_sqli_data.h +9349 -0
- data/lua-hooks/ext/libinjection/libinjection_xss.c +531 -0
- data/lua-hooks/ext/libinjection/libinjection_xss.h +21 -0
- data/lua-hooks/ext/libinjection/lualib.c +109 -0
- data/lua-hooks/ext/lpeg/HISTORY +90 -0
- data/lua-hooks/ext/lpeg/lpcap.c +537 -0
- data/lua-hooks/ext/lpeg/lpcap.h +43 -0
- data/lua-hooks/ext/lpeg/lpcode.c +986 -0
- data/lua-hooks/ext/lpeg/lpcode.h +34 -0
- data/lua-hooks/ext/lpeg/lpeg-128.gif +0 -0
- data/lua-hooks/ext/lpeg/lpeg.html +1429 -0
- data/lua-hooks/ext/lpeg/lpprint.c +244 -0
- data/lua-hooks/ext/lpeg/lpprint.h +35 -0
- data/lua-hooks/ext/lpeg/lptree.c +1238 -0
- data/lua-hooks/ext/lpeg/lptree.h +77 -0
- data/lua-hooks/ext/lpeg/lptypes.h +149 -0
- data/lua-hooks/ext/lpeg/lpvm.c +355 -0
- data/lua-hooks/ext/lpeg/lpvm.h +58 -0
- data/lua-hooks/ext/lpeg/makefile +55 -0
- data/lua-hooks/ext/lpeg/re.html +498 -0
- data/lua-hooks/ext/lpeg/test.lua +1409 -0
- data/lua-hooks/ext/lua-cmsgpack/CMakeLists.txt +45 -0
- data/lua-hooks/ext/lua-cmsgpack/README.md +115 -0
- data/lua-hooks/ext/lua-cmsgpack/lua_cmsgpack.c +957 -0
- data/lua-hooks/ext/lua-cmsgpack/test.lua +570 -0
- data/lua-hooks/ext/lua-snapshot/LICENSE +7 -0
- data/lua-hooks/ext/lua-snapshot/Makefile +12 -0
- data/lua-hooks/ext/lua-snapshot/README.md +18 -0
- data/lua-hooks/ext/lua-snapshot/dump.lua +15 -0
- data/lua-hooks/ext/lua-snapshot/snapshot.c +455 -0
- data/lua-hooks/ext/lua/COPYRIGHT +34 -0
- data/lua-hooks/ext/lua/lapi.c +1087 -0
- data/lua-hooks/ext/lua/lapi.h +16 -0
- data/lua-hooks/ext/lua/lauxlib.c +652 -0
- data/lua-hooks/ext/lua/lauxlib.h +174 -0
- data/lua-hooks/ext/lua/lbaselib.c +659 -0
- data/lua-hooks/ext/lua/lcode.c +831 -0
- data/lua-hooks/ext/lua/lcode.h +76 -0
- data/lua-hooks/ext/lua/ldblib.c +398 -0
- data/lua-hooks/ext/lua/ldebug.c +638 -0
- data/lua-hooks/ext/lua/ldebug.h +33 -0
- data/lua-hooks/ext/lua/ldo.c +519 -0
- data/lua-hooks/ext/lua/ldo.h +57 -0
- data/lua-hooks/ext/lua/ldump.c +164 -0
- data/lua-hooks/ext/lua/lfunc.c +174 -0
- data/lua-hooks/ext/lua/lfunc.h +34 -0
- data/lua-hooks/ext/lua/lgc.c +710 -0
- data/lua-hooks/ext/lua/lgc.h +110 -0
- data/lua-hooks/ext/lua/linit.c +38 -0
- data/lua-hooks/ext/lua/liolib.c +556 -0
- data/lua-hooks/ext/lua/llex.c +463 -0
- data/lua-hooks/ext/lua/llex.h +81 -0
- data/lua-hooks/ext/lua/llimits.h +128 -0
- data/lua-hooks/ext/lua/lmathlib.c +263 -0
- data/lua-hooks/ext/lua/lmem.c +86 -0
- data/lua-hooks/ext/lua/lmem.h +49 -0
- data/lua-hooks/ext/lua/loadlib.c +705 -0
- data/lua-hooks/ext/lua/loadlib_rel.c +760 -0
- data/lua-hooks/ext/lua/lobject.c +214 -0
- data/lua-hooks/ext/lua/lobject.h +381 -0
- data/lua-hooks/ext/lua/lopcodes.c +102 -0
- data/lua-hooks/ext/lua/lopcodes.h +268 -0
- data/lua-hooks/ext/lua/loslib.c +243 -0
- data/lua-hooks/ext/lua/lparser.c +1339 -0
- data/lua-hooks/ext/lua/lparser.h +82 -0
- data/lua-hooks/ext/lua/lstate.c +214 -0
- data/lua-hooks/ext/lua/lstate.h +169 -0
- data/lua-hooks/ext/lua/lstring.c +111 -0
- data/lua-hooks/ext/lua/lstring.h +31 -0
- data/lua-hooks/ext/lua/lstrlib.c +871 -0
- data/lua-hooks/ext/lua/ltable.c +588 -0
- data/lua-hooks/ext/lua/ltable.h +40 -0
- data/lua-hooks/ext/lua/ltablib.c +287 -0
- data/lua-hooks/ext/lua/ltm.c +75 -0
- data/lua-hooks/ext/lua/ltm.h +54 -0
- data/lua-hooks/ext/lua/lua.c +392 -0
- data/lua-hooks/ext/lua/lua.def +131 -0
- data/lua-hooks/ext/lua/lua.h +388 -0
- data/lua-hooks/ext/lua/lua.rc +28 -0
- data/lua-hooks/ext/lua/lua_dll.rc +26 -0
- data/lua-hooks/ext/lua/luac.c +200 -0
- data/lua-hooks/ext/lua/luac.rc +1 -0
- data/lua-hooks/ext/lua/luaconf.h +763 -0
- data/lua-hooks/ext/lua/luaconf.h.in +724 -0
- data/lua-hooks/ext/lua/luaconf.h.orig +763 -0
- data/lua-hooks/ext/lua/lualib.h +53 -0
- data/lua-hooks/ext/lua/lundump.c +227 -0
- data/lua-hooks/ext/lua/lundump.h +36 -0
- data/lua-hooks/ext/lua/lvm.c +767 -0
- data/lua-hooks/ext/lua/lvm.h +36 -0
- data/lua-hooks/ext/lua/lzio.c +82 -0
- data/lua-hooks/ext/lua/lzio.h +67 -0
- data/lua-hooks/ext/lua/print.c +227 -0
- data/lua-hooks/ext/luautf8/README.md +152 -0
- data/lua-hooks/ext/luautf8/lutf8lib.c +1274 -0
- data/lua-hooks/ext/luautf8/unidata.h +3064 -0
- data/lua-hooks/lib/boot.lua +254 -0
- data/lua-hooks/lib/encode.lua +4 -0
- data/lua-hooks/lib/lexers/LICENSE +21 -0
- data/lua-hooks/lib/lexers/bash.lua +134 -0
- data/lua-hooks/lib/lexers/bash_dqstr.lua +62 -0
- data/lua-hooks/lib/lexers/css.lua +216 -0
- data/lua-hooks/lib/lexers/html.lua +106 -0
- data/lua-hooks/lib/lexers/javascript.lua +68 -0
- data/lua-hooks/lib/lexers/lexer.lua +1575 -0
- data/lua-hooks/lib/lexers/markers.lua +33 -0
- metadata +308 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
/*
|
2
|
+
** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
|
3
|
+
** String table (keeps all strings handled by Lua)
|
4
|
+
** See Copyright Notice in lua.h
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
#include <string.h>
|
9
|
+
|
10
|
+
#define lstring_c
|
11
|
+
#define LUA_CORE
|
12
|
+
|
13
|
+
#include "lua.h"
|
14
|
+
|
15
|
+
#include "lmem.h"
|
16
|
+
#include "lobject.h"
|
17
|
+
#include "lstate.h"
|
18
|
+
#include "lstring.h"
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
void luaS_resize (lua_State *L, int newsize) {
|
23
|
+
GCObject **newhash;
|
24
|
+
stringtable *tb;
|
25
|
+
int i;
|
26
|
+
if (G(L)->gcstate == GCSsweepstring)
|
27
|
+
return; /* cannot resize during GC traverse */
|
28
|
+
newhash = luaM_newvector(L, newsize, GCObject *);
|
29
|
+
tb = &G(L)->strt;
|
30
|
+
for (i=0; i<newsize; i++) newhash[i] = NULL;
|
31
|
+
/* rehash */
|
32
|
+
for (i=0; i<tb->size; i++) {
|
33
|
+
GCObject *p = tb->hash[i];
|
34
|
+
while (p) { /* for each node in the list */
|
35
|
+
GCObject *next = p->gch.next; /* save next */
|
36
|
+
unsigned int h = gco2ts(p)->hash;
|
37
|
+
int h1 = lmod(h, newsize); /* new position */
|
38
|
+
lua_assert(cast_int(h%newsize) == lmod(h, newsize));
|
39
|
+
p->gch.next = newhash[h1]; /* chain it */
|
40
|
+
newhash[h1] = p;
|
41
|
+
p = next;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
luaM_freearray(L, tb->hash, tb->size, TString *);
|
45
|
+
tb->size = newsize;
|
46
|
+
tb->hash = newhash;
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
static TString *newlstr (lua_State *L, const char *str, size_t l,
|
51
|
+
unsigned int h) {
|
52
|
+
TString *ts;
|
53
|
+
stringtable *tb;
|
54
|
+
if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
|
55
|
+
luaM_toobig(L);
|
56
|
+
ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
|
57
|
+
ts->tsv.len = l;
|
58
|
+
ts->tsv.hash = h;
|
59
|
+
ts->tsv.marked = luaC_white(G(L));
|
60
|
+
ts->tsv.tt = LUA_TSTRING;
|
61
|
+
ts->tsv.reserved = 0;
|
62
|
+
memcpy(ts+1, str, l*sizeof(char));
|
63
|
+
((char *)(ts+1))[l] = '\0'; /* ending 0 */
|
64
|
+
tb = &G(L)->strt;
|
65
|
+
h = lmod(h, tb->size);
|
66
|
+
ts->tsv.next = tb->hash[h]; /* chain new entry */
|
67
|
+
tb->hash[h] = obj2gco(ts);
|
68
|
+
tb->nuse++;
|
69
|
+
if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
|
70
|
+
luaS_resize(L, tb->size*2); /* too crowded */
|
71
|
+
return ts;
|
72
|
+
}
|
73
|
+
|
74
|
+
|
75
|
+
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
76
|
+
GCObject *o;
|
77
|
+
unsigned int h = cast(unsigned int, l); /* seed */
|
78
|
+
size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
|
79
|
+
size_t l1;
|
80
|
+
for (l1=l; l1>=step; l1-=step) /* compute hash */
|
81
|
+
h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
|
82
|
+
for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
|
83
|
+
o != NULL;
|
84
|
+
o = o->gch.next) {
|
85
|
+
TString *ts = rawgco2ts(o);
|
86
|
+
if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
|
87
|
+
/* string may be dead */
|
88
|
+
if (isdead(G(L), o)) changewhite(o);
|
89
|
+
return ts;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
return newlstr(L, str, l, h); /* not found */
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
|
97
|
+
Udata *u;
|
98
|
+
if (s > MAX_SIZET - sizeof(Udata))
|
99
|
+
luaM_toobig(L);
|
100
|
+
u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata)));
|
101
|
+
u->uv.marked = luaC_white(G(L)); /* is not finalized */
|
102
|
+
u->uv.tt = LUA_TUSERDATA;
|
103
|
+
u->uv.len = s;
|
104
|
+
u->uv.metatable = NULL;
|
105
|
+
u->uv.env = e;
|
106
|
+
/* chain it on udata list (after main thread) */
|
107
|
+
u->uv.next = G(L)->mainthread->next;
|
108
|
+
G(L)->mainthread->next = obj2gco(u);
|
109
|
+
return u;
|
110
|
+
}
|
111
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
/*
|
2
|
+
** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $
|
3
|
+
** String table (keep all strings handled by Lua)
|
4
|
+
** See Copyright Notice in lua.h
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifndef lstring_h
|
8
|
+
#define lstring_h
|
9
|
+
|
10
|
+
|
11
|
+
#include "lgc.h"
|
12
|
+
#include "lobject.h"
|
13
|
+
#include "lstate.h"
|
14
|
+
|
15
|
+
|
16
|
+
#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char))
|
17
|
+
|
18
|
+
#define sizeudata(u) (sizeof(union Udata)+(u)->len)
|
19
|
+
|
20
|
+
#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s)))
|
21
|
+
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
|
22
|
+
(sizeof(s)/sizeof(char))-1))
|
23
|
+
|
24
|
+
#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
|
25
|
+
|
26
|
+
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
27
|
+
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
|
28
|
+
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
29
|
+
|
30
|
+
|
31
|
+
#endif
|
@@ -0,0 +1,871 @@
|
|
1
|
+
/*
|
2
|
+
** $Id: lstrlib.c,v 1.132.1.5 2010/05/14 15:34:19 roberto Exp $
|
3
|
+
** Standard library for string operations and pattern-matching
|
4
|
+
** See Copyright Notice in lua.h
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
#include <ctype.h>
|
9
|
+
#include <stddef.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdlib.h>
|
12
|
+
#include <string.h>
|
13
|
+
|
14
|
+
#define lstrlib_c
|
15
|
+
#define LUA_LIB
|
16
|
+
|
17
|
+
#include "lua.h"
|
18
|
+
|
19
|
+
#include "lauxlib.h"
|
20
|
+
#include "lualib.h"
|
21
|
+
|
22
|
+
|
23
|
+
/* macro to `unsign' a character */
|
24
|
+
#define uchar(c) ((unsigned char)(c))
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
static int str_len (lua_State *L) {
|
29
|
+
size_t l;
|
30
|
+
luaL_checklstring(L, 1, &l);
|
31
|
+
lua_pushinteger(L, l);
|
32
|
+
return 1;
|
33
|
+
}
|
34
|
+
|
35
|
+
|
36
|
+
static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
|
37
|
+
/* relative string position: negative means back from end */
|
38
|
+
if (pos < 0) pos += (ptrdiff_t)len + 1;
|
39
|
+
return (pos >= 0) ? pos : 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
static int str_sub (lua_State *L) {
|
44
|
+
size_t l;
|
45
|
+
const char *s = luaL_checklstring(L, 1, &l);
|
46
|
+
ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
|
47
|
+
ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
|
48
|
+
if (start < 1) start = 1;
|
49
|
+
if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
|
50
|
+
if (start <= end)
|
51
|
+
lua_pushlstring(L, s+start-1, end-start+1);
|
52
|
+
else lua_pushliteral(L, "");
|
53
|
+
return 1;
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
static int str_reverse (lua_State *L) {
|
58
|
+
size_t l;
|
59
|
+
luaL_Buffer b;
|
60
|
+
const char *s = luaL_checklstring(L, 1, &l);
|
61
|
+
luaL_buffinit(L, &b);
|
62
|
+
while (l--) luaL_addchar(&b, s[l]);
|
63
|
+
luaL_pushresult(&b);
|
64
|
+
return 1;
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
static int str_lower (lua_State *L) {
|
69
|
+
size_t l;
|
70
|
+
size_t i;
|
71
|
+
luaL_Buffer b;
|
72
|
+
const char *s = luaL_checklstring(L, 1, &l);
|
73
|
+
luaL_buffinit(L, &b);
|
74
|
+
for (i=0; i<l; i++)
|
75
|
+
luaL_addchar(&b, tolower(uchar(s[i])));
|
76
|
+
luaL_pushresult(&b);
|
77
|
+
return 1;
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
static int str_upper (lua_State *L) {
|
82
|
+
size_t l;
|
83
|
+
size_t i;
|
84
|
+
luaL_Buffer b;
|
85
|
+
const char *s = luaL_checklstring(L, 1, &l);
|
86
|
+
luaL_buffinit(L, &b);
|
87
|
+
for (i=0; i<l; i++)
|
88
|
+
luaL_addchar(&b, toupper(uchar(s[i])));
|
89
|
+
luaL_pushresult(&b);
|
90
|
+
return 1;
|
91
|
+
}
|
92
|
+
|
93
|
+
static int str_rep (lua_State *L) {
|
94
|
+
size_t l;
|
95
|
+
luaL_Buffer b;
|
96
|
+
const char *s = luaL_checklstring(L, 1, &l);
|
97
|
+
int n = luaL_checkint(L, 2);
|
98
|
+
luaL_buffinit(L, &b);
|
99
|
+
while (n-- > 0)
|
100
|
+
luaL_addlstring(&b, s, l);
|
101
|
+
luaL_pushresult(&b);
|
102
|
+
return 1;
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
static int str_byte (lua_State *L) {
|
107
|
+
size_t l;
|
108
|
+
const char *s = luaL_checklstring(L, 1, &l);
|
109
|
+
ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
|
110
|
+
ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
|
111
|
+
int n, i;
|
112
|
+
if (posi <= 0) posi = 1;
|
113
|
+
if ((size_t)pose > l) pose = l;
|
114
|
+
if (posi > pose) return 0; /* empty interval; return no values */
|
115
|
+
n = (int)(pose - posi + 1);
|
116
|
+
if (posi + n <= pose) /* overflow? */
|
117
|
+
luaL_error(L, "string slice too long");
|
118
|
+
luaL_checkstack(L, n, "string slice too long");
|
119
|
+
for (i=0; i<n; i++)
|
120
|
+
lua_pushinteger(L, uchar(s[posi+i-1]));
|
121
|
+
return n;
|
122
|
+
}
|
123
|
+
|
124
|
+
|
125
|
+
static int str_char (lua_State *L) {
|
126
|
+
int n = lua_gettop(L); /* number of arguments */
|
127
|
+
int i;
|
128
|
+
luaL_Buffer b;
|
129
|
+
luaL_buffinit(L, &b);
|
130
|
+
for (i=1; i<=n; i++) {
|
131
|
+
int c = luaL_checkint(L, i);
|
132
|
+
luaL_argcheck(L, uchar(c) == c, i, "invalid value");
|
133
|
+
luaL_addchar(&b, uchar(c));
|
134
|
+
}
|
135
|
+
luaL_pushresult(&b);
|
136
|
+
return 1;
|
137
|
+
}
|
138
|
+
|
139
|
+
|
140
|
+
static int writer (lua_State *L, const void* b, size_t size, void* B) {
|
141
|
+
(void)L;
|
142
|
+
luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
|
143
|
+
return 0;
|
144
|
+
}
|
145
|
+
|
146
|
+
|
147
|
+
static int str_dump (lua_State *L) {
|
148
|
+
luaL_Buffer b;
|
149
|
+
luaL_checktype(L, 1, LUA_TFUNCTION);
|
150
|
+
lua_settop(L, 1);
|
151
|
+
luaL_buffinit(L,&b);
|
152
|
+
if (lua_dump(L, writer, &b) != 0)
|
153
|
+
luaL_error(L, "unable to dump given function");
|
154
|
+
luaL_pushresult(&b);
|
155
|
+
return 1;
|
156
|
+
}
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
/*
|
161
|
+
** {======================================================
|
162
|
+
** PATTERN MATCHING
|
163
|
+
** =======================================================
|
164
|
+
*/
|
165
|
+
|
166
|
+
|
167
|
+
#define CAP_UNFINISHED (-1)
|
168
|
+
#define CAP_POSITION (-2)
|
169
|
+
|
170
|
+
typedef struct MatchState {
|
171
|
+
const char *src_init; /* init of source string */
|
172
|
+
const char *src_end; /* end (`\0') of source string */
|
173
|
+
lua_State *L;
|
174
|
+
int level; /* total number of captures (finished or unfinished) */
|
175
|
+
struct {
|
176
|
+
const char *init;
|
177
|
+
ptrdiff_t len;
|
178
|
+
} capture[LUA_MAXCAPTURES];
|
179
|
+
} MatchState;
|
180
|
+
|
181
|
+
|
182
|
+
#define L_ESC '%'
|
183
|
+
#define SPECIALS "^$*+?.([%-"
|
184
|
+
|
185
|
+
|
186
|
+
static int check_capture (MatchState *ms, int l) {
|
187
|
+
l -= '1';
|
188
|
+
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
|
189
|
+
return luaL_error(ms->L, "invalid capture index");
|
190
|
+
return l;
|
191
|
+
}
|
192
|
+
|
193
|
+
|
194
|
+
static int capture_to_close (MatchState *ms) {
|
195
|
+
int level = ms->level;
|
196
|
+
for (level--; level>=0; level--)
|
197
|
+
if (ms->capture[level].len == CAP_UNFINISHED) return level;
|
198
|
+
return luaL_error(ms->L, "invalid pattern capture");
|
199
|
+
}
|
200
|
+
|
201
|
+
|
202
|
+
static const char *classend (MatchState *ms, const char *p) {
|
203
|
+
switch (*p++) {
|
204
|
+
case L_ESC: {
|
205
|
+
if (*p == '\0')
|
206
|
+
luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
|
207
|
+
return p+1;
|
208
|
+
}
|
209
|
+
case '[': {
|
210
|
+
if (*p == '^') p++;
|
211
|
+
do { /* look for a `]' */
|
212
|
+
if (*p == '\0')
|
213
|
+
luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
|
214
|
+
if (*(p++) == L_ESC && *p != '\0')
|
215
|
+
p++; /* skip escapes (e.g. `%]') */
|
216
|
+
} while (*p != ']');
|
217
|
+
return p+1;
|
218
|
+
}
|
219
|
+
default: {
|
220
|
+
return p;
|
221
|
+
}
|
222
|
+
}
|
223
|
+
}
|
224
|
+
|
225
|
+
|
226
|
+
static int match_class (int c, int cl) {
|
227
|
+
int res;
|
228
|
+
switch (tolower(cl)) {
|
229
|
+
case 'a' : res = isalpha(c); break;
|
230
|
+
case 'c' : res = iscntrl(c); break;
|
231
|
+
case 'd' : res = isdigit(c); break;
|
232
|
+
case 'l' : res = islower(c); break;
|
233
|
+
case 'p' : res = ispunct(c); break;
|
234
|
+
case 's' : res = isspace(c); break;
|
235
|
+
case 'u' : res = isupper(c); break;
|
236
|
+
case 'w' : res = isalnum(c); break;
|
237
|
+
case 'x' : res = isxdigit(c); break;
|
238
|
+
case 'z' : res = (c == 0); break;
|
239
|
+
default: return (cl == c);
|
240
|
+
}
|
241
|
+
return (islower(cl) ? res : !res);
|
242
|
+
}
|
243
|
+
|
244
|
+
|
245
|
+
static int matchbracketclass (int c, const char *p, const char *ec) {
|
246
|
+
int sig = 1;
|
247
|
+
if (*(p+1) == '^') {
|
248
|
+
sig = 0;
|
249
|
+
p++; /* skip the `^' */
|
250
|
+
}
|
251
|
+
while (++p < ec) {
|
252
|
+
if (*p == L_ESC) {
|
253
|
+
p++;
|
254
|
+
if (match_class(c, uchar(*p)))
|
255
|
+
return sig;
|
256
|
+
}
|
257
|
+
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
258
|
+
p+=2;
|
259
|
+
if (uchar(*(p-2)) <= c && c <= uchar(*p))
|
260
|
+
return sig;
|
261
|
+
}
|
262
|
+
else if (uchar(*p) == c) return sig;
|
263
|
+
}
|
264
|
+
return !sig;
|
265
|
+
}
|
266
|
+
|
267
|
+
|
268
|
+
static int singlematch (int c, const char *p, const char *ep) {
|
269
|
+
switch (*p) {
|
270
|
+
case '.': return 1; /* matches any char */
|
271
|
+
case L_ESC: return match_class(c, uchar(*(p+1)));
|
272
|
+
case '[': return matchbracketclass(c, p, ep-1);
|
273
|
+
default: return (uchar(*p) == c);
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
|
278
|
+
static const char *match (MatchState *ms, const char *s, const char *p);
|
279
|
+
|
280
|
+
|
281
|
+
static const char *matchbalance (MatchState *ms, const char *s,
|
282
|
+
const char *p) {
|
283
|
+
if (*p == 0 || *(p+1) == 0)
|
284
|
+
luaL_error(ms->L, "unbalanced pattern");
|
285
|
+
if (*s != *p) return NULL;
|
286
|
+
else {
|
287
|
+
int b = *p;
|
288
|
+
int e = *(p+1);
|
289
|
+
int cont = 1;
|
290
|
+
while (++s < ms->src_end) {
|
291
|
+
if (*s == e) {
|
292
|
+
if (--cont == 0) return s+1;
|
293
|
+
}
|
294
|
+
else if (*s == b) cont++;
|
295
|
+
}
|
296
|
+
}
|
297
|
+
return NULL; /* string ends out of balance */
|
298
|
+
}
|
299
|
+
|
300
|
+
|
301
|
+
static const char *max_expand (MatchState *ms, const char *s,
|
302
|
+
const char *p, const char *ep) {
|
303
|
+
ptrdiff_t i = 0; /* counts maximum expand for item */
|
304
|
+
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
|
305
|
+
i++;
|
306
|
+
/* keeps trying to match with the maximum repetitions */
|
307
|
+
while (i>=0) {
|
308
|
+
const char *res = match(ms, (s+i), ep+1);
|
309
|
+
if (res) return res;
|
310
|
+
i--; /* else didn't match; reduce 1 repetition to try again */
|
311
|
+
}
|
312
|
+
return NULL;
|
313
|
+
}
|
314
|
+
|
315
|
+
|
316
|
+
static const char *min_expand (MatchState *ms, const char *s,
|
317
|
+
const char *p, const char *ep) {
|
318
|
+
for (;;) {
|
319
|
+
const char *res = match(ms, s, ep+1);
|
320
|
+
if (res != NULL)
|
321
|
+
return res;
|
322
|
+
else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
|
323
|
+
s++; /* try with one more repetition */
|
324
|
+
else return NULL;
|
325
|
+
}
|
326
|
+
}
|
327
|
+
|
328
|
+
|
329
|
+
static const char *start_capture (MatchState *ms, const char *s,
|
330
|
+
const char *p, int what) {
|
331
|
+
const char *res;
|
332
|
+
int level = ms->level;
|
333
|
+
if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
|
334
|
+
ms->capture[level].init = s;
|
335
|
+
ms->capture[level].len = what;
|
336
|
+
ms->level = level+1;
|
337
|
+
if ((res=match(ms, s, p)) == NULL) /* match failed? */
|
338
|
+
ms->level--; /* undo capture */
|
339
|
+
return res;
|
340
|
+
}
|
341
|
+
|
342
|
+
|
343
|
+
static const char *end_capture (MatchState *ms, const char *s,
|
344
|
+
const char *p) {
|
345
|
+
int l = capture_to_close(ms);
|
346
|
+
const char *res;
|
347
|
+
ms->capture[l].len = s - ms->capture[l].init; /* close capture */
|
348
|
+
if ((res = match(ms, s, p)) == NULL) /* match failed? */
|
349
|
+
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
|
350
|
+
return res;
|
351
|
+
}
|
352
|
+
|
353
|
+
|
354
|
+
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
355
|
+
size_t len;
|
356
|
+
l = check_capture(ms, l);
|
357
|
+
len = ms->capture[l].len;
|
358
|
+
if ((size_t)(ms->src_end-s) >= len &&
|
359
|
+
memcmp(ms->capture[l].init, s, len) == 0)
|
360
|
+
return s+len;
|
361
|
+
else return NULL;
|
362
|
+
}
|
363
|
+
|
364
|
+
|
365
|
+
static const char *match (MatchState *ms, const char *s, const char *p) {
|
366
|
+
init: /* using goto's to optimize tail recursion */
|
367
|
+
switch (*p) {
|
368
|
+
case '(': { /* start capture */
|
369
|
+
if (*(p+1) == ')') /* position capture? */
|
370
|
+
return start_capture(ms, s, p+2, CAP_POSITION);
|
371
|
+
else
|
372
|
+
return start_capture(ms, s, p+1, CAP_UNFINISHED);
|
373
|
+
}
|
374
|
+
case ')': { /* end capture */
|
375
|
+
return end_capture(ms, s, p+1);
|
376
|
+
}
|
377
|
+
case L_ESC: {
|
378
|
+
switch (*(p+1)) {
|
379
|
+
case 'b': { /* balanced string? */
|
380
|
+
s = matchbalance(ms, s, p+2);
|
381
|
+
if (s == NULL) return NULL;
|
382
|
+
p+=4; goto init; /* else return match(ms, s, p+4); */
|
383
|
+
}
|
384
|
+
case 'f': { /* frontier? */
|
385
|
+
const char *ep; char previous;
|
386
|
+
p += 2;
|
387
|
+
if (*p != '[')
|
388
|
+
luaL_error(ms->L, "missing " LUA_QL("[") " after "
|
389
|
+
LUA_QL("%%f") " in pattern");
|
390
|
+
ep = classend(ms, p); /* points to what is next */
|
391
|
+
previous = (s == ms->src_init) ? '\0' : *(s-1);
|
392
|
+
if (matchbracketclass(uchar(previous), p, ep-1) ||
|
393
|
+
!matchbracketclass(uchar(*s), p, ep-1)) return NULL;
|
394
|
+
p=ep; goto init; /* else return match(ms, s, ep); */
|
395
|
+
}
|
396
|
+
default: {
|
397
|
+
if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
|
398
|
+
s = match_capture(ms, s, uchar(*(p+1)));
|
399
|
+
if (s == NULL) return NULL;
|
400
|
+
p+=2; goto init; /* else return match(ms, s, p+2) */
|
401
|
+
}
|
402
|
+
goto dflt; /* case default */
|
403
|
+
}
|
404
|
+
}
|
405
|
+
}
|
406
|
+
case '\0': { /* end of pattern */
|
407
|
+
return s; /* match succeeded */
|
408
|
+
}
|
409
|
+
case '$': {
|
410
|
+
if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
|
411
|
+
return (s == ms->src_end) ? s : NULL; /* check end of string */
|
412
|
+
else goto dflt;
|
413
|
+
}
|
414
|
+
default: dflt: { /* it is a pattern item */
|
415
|
+
const char *ep = classend(ms, p); /* points to what is next */
|
416
|
+
int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
|
417
|
+
switch (*ep) {
|
418
|
+
case '?': { /* optional */
|
419
|
+
const char *res;
|
420
|
+
if (m && ((res=match(ms, s+1, ep+1)) != NULL))
|
421
|
+
return res;
|
422
|
+
p=ep+1; goto init; /* else return match(ms, s, ep+1); */
|
423
|
+
}
|
424
|
+
case '*': { /* 0 or more repetitions */
|
425
|
+
return max_expand(ms, s, p, ep);
|
426
|
+
}
|
427
|
+
case '+': { /* 1 or more repetitions */
|
428
|
+
return (m ? max_expand(ms, s+1, p, ep) : NULL);
|
429
|
+
}
|
430
|
+
case '-': { /* 0 or more repetitions (minimum) */
|
431
|
+
return min_expand(ms, s, p, ep);
|
432
|
+
}
|
433
|
+
default: {
|
434
|
+
if (!m) return NULL;
|
435
|
+
s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
|
436
|
+
}
|
437
|
+
}
|
438
|
+
}
|
439
|
+
}
|
440
|
+
}
|
441
|
+
|
442
|
+
|
443
|
+
|
444
|
+
static const char *lmemfind (const char *s1, size_t l1,
|
445
|
+
const char *s2, size_t l2) {
|
446
|
+
if (l2 == 0) return s1; /* empty strings are everywhere */
|
447
|
+
else if (l2 > l1) return NULL; /* avoids a negative `l1' */
|
448
|
+
else {
|
449
|
+
const char *init; /* to search for a `*s2' inside `s1' */
|
450
|
+
l2--; /* 1st char will be checked by `memchr' */
|
451
|
+
l1 = l1-l2; /* `s2' cannot be found after that */
|
452
|
+
while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
|
453
|
+
init++; /* 1st char is already checked */
|
454
|
+
if (memcmp(init, s2+1, l2) == 0)
|
455
|
+
return init-1;
|
456
|
+
else { /* correct `l1' and `s1' to try again */
|
457
|
+
l1 -= init-s1;
|
458
|
+
s1 = init;
|
459
|
+
}
|
460
|
+
}
|
461
|
+
return NULL; /* not found */
|
462
|
+
}
|
463
|
+
}
|
464
|
+
|
465
|
+
|
466
|
+
static void push_onecapture (MatchState *ms, int i, const char *s,
|
467
|
+
const char *e) {
|
468
|
+
if (i >= ms->level) {
|
469
|
+
if (i == 0) /* ms->level == 0, too */
|
470
|
+
lua_pushlstring(ms->L, s, e - s); /* add whole match */
|
471
|
+
else
|
472
|
+
luaL_error(ms->L, "invalid capture index");
|
473
|
+
}
|
474
|
+
else {
|
475
|
+
ptrdiff_t l = ms->capture[i].len;
|
476
|
+
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
|
477
|
+
if (l == CAP_POSITION)
|
478
|
+
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
|
479
|
+
else
|
480
|
+
lua_pushlstring(ms->L, ms->capture[i].init, l);
|
481
|
+
}
|
482
|
+
}
|
483
|
+
|
484
|
+
|
485
|
+
static int push_captures (MatchState *ms, const char *s, const char *e) {
|
486
|
+
int i;
|
487
|
+
int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
|
488
|
+
luaL_checkstack(ms->L, nlevels, "too many captures");
|
489
|
+
for (i = 0; i < nlevels; i++)
|
490
|
+
push_onecapture(ms, i, s, e);
|
491
|
+
return nlevels; /* number of strings pushed */
|
492
|
+
}
|
493
|
+
|
494
|
+
|
495
|
+
static int str_find_aux (lua_State *L, int find) {
|
496
|
+
size_t l1, l2;
|
497
|
+
const char *s = luaL_checklstring(L, 1, &l1);
|
498
|
+
const char *p = luaL_checklstring(L, 2, &l2);
|
499
|
+
ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
|
500
|
+
if (init < 0) init = 0;
|
501
|
+
else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
|
502
|
+
if (find && (lua_toboolean(L, 4) || /* explicit request? */
|
503
|
+
strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
|
504
|
+
/* do a plain search */
|
505
|
+
const char *s2 = lmemfind(s+init, l1-init, p, l2);
|
506
|
+
if (s2) {
|
507
|
+
lua_pushinteger(L, s2-s+1);
|
508
|
+
lua_pushinteger(L, s2-s+l2);
|
509
|
+
return 2;
|
510
|
+
}
|
511
|
+
}
|
512
|
+
else {
|
513
|
+
MatchState ms;
|
514
|
+
int anchor = (*p == '^') ? (p++, 1) : 0;
|
515
|
+
const char *s1=s+init;
|
516
|
+
ms.L = L;
|
517
|
+
ms.src_init = s;
|
518
|
+
ms.src_end = s+l1;
|
519
|
+
do {
|
520
|
+
const char *res;
|
521
|
+
ms.level = 0;
|
522
|
+
if ((res=match(&ms, s1, p)) != NULL) {
|
523
|
+
if (find) {
|
524
|
+
lua_pushinteger(L, s1-s+1); /* start */
|
525
|
+
lua_pushinteger(L, res-s); /* end */
|
526
|
+
return push_captures(&ms, NULL, 0) + 2;
|
527
|
+
}
|
528
|
+
else
|
529
|
+
return push_captures(&ms, s1, res);
|
530
|
+
}
|
531
|
+
} while (s1++ < ms.src_end && !anchor);
|
532
|
+
}
|
533
|
+
lua_pushnil(L); /* not found */
|
534
|
+
return 1;
|
535
|
+
}
|
536
|
+
|
537
|
+
|
538
|
+
static int str_find (lua_State *L) {
|
539
|
+
return str_find_aux(L, 1);
|
540
|
+
}
|
541
|
+
|
542
|
+
|
543
|
+
static int str_match (lua_State *L) {
|
544
|
+
return str_find_aux(L, 0);
|
545
|
+
}
|
546
|
+
|
547
|
+
|
548
|
+
static int gmatch_aux (lua_State *L) {
|
549
|
+
MatchState ms;
|
550
|
+
size_t ls;
|
551
|
+
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
|
552
|
+
const char *p = lua_tostring(L, lua_upvalueindex(2));
|
553
|
+
const char *src;
|
554
|
+
ms.L = L;
|
555
|
+
ms.src_init = s;
|
556
|
+
ms.src_end = s+ls;
|
557
|
+
for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
|
558
|
+
src <= ms.src_end;
|
559
|
+
src++) {
|
560
|
+
const char *e;
|
561
|
+
ms.level = 0;
|
562
|
+
if ((e = match(&ms, src, p)) != NULL) {
|
563
|
+
lua_Integer newstart = e-s;
|
564
|
+
if (e == src) newstart++; /* empty match? go at least one position */
|
565
|
+
lua_pushinteger(L, newstart);
|
566
|
+
lua_replace(L, lua_upvalueindex(3));
|
567
|
+
return push_captures(&ms, src, e);
|
568
|
+
}
|
569
|
+
}
|
570
|
+
return 0; /* not found */
|
571
|
+
}
|
572
|
+
|
573
|
+
|
574
|
+
static int gmatch (lua_State *L) {
|
575
|
+
luaL_checkstring(L, 1);
|
576
|
+
luaL_checkstring(L, 2);
|
577
|
+
lua_settop(L, 2);
|
578
|
+
lua_pushinteger(L, 0);
|
579
|
+
lua_pushcclosure(L, gmatch_aux, 3);
|
580
|
+
return 1;
|
581
|
+
}
|
582
|
+
|
583
|
+
|
584
|
+
static int gfind_nodef (lua_State *L) {
|
585
|
+
return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
|
586
|
+
LUA_QL("string.gmatch"));
|
587
|
+
}
|
588
|
+
|
589
|
+
|
590
|
+
static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
|
591
|
+
const char *e) {
|
592
|
+
size_t l, i;
|
593
|
+
const char *news = lua_tolstring(ms->L, 3, &l);
|
594
|
+
for (i = 0; i < l; i++) {
|
595
|
+
if (news[i] != L_ESC)
|
596
|
+
luaL_addchar(b, news[i]);
|
597
|
+
else {
|
598
|
+
i++; /* skip ESC */
|
599
|
+
if (!isdigit(uchar(news[i])))
|
600
|
+
luaL_addchar(b, news[i]);
|
601
|
+
else if (news[i] == '0')
|
602
|
+
luaL_addlstring(b, s, e - s);
|
603
|
+
else {
|
604
|
+
push_onecapture(ms, news[i] - '1', s, e);
|
605
|
+
luaL_addvalue(b); /* add capture to accumulated result */
|
606
|
+
}
|
607
|
+
}
|
608
|
+
}
|
609
|
+
}
|
610
|
+
|
611
|
+
|
612
|
+
static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
|
613
|
+
const char *e) {
|
614
|
+
lua_State *L = ms->L;
|
615
|
+
switch (lua_type(L, 3)) {
|
616
|
+
case LUA_TNUMBER:
|
617
|
+
case LUA_TSTRING: {
|
618
|
+
add_s(ms, b, s, e);
|
619
|
+
return;
|
620
|
+
}
|
621
|
+
case LUA_TFUNCTION: {
|
622
|
+
int n;
|
623
|
+
lua_pushvalue(L, 3);
|
624
|
+
n = push_captures(ms, s, e);
|
625
|
+
lua_call(L, n, 1);
|
626
|
+
break;
|
627
|
+
}
|
628
|
+
case LUA_TTABLE: {
|
629
|
+
push_onecapture(ms, 0, s, e);
|
630
|
+
lua_gettable(L, 3);
|
631
|
+
break;
|
632
|
+
}
|
633
|
+
}
|
634
|
+
if (!lua_toboolean(L, -1)) { /* nil or false? */
|
635
|
+
lua_pop(L, 1);
|
636
|
+
lua_pushlstring(L, s, e - s); /* keep original text */
|
637
|
+
}
|
638
|
+
else if (!lua_isstring(L, -1))
|
639
|
+
luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
|
640
|
+
luaL_addvalue(b); /* add result to accumulator */
|
641
|
+
}
|
642
|
+
|
643
|
+
|
644
|
+
static int str_gsub (lua_State *L) {
|
645
|
+
size_t srcl;
|
646
|
+
const char *src = luaL_checklstring(L, 1, &srcl);
|
647
|
+
const char *p = luaL_checkstring(L, 2);
|
648
|
+
int tr = lua_type(L, 3);
|
649
|
+
int max_s = luaL_optint(L, 4, srcl+1);
|
650
|
+
int anchor = (*p == '^') ? (p++, 1) : 0;
|
651
|
+
int n = 0;
|
652
|
+
MatchState ms;
|
653
|
+
luaL_Buffer b;
|
654
|
+
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
|
655
|
+
tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
|
656
|
+
"string/function/table expected");
|
657
|
+
luaL_buffinit(L, &b);
|
658
|
+
ms.L = L;
|
659
|
+
ms.src_init = src;
|
660
|
+
ms.src_end = src+srcl;
|
661
|
+
while (n < max_s) {
|
662
|
+
const char *e;
|
663
|
+
ms.level = 0;
|
664
|
+
e = match(&ms, src, p);
|
665
|
+
if (e) {
|
666
|
+
n++;
|
667
|
+
add_value(&ms, &b, src, e);
|
668
|
+
}
|
669
|
+
if (e && e>src) /* non empty match? */
|
670
|
+
src = e; /* skip it */
|
671
|
+
else if (src < ms.src_end)
|
672
|
+
luaL_addchar(&b, *src++);
|
673
|
+
else break;
|
674
|
+
if (anchor) break;
|
675
|
+
}
|
676
|
+
luaL_addlstring(&b, src, ms.src_end-src);
|
677
|
+
luaL_pushresult(&b);
|
678
|
+
lua_pushinteger(L, n); /* number of substitutions */
|
679
|
+
return 2;
|
680
|
+
}
|
681
|
+
|
682
|
+
/* }====================================================== */
|
683
|
+
|
684
|
+
|
685
|
+
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
|
686
|
+
#define MAX_ITEM 512
|
687
|
+
/* valid flags in a format specification */
|
688
|
+
#define FLAGS "-+ #0"
|
689
|
+
/*
|
690
|
+
** maximum size of each format specification (such as '%-099.99d')
|
691
|
+
** (+10 accounts for %99.99x plus margin of error)
|
692
|
+
*/
|
693
|
+
#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
|
694
|
+
|
695
|
+
|
696
|
+
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
|
697
|
+
size_t l;
|
698
|
+
const char *s = luaL_checklstring(L, arg, &l);
|
699
|
+
luaL_addchar(b, '"');
|
700
|
+
while (l--) {
|
701
|
+
switch (*s) {
|
702
|
+
case '"': case '\\': case '\n': {
|
703
|
+
luaL_addchar(b, '\\');
|
704
|
+
luaL_addchar(b, *s);
|
705
|
+
break;
|
706
|
+
}
|
707
|
+
case '\r': {
|
708
|
+
luaL_addlstring(b, "\\r", 2);
|
709
|
+
break;
|
710
|
+
}
|
711
|
+
case '\0': {
|
712
|
+
luaL_addlstring(b, "\\000", 4);
|
713
|
+
break;
|
714
|
+
}
|
715
|
+
default: {
|
716
|
+
luaL_addchar(b, *s);
|
717
|
+
break;
|
718
|
+
}
|
719
|
+
}
|
720
|
+
s++;
|
721
|
+
}
|
722
|
+
luaL_addchar(b, '"');
|
723
|
+
}
|
724
|
+
|
725
|
+
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
|
726
|
+
const char *p = strfrmt;
|
727
|
+
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
|
728
|
+
if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
|
729
|
+
luaL_error(L, "invalid format (repeated flags)");
|
730
|
+
if (isdigit(uchar(*p))) p++; /* skip width */
|
731
|
+
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
732
|
+
if (*p == '.') {
|
733
|
+
p++;
|
734
|
+
if (isdigit(uchar(*p))) p++; /* skip precision */
|
735
|
+
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
736
|
+
}
|
737
|
+
if (isdigit(uchar(*p)))
|
738
|
+
luaL_error(L, "invalid format (width or precision too long)");
|
739
|
+
*(form++) = '%';
|
740
|
+
strncpy(form, strfrmt, p - strfrmt + 1);
|
741
|
+
form += p - strfrmt + 1;
|
742
|
+
*form = '\0';
|
743
|
+
return p;
|
744
|
+
}
|
745
|
+
|
746
|
+
|
747
|
+
static void addintlen (char *form) {
|
748
|
+
size_t l = strlen(form);
|
749
|
+
char spec = form[l - 1];
|
750
|
+
strcpy(form + l - 1, LUA_INTFRMLEN);
|
751
|
+
form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
|
752
|
+
form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
|
753
|
+
}
|
754
|
+
|
755
|
+
|
756
|
+
static int str_format (lua_State *L) {
|
757
|
+
int top = lua_gettop(L);
|
758
|
+
int arg = 1;
|
759
|
+
size_t sfl;
|
760
|
+
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
|
761
|
+
const char *strfrmt_end = strfrmt+sfl;
|
762
|
+
luaL_Buffer b;
|
763
|
+
luaL_buffinit(L, &b);
|
764
|
+
while (strfrmt < strfrmt_end) {
|
765
|
+
if (*strfrmt != L_ESC)
|
766
|
+
luaL_addchar(&b, *strfrmt++);
|
767
|
+
else if (*++strfrmt == L_ESC)
|
768
|
+
luaL_addchar(&b, *strfrmt++); /* %% */
|
769
|
+
else { /* format item */
|
770
|
+
char form[MAX_FORMAT]; /* to store the format (`%...') */
|
771
|
+
char buff[MAX_ITEM]; /* to store the formatted item */
|
772
|
+
if (++arg > top)
|
773
|
+
luaL_argerror(L, arg, "no value");
|
774
|
+
strfrmt = scanformat(L, strfrmt, form);
|
775
|
+
switch (*strfrmt++) {
|
776
|
+
case 'c': {
|
777
|
+
sprintf(buff, form, (int)luaL_checknumber(L, arg));
|
778
|
+
break;
|
779
|
+
}
|
780
|
+
case 'd': case 'i': {
|
781
|
+
addintlen(form);
|
782
|
+
sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
|
783
|
+
break;
|
784
|
+
}
|
785
|
+
case 'o': case 'u': case 'x': case 'X': {
|
786
|
+
addintlen(form);
|
787
|
+
sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
|
788
|
+
break;
|
789
|
+
}
|
790
|
+
case 'e': case 'E': case 'f':
|
791
|
+
case 'g': case 'G': {
|
792
|
+
sprintf(buff, form, (double)luaL_checknumber(L, arg));
|
793
|
+
break;
|
794
|
+
}
|
795
|
+
case 'q': {
|
796
|
+
addquoted(L, &b, arg);
|
797
|
+
continue; /* skip the 'addsize' at the end */
|
798
|
+
}
|
799
|
+
case 's': {
|
800
|
+
size_t l;
|
801
|
+
const char *s = luaL_checklstring(L, arg, &l);
|
802
|
+
if (!strchr(form, '.') && l >= 100) {
|
803
|
+
/* no precision and string is too long to be formatted;
|
804
|
+
keep original string */
|
805
|
+
lua_pushvalue(L, arg);
|
806
|
+
luaL_addvalue(&b);
|
807
|
+
continue; /* skip the `addsize' at the end */
|
808
|
+
}
|
809
|
+
else {
|
810
|
+
sprintf(buff, form, s);
|
811
|
+
break;
|
812
|
+
}
|
813
|
+
}
|
814
|
+
default: { /* also treat cases `pnLlh' */
|
815
|
+
return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
|
816
|
+
LUA_QL("format"), *(strfrmt - 1));
|
817
|
+
}
|
818
|
+
}
|
819
|
+
luaL_addlstring(&b, buff, strlen(buff));
|
820
|
+
}
|
821
|
+
}
|
822
|
+
luaL_pushresult(&b);
|
823
|
+
return 1;
|
824
|
+
}
|
825
|
+
|
826
|
+
|
827
|
+
static const luaL_Reg strlib[] = {
|
828
|
+
{"byte", str_byte},
|
829
|
+
{"char", str_char},
|
830
|
+
{"dump", str_dump},
|
831
|
+
{"find", str_find},
|
832
|
+
{"format", str_format},
|
833
|
+
{"gfind", gfind_nodef},
|
834
|
+
{"gmatch", gmatch},
|
835
|
+
{"gsub", str_gsub},
|
836
|
+
{"len", str_len},
|
837
|
+
{"lower", str_lower},
|
838
|
+
{"match", str_match},
|
839
|
+
{"rep", str_rep},
|
840
|
+
{"reverse", str_reverse},
|
841
|
+
{"sub", str_sub},
|
842
|
+
{"upper", str_upper},
|
843
|
+
{NULL, NULL}
|
844
|
+
};
|
845
|
+
|
846
|
+
|
847
|
+
static void createmetatable (lua_State *L) {
|
848
|
+
lua_createtable(L, 0, 1); /* create metatable for strings */
|
849
|
+
lua_pushliteral(L, ""); /* dummy string */
|
850
|
+
lua_pushvalue(L, -2);
|
851
|
+
lua_setmetatable(L, -2); /* set string metatable */
|
852
|
+
lua_pop(L, 1); /* pop dummy string */
|
853
|
+
lua_pushvalue(L, -2); /* string library... */
|
854
|
+
lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
|
855
|
+
lua_pop(L, 1); /* pop metatable */
|
856
|
+
}
|
857
|
+
|
858
|
+
|
859
|
+
/*
|
860
|
+
** Open string library
|
861
|
+
*/
|
862
|
+
LUALIB_API int luaopen_string (lua_State *L) {
|
863
|
+
luaL_register(L, LUA_STRLIBNAME, strlib);
|
864
|
+
#if defined(LUA_COMPAT_GFIND)
|
865
|
+
lua_getfield(L, -1, "gmatch");
|
866
|
+
lua_setfield(L, -2, "gfind");
|
867
|
+
#endif
|
868
|
+
createmetatable(L);
|
869
|
+
return 1;
|
870
|
+
}
|
871
|
+
|