1*0a6a1f1dSLionel Sambuc /* $NetBSD: lstrlib.c,v 1.9 2015/10/08 13:40:16 mbalmer Exp $ */
211be35a1SLionel Sambuc
311be35a1SLionel Sambuc /*
4*0a6a1f1dSLionel Sambuc ** Id: lstrlib.c,v 1.229 2015/05/20 17:39:23 roberto Exp
511be35a1SLionel Sambuc ** Standard library for string operations and pattern-matching
611be35a1SLionel Sambuc ** See Copyright Notice in lua.h
711be35a1SLionel Sambuc */
811be35a1SLionel Sambuc
9*0a6a1f1dSLionel Sambuc #define lstrlib_c
10*0a6a1f1dSLionel Sambuc #define LUA_LIB
1111be35a1SLionel Sambuc
12*0a6a1f1dSLionel Sambuc #include "lprefix.h"
13*0a6a1f1dSLionel Sambuc
14*0a6a1f1dSLionel Sambuc
15*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1611be35a1SLionel Sambuc #include <ctype.h>
17*0a6a1f1dSLionel Sambuc #include <float.h>
18*0a6a1f1dSLionel Sambuc #include <limits.h>
1911be35a1SLionel Sambuc #include <stddef.h>
2011be35a1SLionel Sambuc #include <stdio.h>
2111be35a1SLionel Sambuc #include <stdlib.h>
2211be35a1SLionel Sambuc #include <string.h>
23*0a6a1f1dSLionel Sambuc #endif
2411be35a1SLionel Sambuc
2511be35a1SLionel Sambuc #include "lua.h"
2611be35a1SLionel Sambuc
2711be35a1SLionel Sambuc #include "lauxlib.h"
2811be35a1SLionel Sambuc #include "lualib.h"
2911be35a1SLionel Sambuc
3011be35a1SLionel Sambuc
31*0a6a1f1dSLionel Sambuc /*
32*0a6a1f1dSLionel Sambuc ** maximum number of captures that a pattern can do during
33*0a6a1f1dSLionel Sambuc ** pattern-matching. This limit is arbitrary.
34*0a6a1f1dSLionel Sambuc */
35*0a6a1f1dSLionel Sambuc #if !defined(LUA_MAXCAPTURES)
36*0a6a1f1dSLionel Sambuc #define LUA_MAXCAPTURES 32
37*0a6a1f1dSLionel Sambuc #endif
38*0a6a1f1dSLionel Sambuc
39*0a6a1f1dSLionel Sambuc
40*0a6a1f1dSLionel Sambuc /* macro to 'unsign' a character */
4111be35a1SLionel Sambuc #define uchar(c) ((unsigned char)(c))
4211be35a1SLionel Sambuc
4311be35a1SLionel Sambuc
44*0a6a1f1dSLionel Sambuc /*
45*0a6a1f1dSLionel Sambuc ** Some sizes are better limited to fit in 'int', but must also fit in
46*0a6a1f1dSLionel Sambuc ** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
47*0a6a1f1dSLionel Sambuc */
48*0a6a1f1dSLionel Sambuc #define MAXSIZE \
49*0a6a1f1dSLionel Sambuc (sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX))
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel Sambuc
52*0a6a1f1dSLionel Sambuc
5311be35a1SLionel Sambuc
str_len(lua_State * L)5411be35a1SLionel Sambuc static int str_len (lua_State *L) {
5511be35a1SLionel Sambuc size_t l;
5611be35a1SLionel Sambuc luaL_checklstring(L, 1, &l);
57*0a6a1f1dSLionel Sambuc lua_pushinteger(L, (lua_Integer)l);
5811be35a1SLionel Sambuc return 1;
5911be35a1SLionel Sambuc }
6011be35a1SLionel Sambuc
6111be35a1SLionel Sambuc
62*0a6a1f1dSLionel Sambuc /* translate a relative string position: negative means back from end */
posrelat(lua_Integer pos,size_t len)63*0a6a1f1dSLionel Sambuc static lua_Integer posrelat (lua_Integer pos, size_t len) {
64*0a6a1f1dSLionel Sambuc if (pos >= 0) return pos;
65*0a6a1f1dSLionel Sambuc else if (0u - (size_t)pos > len) return 0;
66*0a6a1f1dSLionel Sambuc else return (lua_Integer)len + pos + 1;
6711be35a1SLionel Sambuc }
6811be35a1SLionel Sambuc
6911be35a1SLionel Sambuc
str_sub(lua_State * L)7011be35a1SLionel Sambuc static int str_sub (lua_State *L) {
7111be35a1SLionel Sambuc size_t l;
7211be35a1SLionel Sambuc const char *s = luaL_checklstring(L, 1, &l);
73*0a6a1f1dSLionel Sambuc lua_Integer start = posrelat(luaL_checkinteger(L, 2), l);
74*0a6a1f1dSLionel Sambuc lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l);
7511be35a1SLionel Sambuc if (start < 1) start = 1;
76*0a6a1f1dSLionel Sambuc if (end > (lua_Integer)l) end = l;
7711be35a1SLionel Sambuc if (start <= end)
78*0a6a1f1dSLionel Sambuc lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
7911be35a1SLionel Sambuc else lua_pushliteral(L, "");
8011be35a1SLionel Sambuc return 1;
8111be35a1SLionel Sambuc }
8211be35a1SLionel Sambuc
8311be35a1SLionel Sambuc
str_reverse(lua_State * L)8411be35a1SLionel Sambuc static int str_reverse (lua_State *L) {
85*0a6a1f1dSLionel Sambuc size_t l, i;
8611be35a1SLionel Sambuc luaL_Buffer b;
8711be35a1SLionel Sambuc const char *s = luaL_checklstring(L, 1, &l);
88*0a6a1f1dSLionel Sambuc char *p = luaL_buffinitsize(L, &b, l);
89*0a6a1f1dSLionel Sambuc for (i = 0; i < l; i++)
90*0a6a1f1dSLionel Sambuc p[i] = s[l - i - 1];
91*0a6a1f1dSLionel Sambuc luaL_pushresultsize(&b, l);
9211be35a1SLionel Sambuc return 1;
9311be35a1SLionel Sambuc }
9411be35a1SLionel Sambuc
9511be35a1SLionel Sambuc
str_lower(lua_State * L)9611be35a1SLionel Sambuc static int str_lower (lua_State *L) {
9711be35a1SLionel Sambuc size_t l;
9811be35a1SLionel Sambuc size_t i;
9911be35a1SLionel Sambuc luaL_Buffer b;
10011be35a1SLionel Sambuc const char *s = luaL_checklstring(L, 1, &l);
101*0a6a1f1dSLionel Sambuc char *p = luaL_buffinitsize(L, &b, l);
10211be35a1SLionel Sambuc for (i=0; i<l; i++)
103*0a6a1f1dSLionel Sambuc p[i] = tolower(uchar(s[i]));
104*0a6a1f1dSLionel Sambuc luaL_pushresultsize(&b, l);
10511be35a1SLionel Sambuc return 1;
10611be35a1SLionel Sambuc }
10711be35a1SLionel Sambuc
10811be35a1SLionel Sambuc
str_upper(lua_State * L)10911be35a1SLionel Sambuc static int str_upper (lua_State *L) {
11011be35a1SLionel Sambuc size_t l;
11111be35a1SLionel Sambuc size_t i;
11211be35a1SLionel Sambuc luaL_Buffer b;
11311be35a1SLionel Sambuc const char *s = luaL_checklstring(L, 1, &l);
114*0a6a1f1dSLionel Sambuc char *p = luaL_buffinitsize(L, &b, l);
11511be35a1SLionel Sambuc for (i=0; i<l; i++)
116*0a6a1f1dSLionel Sambuc p[i] = toupper(uchar(s[i]));
117*0a6a1f1dSLionel Sambuc luaL_pushresultsize(&b, l);
11811be35a1SLionel Sambuc return 1;
11911be35a1SLionel Sambuc }
12011be35a1SLionel Sambuc
121*0a6a1f1dSLionel Sambuc
str_rep(lua_State * L)12211be35a1SLionel Sambuc static int str_rep (lua_State *L) {
123*0a6a1f1dSLionel Sambuc size_t l, lsep;
12411be35a1SLionel Sambuc const char *s = luaL_checklstring(L, 1, &l);
125*0a6a1f1dSLionel Sambuc lua_Integer n = luaL_checkinteger(L, 2);
126*0a6a1f1dSLionel Sambuc const char *sep = luaL_optlstring(L, 3, "", &lsep);
127*0a6a1f1dSLionel Sambuc if (n <= 0) lua_pushliteral(L, "");
128*0a6a1f1dSLionel Sambuc else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */
129*0a6a1f1dSLionel Sambuc return luaL_error(L, "resulting string too large");
130*0a6a1f1dSLionel Sambuc else {
131*0a6a1f1dSLionel Sambuc size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
132*0a6a1f1dSLionel Sambuc luaL_Buffer b;
133*0a6a1f1dSLionel Sambuc char *p = luaL_buffinitsize(L, &b, totallen);
134*0a6a1f1dSLionel Sambuc while (n-- > 1) { /* first n-1 copies (followed by separator) */
135*0a6a1f1dSLionel Sambuc memcpy(p, s, l * sizeof(char)); p += l;
136*0a6a1f1dSLionel Sambuc if (lsep > 0) { /* empty 'memcpy' is not that cheap */
137*0a6a1f1dSLionel Sambuc memcpy(p, sep, lsep * sizeof(char));
138*0a6a1f1dSLionel Sambuc p += lsep;
139*0a6a1f1dSLionel Sambuc }
140*0a6a1f1dSLionel Sambuc }
141*0a6a1f1dSLionel Sambuc memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
142*0a6a1f1dSLionel Sambuc luaL_pushresultsize(&b, totallen);
143*0a6a1f1dSLionel Sambuc }
14411be35a1SLionel Sambuc return 1;
14511be35a1SLionel Sambuc }
14611be35a1SLionel Sambuc
14711be35a1SLionel Sambuc
str_byte(lua_State * L)14811be35a1SLionel Sambuc static int str_byte (lua_State *L) {
14911be35a1SLionel Sambuc size_t l;
15011be35a1SLionel Sambuc const char *s = luaL_checklstring(L, 1, &l);
151*0a6a1f1dSLionel Sambuc lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l);
152*0a6a1f1dSLionel Sambuc lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l);
15311be35a1SLionel Sambuc int n, i;
154*0a6a1f1dSLionel Sambuc if (posi < 1) posi = 1;
155*0a6a1f1dSLionel Sambuc if (pose > (lua_Integer)l) pose = l;
15611be35a1SLionel Sambuc if (posi > pose) return 0; /* empty interval; return no values */
157*0a6a1f1dSLionel Sambuc if (pose - posi >= INT_MAX) /* arithmetic overflow? */
158*0a6a1f1dSLionel Sambuc return luaL_error(L, "string slice too long");
159*0a6a1f1dSLionel Sambuc n = (int)(pose - posi) + 1;
16011be35a1SLionel Sambuc luaL_checkstack(L, n, "string slice too long");
16111be35a1SLionel Sambuc for (i=0; i<n; i++)
16211be35a1SLionel Sambuc lua_pushinteger(L, uchar(s[posi+i-1]));
16311be35a1SLionel Sambuc return n;
16411be35a1SLionel Sambuc }
16511be35a1SLionel Sambuc
16611be35a1SLionel Sambuc
str_char(lua_State * L)16711be35a1SLionel Sambuc static int str_char (lua_State *L) {
16811be35a1SLionel Sambuc int n = lua_gettop(L); /* number of arguments */
16911be35a1SLionel Sambuc int i;
17011be35a1SLionel Sambuc luaL_Buffer b;
171*0a6a1f1dSLionel Sambuc char *p = luaL_buffinitsize(L, &b, n);
17211be35a1SLionel Sambuc for (i=1; i<=n; i++) {
173*0a6a1f1dSLionel Sambuc lua_Integer c = luaL_checkinteger(L, i);
174*0a6a1f1dSLionel Sambuc luaL_argcheck(L, uchar(c) == c, i, "value out of range");
175*0a6a1f1dSLionel Sambuc p[i - 1] = uchar(c);
17611be35a1SLionel Sambuc }
177*0a6a1f1dSLionel Sambuc luaL_pushresultsize(&b, n);
17811be35a1SLionel Sambuc return 1;
17911be35a1SLionel Sambuc }
18011be35a1SLionel Sambuc
18111be35a1SLionel Sambuc
writer(lua_State * L,const void * b,size_t size,void * B)18211be35a1SLionel Sambuc static int writer (lua_State *L, const void *b, size_t size, void *B) {
18311be35a1SLionel Sambuc (void)L;
18411be35a1SLionel Sambuc luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
18511be35a1SLionel Sambuc return 0;
18611be35a1SLionel Sambuc }
18711be35a1SLionel Sambuc
18811be35a1SLionel Sambuc
str_dump(lua_State * L)18911be35a1SLionel Sambuc static int str_dump (lua_State *L) {
19011be35a1SLionel Sambuc luaL_Buffer b;
191*0a6a1f1dSLionel Sambuc int strip = lua_toboolean(L, 2);
19211be35a1SLionel Sambuc luaL_checktype(L, 1, LUA_TFUNCTION);
19311be35a1SLionel Sambuc lua_settop(L, 1);
19411be35a1SLionel Sambuc luaL_buffinit(L,&b);
195*0a6a1f1dSLionel Sambuc if (lua_dump(L, writer, &b, strip) != 0)
196*0a6a1f1dSLionel Sambuc return luaL_error(L, "unable to dump given function");
19711be35a1SLionel Sambuc luaL_pushresult(&b);
19811be35a1SLionel Sambuc return 1;
19911be35a1SLionel Sambuc }
20011be35a1SLionel Sambuc
20111be35a1SLionel Sambuc
20211be35a1SLionel Sambuc
20311be35a1SLionel Sambuc /*
20411be35a1SLionel Sambuc ** {======================================================
20511be35a1SLionel Sambuc ** PATTERN MATCHING
20611be35a1SLionel Sambuc ** =======================================================
20711be35a1SLionel Sambuc */
20811be35a1SLionel Sambuc
20911be35a1SLionel Sambuc
21011be35a1SLionel Sambuc #define CAP_UNFINISHED (-1)
21111be35a1SLionel Sambuc #define CAP_POSITION (-2)
21211be35a1SLionel Sambuc
213*0a6a1f1dSLionel Sambuc
21411be35a1SLionel Sambuc typedef struct MatchState {
215*0a6a1f1dSLionel Sambuc int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
21611be35a1SLionel Sambuc const char *src_init; /* init of source string */
217*0a6a1f1dSLionel Sambuc const char *src_end; /* end ('\0') of source string */
218*0a6a1f1dSLionel Sambuc const char *p_end; /* end ('\0') of pattern */
21911be35a1SLionel Sambuc lua_State *L;
22011be35a1SLionel Sambuc int level; /* total number of captures (finished or unfinished) */
22111be35a1SLionel Sambuc struct {
22211be35a1SLionel Sambuc const char *init;
22311be35a1SLionel Sambuc ptrdiff_t len;
22411be35a1SLionel Sambuc } capture[LUA_MAXCAPTURES];
22511be35a1SLionel Sambuc } MatchState;
22611be35a1SLionel Sambuc
22711be35a1SLionel Sambuc
228*0a6a1f1dSLionel Sambuc /* recursive function */
229*0a6a1f1dSLionel Sambuc static const char *match (MatchState *ms, const char *s, const char *p);
230*0a6a1f1dSLionel Sambuc
231*0a6a1f1dSLionel Sambuc
232*0a6a1f1dSLionel Sambuc /* maximum recursion depth for 'match' */
233*0a6a1f1dSLionel Sambuc #if !defined(MAXCCALLS)
234*0a6a1f1dSLionel Sambuc #define MAXCCALLS 200
235*0a6a1f1dSLionel Sambuc #endif
236*0a6a1f1dSLionel Sambuc
237*0a6a1f1dSLionel Sambuc
23811be35a1SLionel Sambuc #define L_ESC '%'
23911be35a1SLionel Sambuc #define SPECIALS "^$*+?.([%-"
24011be35a1SLionel Sambuc
24111be35a1SLionel Sambuc
check_capture(MatchState * ms,int l)24211be35a1SLionel Sambuc static int check_capture (MatchState *ms, int l) {
24311be35a1SLionel Sambuc l -= '1';
24411be35a1SLionel Sambuc if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
245*0a6a1f1dSLionel Sambuc return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
24611be35a1SLionel Sambuc return l;
24711be35a1SLionel Sambuc }
24811be35a1SLionel Sambuc
24911be35a1SLionel Sambuc
capture_to_close(MatchState * ms)25011be35a1SLionel Sambuc static int capture_to_close (MatchState *ms) {
25111be35a1SLionel Sambuc int level = ms->level;
25211be35a1SLionel Sambuc for (level--; level>=0; level--)
25311be35a1SLionel Sambuc if (ms->capture[level].len == CAP_UNFINISHED) return level;
25411be35a1SLionel Sambuc return luaL_error(ms->L, "invalid pattern capture");
25511be35a1SLionel Sambuc }
25611be35a1SLionel Sambuc
25711be35a1SLionel Sambuc
classend(MatchState * ms,const char * p)25811be35a1SLionel Sambuc static const char *classend (MatchState *ms, const char *p) {
25911be35a1SLionel Sambuc switch (*p++) {
26011be35a1SLionel Sambuc case L_ESC: {
261*0a6a1f1dSLionel Sambuc if (p == ms->p_end)
262*0a6a1f1dSLionel Sambuc luaL_error(ms->L, "malformed pattern (ends with '%%')");
26311be35a1SLionel Sambuc return p+1;
26411be35a1SLionel Sambuc }
26511be35a1SLionel Sambuc case '[': {
26611be35a1SLionel Sambuc if (*p == '^') p++;
267*0a6a1f1dSLionel Sambuc do { /* look for a ']' */
268*0a6a1f1dSLionel Sambuc if (p == ms->p_end)
269*0a6a1f1dSLionel Sambuc luaL_error(ms->L, "malformed pattern (missing ']')");
270*0a6a1f1dSLionel Sambuc if (*(p++) == L_ESC && p < ms->p_end)
271*0a6a1f1dSLionel Sambuc p++; /* skip escapes (e.g. '%]') */
27211be35a1SLionel Sambuc } while (*p != ']');
27311be35a1SLionel Sambuc return p+1;
27411be35a1SLionel Sambuc }
27511be35a1SLionel Sambuc default: {
27611be35a1SLionel Sambuc return p;
27711be35a1SLionel Sambuc }
27811be35a1SLionel Sambuc }
27911be35a1SLionel Sambuc }
28011be35a1SLionel Sambuc
28111be35a1SLionel Sambuc
match_class(int c,int cl)28211be35a1SLionel Sambuc static int match_class (int c, int cl) {
28311be35a1SLionel Sambuc int res;
28411be35a1SLionel Sambuc switch (tolower(cl)) {
28511be35a1SLionel Sambuc case 'a' : res = isalpha(c); break;
28611be35a1SLionel Sambuc case 'c' : res = iscntrl(c); break;
28711be35a1SLionel Sambuc case 'd' : res = isdigit(c); break;
288*0a6a1f1dSLionel Sambuc case 'g' : res = isgraph(c); break;
28911be35a1SLionel Sambuc case 'l' : res = islower(c); break;
29011be35a1SLionel Sambuc case 'p' : res = ispunct(c); break;
29111be35a1SLionel Sambuc case 's' : res = isspace(c); break;
29211be35a1SLionel Sambuc case 'u' : res = isupper(c); break;
29311be35a1SLionel Sambuc case 'w' : res = isalnum(c); break;
29411be35a1SLionel Sambuc case 'x' : res = isxdigit(c); break;
295*0a6a1f1dSLionel Sambuc case 'z' : res = (c == 0); break; /* deprecated option */
29611be35a1SLionel Sambuc default: return (cl == c);
29711be35a1SLionel Sambuc }
29811be35a1SLionel Sambuc return (islower(cl) ? res : !res);
29911be35a1SLionel Sambuc }
30011be35a1SLionel Sambuc
30111be35a1SLionel Sambuc
matchbracketclass(int c,const char * p,const char * ec)30211be35a1SLionel Sambuc static int matchbracketclass (int c, const char *p, const char *ec) {
30311be35a1SLionel Sambuc int sig = 1;
30411be35a1SLionel Sambuc if (*(p+1) == '^') {
30511be35a1SLionel Sambuc sig = 0;
306*0a6a1f1dSLionel Sambuc p++; /* skip the '^' */
30711be35a1SLionel Sambuc }
30811be35a1SLionel Sambuc while (++p < ec) {
30911be35a1SLionel Sambuc if (*p == L_ESC) {
31011be35a1SLionel Sambuc p++;
31111be35a1SLionel Sambuc if (match_class(c, uchar(*p)))
31211be35a1SLionel Sambuc return sig;
31311be35a1SLionel Sambuc }
31411be35a1SLionel Sambuc else if ((*(p+1) == '-') && (p+2 < ec)) {
31511be35a1SLionel Sambuc p+=2;
31611be35a1SLionel Sambuc if (uchar(*(p-2)) <= c && c <= uchar(*p))
31711be35a1SLionel Sambuc return sig;
31811be35a1SLionel Sambuc }
31911be35a1SLionel Sambuc else if (uchar(*p) == c) return sig;
32011be35a1SLionel Sambuc }
32111be35a1SLionel Sambuc return !sig;
32211be35a1SLionel Sambuc }
32311be35a1SLionel Sambuc
32411be35a1SLionel Sambuc
singlematch(MatchState * ms,const char * s,const char * p,const char * ep)325*0a6a1f1dSLionel Sambuc static int singlematch (MatchState *ms, const char *s, const char *p,
326*0a6a1f1dSLionel Sambuc const char *ep) {
327*0a6a1f1dSLionel Sambuc if (s >= ms->src_end)
328*0a6a1f1dSLionel Sambuc return 0;
329*0a6a1f1dSLionel Sambuc else {
330*0a6a1f1dSLionel Sambuc int c = uchar(*s);
33111be35a1SLionel Sambuc switch (*p) {
33211be35a1SLionel Sambuc case '.': return 1; /* matches any char */
33311be35a1SLionel Sambuc case L_ESC: return match_class(c, uchar(*(p+1)));
33411be35a1SLionel Sambuc case '[': return matchbracketclass(c, p, ep-1);
33511be35a1SLionel Sambuc default: return (uchar(*p) == c);
33611be35a1SLionel Sambuc }
33711be35a1SLionel Sambuc }
338*0a6a1f1dSLionel Sambuc }
33911be35a1SLionel Sambuc
34011be35a1SLionel Sambuc
matchbalance(MatchState * ms,const char * s,const char * p)34111be35a1SLionel Sambuc static const char *matchbalance (MatchState *ms, const char *s,
34211be35a1SLionel Sambuc const char *p) {
343*0a6a1f1dSLionel Sambuc if (p >= ms->p_end - 1)
344*0a6a1f1dSLionel Sambuc luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
34511be35a1SLionel Sambuc if (*s != *p) return NULL;
34611be35a1SLionel Sambuc else {
34711be35a1SLionel Sambuc int b = *p;
34811be35a1SLionel Sambuc int e = *(p+1);
34911be35a1SLionel Sambuc int cont = 1;
35011be35a1SLionel Sambuc while (++s < ms->src_end) {
35111be35a1SLionel Sambuc if (*s == e) {
35211be35a1SLionel Sambuc if (--cont == 0) return s+1;
35311be35a1SLionel Sambuc }
35411be35a1SLionel Sambuc else if (*s == b) cont++;
35511be35a1SLionel Sambuc }
35611be35a1SLionel Sambuc }
35711be35a1SLionel Sambuc return NULL; /* string ends out of balance */
35811be35a1SLionel Sambuc }
35911be35a1SLionel Sambuc
36011be35a1SLionel Sambuc
max_expand(MatchState * ms,const char * s,const char * p,const char * ep)36111be35a1SLionel Sambuc static const char *max_expand (MatchState *ms, const char *s,
36211be35a1SLionel Sambuc const char *p, const char *ep) {
36311be35a1SLionel Sambuc ptrdiff_t i = 0; /* counts maximum expand for item */
364*0a6a1f1dSLionel Sambuc while (singlematch(ms, s + i, p, ep))
36511be35a1SLionel Sambuc i++;
36611be35a1SLionel Sambuc /* keeps trying to match with the maximum repetitions */
36711be35a1SLionel Sambuc while (i>=0) {
36811be35a1SLionel Sambuc const char *res = match(ms, (s+i), ep+1);
36911be35a1SLionel Sambuc if (res) return res;
37011be35a1SLionel Sambuc i--; /* else didn't match; reduce 1 repetition to try again */
37111be35a1SLionel Sambuc }
37211be35a1SLionel Sambuc return NULL;
37311be35a1SLionel Sambuc }
37411be35a1SLionel Sambuc
37511be35a1SLionel Sambuc
min_expand(MatchState * ms,const char * s,const char * p,const char * ep)37611be35a1SLionel Sambuc static const char *min_expand (MatchState *ms, const char *s,
37711be35a1SLionel Sambuc const char *p, const char *ep) {
37811be35a1SLionel Sambuc for (;;) {
37911be35a1SLionel Sambuc const char *res = match(ms, s, ep+1);
38011be35a1SLionel Sambuc if (res != NULL)
38111be35a1SLionel Sambuc return res;
382*0a6a1f1dSLionel Sambuc else if (singlematch(ms, s, p, ep))
38311be35a1SLionel Sambuc s++; /* try with one more repetition */
38411be35a1SLionel Sambuc else return NULL;
38511be35a1SLionel Sambuc }
38611be35a1SLionel Sambuc }
38711be35a1SLionel Sambuc
38811be35a1SLionel Sambuc
start_capture(MatchState * ms,const char * s,const char * p,int what)38911be35a1SLionel Sambuc static const char *start_capture (MatchState *ms, const char *s,
39011be35a1SLionel Sambuc const char *p, int what) {
39111be35a1SLionel Sambuc const char *res;
39211be35a1SLionel Sambuc int level = ms->level;
39311be35a1SLionel Sambuc if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
39411be35a1SLionel Sambuc ms->capture[level].init = s;
39511be35a1SLionel Sambuc ms->capture[level].len = what;
39611be35a1SLionel Sambuc ms->level = level+1;
39711be35a1SLionel Sambuc if ((res=match(ms, s, p)) == NULL) /* match failed? */
39811be35a1SLionel Sambuc ms->level--; /* undo capture */
39911be35a1SLionel Sambuc return res;
40011be35a1SLionel Sambuc }
40111be35a1SLionel Sambuc
40211be35a1SLionel Sambuc
end_capture(MatchState * ms,const char * s,const char * p)40311be35a1SLionel Sambuc static const char *end_capture (MatchState *ms, const char *s,
40411be35a1SLionel Sambuc const char *p) {
40511be35a1SLionel Sambuc int l = capture_to_close(ms);
40611be35a1SLionel Sambuc const char *res;
40711be35a1SLionel Sambuc ms->capture[l].len = s - ms->capture[l].init; /* close capture */
40811be35a1SLionel Sambuc if ((res = match(ms, s, p)) == NULL) /* match failed? */
40911be35a1SLionel Sambuc ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
41011be35a1SLionel Sambuc return res;
41111be35a1SLionel Sambuc }
41211be35a1SLionel Sambuc
41311be35a1SLionel Sambuc
match_capture(MatchState * ms,const char * s,int l)41411be35a1SLionel Sambuc static const char *match_capture (MatchState *ms, const char *s, int l) {
41511be35a1SLionel Sambuc size_t len;
41611be35a1SLionel Sambuc l = check_capture(ms, l);
41711be35a1SLionel Sambuc len = ms->capture[l].len;
41811be35a1SLionel Sambuc if ((size_t)(ms->src_end-s) >= len &&
41911be35a1SLionel Sambuc memcmp(ms->capture[l].init, s, len) == 0)
42011be35a1SLionel Sambuc return s+len;
42111be35a1SLionel Sambuc else return NULL;
42211be35a1SLionel Sambuc }
42311be35a1SLionel Sambuc
42411be35a1SLionel Sambuc
match(MatchState * ms,const char * s,const char * p)42511be35a1SLionel Sambuc static const char *match (MatchState *ms, const char *s, const char *p) {
426*0a6a1f1dSLionel Sambuc if (ms->matchdepth-- == 0)
427*0a6a1f1dSLionel Sambuc luaL_error(ms->L, "pattern too complex");
42811be35a1SLionel Sambuc init: /* using goto's to optimize tail recursion */
429*0a6a1f1dSLionel Sambuc if (p != ms->p_end) { /* end of pattern? */
43011be35a1SLionel Sambuc switch (*p) {
43111be35a1SLionel Sambuc case '(': { /* start capture */
43211be35a1SLionel Sambuc if (*(p + 1) == ')') /* position capture? */
433*0a6a1f1dSLionel Sambuc s = start_capture(ms, s, p + 2, CAP_POSITION);
43411be35a1SLionel Sambuc else
435*0a6a1f1dSLionel Sambuc s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
436*0a6a1f1dSLionel Sambuc break;
43711be35a1SLionel Sambuc }
43811be35a1SLionel Sambuc case ')': { /* end capture */
439*0a6a1f1dSLionel Sambuc s = end_capture(ms, s, p + 1);
440*0a6a1f1dSLionel Sambuc break;
44111be35a1SLionel Sambuc }
442*0a6a1f1dSLionel Sambuc case '$': {
443*0a6a1f1dSLionel Sambuc if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */
444*0a6a1f1dSLionel Sambuc goto dflt; /* no; go to default */
445*0a6a1f1dSLionel Sambuc s = (s == ms->src_end) ? s : NULL; /* check end of string */
446*0a6a1f1dSLionel Sambuc break;
447*0a6a1f1dSLionel Sambuc }
448*0a6a1f1dSLionel Sambuc case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
44911be35a1SLionel Sambuc switch (*(p + 1)) {
45011be35a1SLionel Sambuc case 'b': { /* balanced string? */
45111be35a1SLionel Sambuc s = matchbalance(ms, s, p + 2);
452*0a6a1f1dSLionel Sambuc if (s != NULL) {
453*0a6a1f1dSLionel Sambuc p += 4; goto init; /* return match(ms, s, p + 4); */
454*0a6a1f1dSLionel Sambuc } /* else fail (s == NULL) */
455*0a6a1f1dSLionel Sambuc break;
45611be35a1SLionel Sambuc }
45711be35a1SLionel Sambuc case 'f': { /* frontier? */
45811be35a1SLionel Sambuc const char *ep; char previous;
45911be35a1SLionel Sambuc p += 2;
46011be35a1SLionel Sambuc if (*p != '[')
461*0a6a1f1dSLionel Sambuc luaL_error(ms->L, "missing '[' after '%%f' in pattern");
46211be35a1SLionel Sambuc ep = classend(ms, p); /* points to what is next */
46311be35a1SLionel Sambuc previous = (s == ms->src_init) ? '\0' : *(s - 1);
464*0a6a1f1dSLionel Sambuc if (!matchbracketclass(uchar(previous), p, ep - 1) &&
465*0a6a1f1dSLionel Sambuc matchbracketclass(uchar(*s), p, ep - 1)) {
466*0a6a1f1dSLionel Sambuc p = ep; goto init; /* return match(ms, s, ep); */
46711be35a1SLionel Sambuc }
468*0a6a1f1dSLionel Sambuc s = NULL; /* match failed */
469*0a6a1f1dSLionel Sambuc break;
470*0a6a1f1dSLionel Sambuc }
471*0a6a1f1dSLionel Sambuc case '0': case '1': case '2': case '3':
472*0a6a1f1dSLionel Sambuc case '4': case '5': case '6': case '7':
473*0a6a1f1dSLionel Sambuc case '8': case '9': { /* capture results (%0-%9)? */
47411be35a1SLionel Sambuc s = match_capture(ms, s, uchar(*(p + 1)));
475*0a6a1f1dSLionel Sambuc if (s != NULL) {
476*0a6a1f1dSLionel Sambuc p += 2; goto init; /* return match(ms, s, p + 2) */
47711be35a1SLionel Sambuc }
478*0a6a1f1dSLionel Sambuc break;
47911be35a1SLionel Sambuc }
480*0a6a1f1dSLionel Sambuc default: goto dflt;
48111be35a1SLionel Sambuc }
482*0a6a1f1dSLionel Sambuc break;
48311be35a1SLionel Sambuc }
484*0a6a1f1dSLionel Sambuc default: dflt: { /* pattern class plus optional suffix */
485*0a6a1f1dSLionel Sambuc const char *ep = classend(ms, p); /* points to optional suffix */
486*0a6a1f1dSLionel Sambuc /* does not match at least once? */
487*0a6a1f1dSLionel Sambuc if (!singlematch(ms, s, p, ep)) {
488*0a6a1f1dSLionel Sambuc if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */
489*0a6a1f1dSLionel Sambuc p = ep + 1; goto init; /* return match(ms, s, ep + 1); */
49011be35a1SLionel Sambuc }
491*0a6a1f1dSLionel Sambuc else /* '+' or no suffix */
492*0a6a1f1dSLionel Sambuc s = NULL; /* fail */
49311be35a1SLionel Sambuc }
494*0a6a1f1dSLionel Sambuc else { /* matched once */
495*0a6a1f1dSLionel Sambuc switch (*ep) { /* handle optional suffix */
49611be35a1SLionel Sambuc case '?': { /* optional */
49711be35a1SLionel Sambuc const char *res;
498*0a6a1f1dSLionel Sambuc if ((res = match(ms, s + 1, ep + 1)) != NULL)
499*0a6a1f1dSLionel Sambuc s = res;
500*0a6a1f1dSLionel Sambuc else {
50111be35a1SLionel Sambuc p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */
50211be35a1SLionel Sambuc }
503*0a6a1f1dSLionel Sambuc break;
50411be35a1SLionel Sambuc }
505*0a6a1f1dSLionel Sambuc case '+': /* 1 or more repetitions */
506*0a6a1f1dSLionel Sambuc s++; /* 1 match already done */
507*0a6a1f1dSLionel Sambuc /* FALLTHROUGH */
508*0a6a1f1dSLionel Sambuc case '*': /* 0 or more repetitions */
509*0a6a1f1dSLionel Sambuc s = max_expand(ms, s, p, ep);
510*0a6a1f1dSLionel Sambuc break;
511*0a6a1f1dSLionel Sambuc case '-': /* 0 or more repetitions (minimum) */
512*0a6a1f1dSLionel Sambuc s = min_expand(ms, s, p, ep);
513*0a6a1f1dSLionel Sambuc break;
514*0a6a1f1dSLionel Sambuc default: /* no suffix */
515*0a6a1f1dSLionel Sambuc s++; p = ep; goto init; /* return match(ms, s + 1, ep); */
51611be35a1SLionel Sambuc }
51711be35a1SLionel Sambuc }
518*0a6a1f1dSLionel Sambuc break;
51911be35a1SLionel Sambuc }
52011be35a1SLionel Sambuc }
52111be35a1SLionel Sambuc }
522*0a6a1f1dSLionel Sambuc ms->matchdepth++;
523*0a6a1f1dSLionel Sambuc return s;
52411be35a1SLionel Sambuc }
52511be35a1SLionel Sambuc
52611be35a1SLionel Sambuc
52711be35a1SLionel Sambuc
lmemfind(const char * s1,size_t l1,const char * s2,size_t l2)52811be35a1SLionel Sambuc static const char *lmemfind (const char *s1, size_t l1,
52911be35a1SLionel Sambuc const char *s2, size_t l2) {
53011be35a1SLionel Sambuc if (l2 == 0) return s1; /* empty strings are everywhere */
531*0a6a1f1dSLionel Sambuc else if (l2 > l1) return NULL; /* avoids a negative 'l1' */
53211be35a1SLionel Sambuc else {
533*0a6a1f1dSLionel Sambuc const char *init; /* to search for a '*s2' inside 's1' */
534*0a6a1f1dSLionel Sambuc l2--; /* 1st char will be checked by 'memchr' */
535*0a6a1f1dSLionel Sambuc l1 = l1-l2; /* 's2' cannot be found after that */
53611be35a1SLionel Sambuc while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
53711be35a1SLionel Sambuc init++; /* 1st char is already checked */
53811be35a1SLionel Sambuc if (memcmp(init, s2+1, l2) == 0)
53911be35a1SLionel Sambuc return init-1;
540*0a6a1f1dSLionel Sambuc else { /* correct 'l1' and 's1' to try again */
54111be35a1SLionel Sambuc l1 -= init-s1;
54211be35a1SLionel Sambuc s1 = init;
54311be35a1SLionel Sambuc }
54411be35a1SLionel Sambuc }
54511be35a1SLionel Sambuc return NULL; /* not found */
54611be35a1SLionel Sambuc }
54711be35a1SLionel Sambuc }
54811be35a1SLionel Sambuc
54911be35a1SLionel Sambuc
push_onecapture(MatchState * ms,int i,const char * s,const char * e)55011be35a1SLionel Sambuc static void push_onecapture (MatchState *ms, int i, const char *s,
55111be35a1SLionel Sambuc const char *e) {
55211be35a1SLionel Sambuc if (i >= ms->level) {
55311be35a1SLionel Sambuc if (i == 0) /* ms->level == 0, too */
55411be35a1SLionel Sambuc lua_pushlstring(ms->L, s, e - s); /* add whole match */
55511be35a1SLionel Sambuc else
556*0a6a1f1dSLionel Sambuc luaL_error(ms->L, "invalid capture index %%%d", i + 1);
55711be35a1SLionel Sambuc }
55811be35a1SLionel Sambuc else {
55911be35a1SLionel Sambuc ptrdiff_t l = ms->capture[i].len;
56011be35a1SLionel Sambuc if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
56111be35a1SLionel Sambuc if (l == CAP_POSITION)
562*0a6a1f1dSLionel Sambuc lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
56311be35a1SLionel Sambuc else
56411be35a1SLionel Sambuc lua_pushlstring(ms->L, ms->capture[i].init, l);
56511be35a1SLionel Sambuc }
56611be35a1SLionel Sambuc }
56711be35a1SLionel Sambuc
56811be35a1SLionel Sambuc
push_captures(MatchState * ms,const char * s,const char * e)56911be35a1SLionel Sambuc static int push_captures (MatchState *ms, const char *s, const char *e) {
57011be35a1SLionel Sambuc int i;
57111be35a1SLionel Sambuc int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
57211be35a1SLionel Sambuc luaL_checkstack(ms->L, nlevels, "too many captures");
57311be35a1SLionel Sambuc for (i = 0; i < nlevels; i++)
57411be35a1SLionel Sambuc push_onecapture(ms, i, s, e);
57511be35a1SLionel Sambuc return nlevels; /* number of strings pushed */
57611be35a1SLionel Sambuc }
57711be35a1SLionel Sambuc
57811be35a1SLionel Sambuc
579*0a6a1f1dSLionel Sambuc /* check whether pattern has no special characters */
nospecials(const char * p,size_t l)580*0a6a1f1dSLionel Sambuc static int nospecials (const char *p, size_t l) {
581*0a6a1f1dSLionel Sambuc size_t upto = 0;
582*0a6a1f1dSLionel Sambuc do {
583*0a6a1f1dSLionel Sambuc if (strpbrk(p + upto, SPECIALS))
584*0a6a1f1dSLionel Sambuc return 0; /* pattern has a special character */
585*0a6a1f1dSLionel Sambuc upto += strlen(p + upto) + 1; /* may have more after \0 */
586*0a6a1f1dSLionel Sambuc } while (upto <= l);
587*0a6a1f1dSLionel Sambuc return 1; /* no special chars found */
588*0a6a1f1dSLionel Sambuc }
589*0a6a1f1dSLionel Sambuc
590*0a6a1f1dSLionel Sambuc
str_find_aux(lua_State * L,int find)59111be35a1SLionel Sambuc static int str_find_aux (lua_State *L, int find) {
592*0a6a1f1dSLionel Sambuc size_t ls, lp;
593*0a6a1f1dSLionel Sambuc const char *s = luaL_checklstring(L, 1, &ls);
594*0a6a1f1dSLionel Sambuc const char *p = luaL_checklstring(L, 2, &lp);
595*0a6a1f1dSLionel Sambuc lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls);
596*0a6a1f1dSLionel Sambuc if (init < 1) init = 1;
597*0a6a1f1dSLionel Sambuc else if (init > (lua_Integer)ls + 1) { /* start after string's end? */
598*0a6a1f1dSLionel Sambuc lua_pushnil(L); /* cannot find anything */
599*0a6a1f1dSLionel Sambuc return 1;
600*0a6a1f1dSLionel Sambuc }
601*0a6a1f1dSLionel Sambuc /* explicit request or no special characters? */
602*0a6a1f1dSLionel Sambuc if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {
60311be35a1SLionel Sambuc /* do a plain search */
604*0a6a1f1dSLionel Sambuc const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
60511be35a1SLionel Sambuc if (s2) {
606*0a6a1f1dSLionel Sambuc lua_pushinteger(L, (s2 - s) + 1);
607*0a6a1f1dSLionel Sambuc lua_pushinteger(L, (s2 - s) + lp);
60811be35a1SLionel Sambuc return 2;
60911be35a1SLionel Sambuc }
61011be35a1SLionel Sambuc }
61111be35a1SLionel Sambuc else {
61211be35a1SLionel Sambuc MatchState ms;
613*0a6a1f1dSLionel Sambuc const char *s1 = s + init - 1;
614*0a6a1f1dSLionel Sambuc int anchor = (*p == '^');
615*0a6a1f1dSLionel Sambuc if (anchor) {
616*0a6a1f1dSLionel Sambuc p++; lp--; /* skip anchor character */
617*0a6a1f1dSLionel Sambuc }
61811be35a1SLionel Sambuc ms.L = L;
619*0a6a1f1dSLionel Sambuc ms.matchdepth = MAXCCALLS;
62011be35a1SLionel Sambuc ms.src_init = s;
621*0a6a1f1dSLionel Sambuc ms.src_end = s + ls;
622*0a6a1f1dSLionel Sambuc ms.p_end = p + lp;
62311be35a1SLionel Sambuc do {
62411be35a1SLionel Sambuc const char *res;
62511be35a1SLionel Sambuc ms.level = 0;
626*0a6a1f1dSLionel Sambuc lua_assert(ms.matchdepth == MAXCCALLS);
62711be35a1SLionel Sambuc if ((res=match(&ms, s1, p)) != NULL) {
62811be35a1SLionel Sambuc if (find) {
629*0a6a1f1dSLionel Sambuc lua_pushinteger(L, (s1 - s) + 1); /* start */
63011be35a1SLionel Sambuc lua_pushinteger(L, res - s); /* end */
63111be35a1SLionel Sambuc return push_captures(&ms, NULL, 0) + 2;
63211be35a1SLionel Sambuc }
63311be35a1SLionel Sambuc else
63411be35a1SLionel Sambuc return push_captures(&ms, s1, res);
63511be35a1SLionel Sambuc }
63611be35a1SLionel Sambuc } while (s1++ < ms.src_end && !anchor);
63711be35a1SLionel Sambuc }
63811be35a1SLionel Sambuc lua_pushnil(L); /* not found */
63911be35a1SLionel Sambuc return 1;
64011be35a1SLionel Sambuc }
64111be35a1SLionel Sambuc
64211be35a1SLionel Sambuc
str_find(lua_State * L)64311be35a1SLionel Sambuc static int str_find (lua_State *L) {
64411be35a1SLionel Sambuc return str_find_aux(L, 1);
64511be35a1SLionel Sambuc }
64611be35a1SLionel Sambuc
64711be35a1SLionel Sambuc
str_match(lua_State * L)64811be35a1SLionel Sambuc static int str_match (lua_State *L) {
64911be35a1SLionel Sambuc return str_find_aux(L, 0);
65011be35a1SLionel Sambuc }
65111be35a1SLionel Sambuc
65211be35a1SLionel Sambuc
gmatch_aux(lua_State * L)65311be35a1SLionel Sambuc static int gmatch_aux (lua_State *L) {
65411be35a1SLionel Sambuc MatchState ms;
655*0a6a1f1dSLionel Sambuc size_t ls, lp;
65611be35a1SLionel Sambuc const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
657*0a6a1f1dSLionel Sambuc const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
65811be35a1SLionel Sambuc const char *src;
65911be35a1SLionel Sambuc ms.L = L;
660*0a6a1f1dSLionel Sambuc ms.matchdepth = MAXCCALLS;
66111be35a1SLionel Sambuc ms.src_init = s;
66211be35a1SLionel Sambuc ms.src_end = s+ls;
663*0a6a1f1dSLionel Sambuc ms.p_end = p + lp;
66411be35a1SLionel Sambuc for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
66511be35a1SLionel Sambuc src <= ms.src_end;
66611be35a1SLionel Sambuc src++) {
66711be35a1SLionel Sambuc const char *e;
66811be35a1SLionel Sambuc ms.level = 0;
669*0a6a1f1dSLionel Sambuc lua_assert(ms.matchdepth == MAXCCALLS);
67011be35a1SLionel Sambuc if ((e = match(&ms, src, p)) != NULL) {
67111be35a1SLionel Sambuc lua_Integer newstart = e-s;
67211be35a1SLionel Sambuc if (e == src) newstart++; /* empty match? go at least one position */
67311be35a1SLionel Sambuc lua_pushinteger(L, newstart);
67411be35a1SLionel Sambuc lua_replace(L, lua_upvalueindex(3));
67511be35a1SLionel Sambuc return push_captures(&ms, src, e);
67611be35a1SLionel Sambuc }
67711be35a1SLionel Sambuc }
67811be35a1SLionel Sambuc return 0; /* not found */
67911be35a1SLionel Sambuc }
68011be35a1SLionel Sambuc
68111be35a1SLionel Sambuc
gmatch(lua_State * L)68211be35a1SLionel Sambuc static int gmatch (lua_State *L) {
68311be35a1SLionel Sambuc luaL_checkstring(L, 1);
68411be35a1SLionel Sambuc luaL_checkstring(L, 2);
68511be35a1SLionel Sambuc lua_settop(L, 2);
68611be35a1SLionel Sambuc lua_pushinteger(L, 0);
68711be35a1SLionel Sambuc lua_pushcclosure(L, gmatch_aux, 3);
68811be35a1SLionel Sambuc return 1;
68911be35a1SLionel Sambuc }
69011be35a1SLionel Sambuc
69111be35a1SLionel Sambuc
add_s(MatchState * ms,luaL_Buffer * b,const char * s,const char * e)69211be35a1SLionel Sambuc static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
69311be35a1SLionel Sambuc const char *e) {
69411be35a1SLionel Sambuc size_t l, i;
695*0a6a1f1dSLionel Sambuc lua_State *L = ms->L;
696*0a6a1f1dSLionel Sambuc const char *news = lua_tolstring(L, 3, &l);
69711be35a1SLionel Sambuc for (i = 0; i < l; i++) {
69811be35a1SLionel Sambuc if (news[i] != L_ESC)
69911be35a1SLionel Sambuc luaL_addchar(b, news[i]);
70011be35a1SLionel Sambuc else {
70111be35a1SLionel Sambuc i++; /* skip ESC */
702*0a6a1f1dSLionel Sambuc if (!isdigit(uchar(news[i]))) {
703*0a6a1f1dSLionel Sambuc if (news[i] != L_ESC)
704*0a6a1f1dSLionel Sambuc luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
70511be35a1SLionel Sambuc luaL_addchar(b, news[i]);
706*0a6a1f1dSLionel Sambuc }
70711be35a1SLionel Sambuc else if (news[i] == '0')
70811be35a1SLionel Sambuc luaL_addlstring(b, s, e - s);
70911be35a1SLionel Sambuc else {
71011be35a1SLionel Sambuc push_onecapture(ms, news[i] - '1', s, e);
711*0a6a1f1dSLionel Sambuc luaL_tolstring(L, -1, NULL); /* if number, convert it to string */
712*0a6a1f1dSLionel Sambuc lua_remove(L, -2); /* remove original value */
71311be35a1SLionel Sambuc luaL_addvalue(b); /* add capture to accumulated result */
71411be35a1SLionel Sambuc }
71511be35a1SLionel Sambuc }
71611be35a1SLionel Sambuc }
71711be35a1SLionel Sambuc }
71811be35a1SLionel Sambuc
71911be35a1SLionel Sambuc
add_value(MatchState * ms,luaL_Buffer * b,const char * s,const char * e,int tr)72011be35a1SLionel Sambuc static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
721*0a6a1f1dSLionel Sambuc const char *e, int tr) {
72211be35a1SLionel Sambuc lua_State *L = ms->L;
723*0a6a1f1dSLionel Sambuc switch (tr) {
72411be35a1SLionel Sambuc case LUA_TFUNCTION: {
72511be35a1SLionel Sambuc int n;
72611be35a1SLionel Sambuc lua_pushvalue(L, 3);
72711be35a1SLionel Sambuc n = push_captures(ms, s, e);
72811be35a1SLionel Sambuc lua_call(L, n, 1);
72911be35a1SLionel Sambuc break;
73011be35a1SLionel Sambuc }
73111be35a1SLionel Sambuc case LUA_TTABLE: {
73211be35a1SLionel Sambuc push_onecapture(ms, 0, s, e);
73311be35a1SLionel Sambuc lua_gettable(L, 3);
73411be35a1SLionel Sambuc break;
73511be35a1SLionel Sambuc }
736*0a6a1f1dSLionel Sambuc default: { /* LUA_TNUMBER or LUA_TSTRING */
737*0a6a1f1dSLionel Sambuc add_s(ms, b, s, e);
738*0a6a1f1dSLionel Sambuc return;
739*0a6a1f1dSLionel Sambuc }
74011be35a1SLionel Sambuc }
74111be35a1SLionel Sambuc if (!lua_toboolean(L, -1)) { /* nil or false? */
74211be35a1SLionel Sambuc lua_pop(L, 1);
74311be35a1SLionel Sambuc lua_pushlstring(L, s, e - s); /* keep original text */
74411be35a1SLionel Sambuc }
74511be35a1SLionel Sambuc else if (!lua_isstring(L, -1))
74611be35a1SLionel Sambuc luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
74711be35a1SLionel Sambuc luaL_addvalue(b); /* add result to accumulator */
74811be35a1SLionel Sambuc }
74911be35a1SLionel Sambuc
75011be35a1SLionel Sambuc
str_gsub(lua_State * L)75111be35a1SLionel Sambuc static int str_gsub (lua_State *L) {
752*0a6a1f1dSLionel Sambuc size_t srcl, lp;
75311be35a1SLionel Sambuc const char *src = luaL_checklstring(L, 1, &srcl);
754*0a6a1f1dSLionel Sambuc const char *p = luaL_checklstring(L, 2, &lp);
75511be35a1SLionel Sambuc int tr = lua_type(L, 3);
756*0a6a1f1dSLionel Sambuc lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
757*0a6a1f1dSLionel Sambuc int anchor = (*p == '^');
758*0a6a1f1dSLionel Sambuc lua_Integer n = 0;
75911be35a1SLionel Sambuc MatchState ms;
76011be35a1SLionel Sambuc luaL_Buffer b;
76111be35a1SLionel Sambuc luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
76211be35a1SLionel Sambuc tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
76311be35a1SLionel Sambuc "string/function/table expected");
76411be35a1SLionel Sambuc luaL_buffinit(L, &b);
765*0a6a1f1dSLionel Sambuc if (anchor) {
766*0a6a1f1dSLionel Sambuc p++; lp--; /* skip anchor character */
767*0a6a1f1dSLionel Sambuc }
76811be35a1SLionel Sambuc ms.L = L;
769*0a6a1f1dSLionel Sambuc ms.matchdepth = MAXCCALLS;
77011be35a1SLionel Sambuc ms.src_init = src;
77111be35a1SLionel Sambuc ms.src_end = src+srcl;
772*0a6a1f1dSLionel Sambuc ms.p_end = p + lp;
77311be35a1SLionel Sambuc while (n < max_s) {
77411be35a1SLionel Sambuc const char *e;
77511be35a1SLionel Sambuc ms.level = 0;
776*0a6a1f1dSLionel Sambuc lua_assert(ms.matchdepth == MAXCCALLS);
77711be35a1SLionel Sambuc e = match(&ms, src, p);
77811be35a1SLionel Sambuc if (e) {
77911be35a1SLionel Sambuc n++;
780*0a6a1f1dSLionel Sambuc add_value(&ms, &b, src, e, tr);
78111be35a1SLionel Sambuc }
78211be35a1SLionel Sambuc if (e && e>src) /* non empty match? */
78311be35a1SLionel Sambuc src = e; /* skip it */
78411be35a1SLionel Sambuc else if (src < ms.src_end)
78511be35a1SLionel Sambuc luaL_addchar(&b, *src++);
78611be35a1SLionel Sambuc else break;
78711be35a1SLionel Sambuc if (anchor) break;
78811be35a1SLionel Sambuc }
78911be35a1SLionel Sambuc luaL_addlstring(&b, src, ms.src_end-src);
79011be35a1SLionel Sambuc luaL_pushresult(&b);
79111be35a1SLionel Sambuc lua_pushinteger(L, n); /* number of substitutions */
79211be35a1SLionel Sambuc return 2;
79311be35a1SLionel Sambuc }
79411be35a1SLionel Sambuc
79511be35a1SLionel Sambuc /* }====================================================== */
79611be35a1SLionel Sambuc
79711be35a1SLionel Sambuc
798*0a6a1f1dSLionel Sambuc
799*0a6a1f1dSLionel Sambuc /*
800*0a6a1f1dSLionel Sambuc ** {======================================================
801*0a6a1f1dSLionel Sambuc ** STRING FORMAT
802*0a6a1f1dSLionel Sambuc ** =======================================================
803*0a6a1f1dSLionel Sambuc */
804*0a6a1f1dSLionel Sambuc
805*0a6a1f1dSLionel Sambuc #if !defined(lua_number2strx) /* { */
806*0a6a1f1dSLionel Sambuc
807*0a6a1f1dSLionel Sambuc /*
808*0a6a1f1dSLionel Sambuc ** Hexadecimal floating-point formatter
809*0a6a1f1dSLionel Sambuc */
810*0a6a1f1dSLionel Sambuc
811*0a6a1f1dSLionel Sambuc #include <locale.h>
812*0a6a1f1dSLionel Sambuc #include <math.h>
813*0a6a1f1dSLionel Sambuc
814*0a6a1f1dSLionel Sambuc #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
815*0a6a1f1dSLionel Sambuc
816*0a6a1f1dSLionel Sambuc
817*0a6a1f1dSLionel Sambuc /*
818*0a6a1f1dSLionel Sambuc ** Number of bits that goes into the first digit. It can be any value
819*0a6a1f1dSLionel Sambuc ** between 1 and 4; the following definition tries to align the number
820*0a6a1f1dSLionel Sambuc ** to nibble boundaries by making what is left after that first digit a
821*0a6a1f1dSLionel Sambuc ** multiple of 4.
822*0a6a1f1dSLionel Sambuc */
823*0a6a1f1dSLionel Sambuc #define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1)
824*0a6a1f1dSLionel Sambuc
825*0a6a1f1dSLionel Sambuc
826*0a6a1f1dSLionel Sambuc /*
827*0a6a1f1dSLionel Sambuc ** Add integer part of 'x' to buffer and return new 'x'
828*0a6a1f1dSLionel Sambuc */
adddigit(char * buff,int n,lua_Number x)829*0a6a1f1dSLionel Sambuc static lua_Number adddigit (char *buff, int n, lua_Number x) {
830*0a6a1f1dSLionel Sambuc lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
831*0a6a1f1dSLionel Sambuc int d = (int)dd;
832*0a6a1f1dSLionel Sambuc buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
833*0a6a1f1dSLionel Sambuc return x - dd; /* return what is left */
834*0a6a1f1dSLionel Sambuc }
835*0a6a1f1dSLionel Sambuc
836*0a6a1f1dSLionel Sambuc
num2straux(char * buff,lua_Number x)837*0a6a1f1dSLionel Sambuc static int num2straux (char *buff, lua_Number x) {
838*0a6a1f1dSLionel Sambuc if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */
839*0a6a1f1dSLionel Sambuc return sprintf(buff, LUA_NUMBER_FMT, x); /* equal to '%g' */
840*0a6a1f1dSLionel Sambuc else if (x == 0) { /* can be -0... */
841*0a6a1f1dSLionel Sambuc sprintf(buff, LUA_NUMBER_FMT, x);
842*0a6a1f1dSLionel Sambuc strcat(buff, "x0p+0"); /* reuses '0/-0' from 'sprintf'... */
843*0a6a1f1dSLionel Sambuc return strlen(buff);
844*0a6a1f1dSLionel Sambuc }
845*0a6a1f1dSLionel Sambuc else {
846*0a6a1f1dSLionel Sambuc int e;
847*0a6a1f1dSLionel Sambuc lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
848*0a6a1f1dSLionel Sambuc int n = 0; /* character count */
849*0a6a1f1dSLionel Sambuc if (m < 0) { /* is number negative? */
850*0a6a1f1dSLionel Sambuc buff[n++] = '-'; /* add signal */
851*0a6a1f1dSLionel Sambuc m = -m; /* make it positive */
852*0a6a1f1dSLionel Sambuc }
853*0a6a1f1dSLionel Sambuc buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */
854*0a6a1f1dSLionel Sambuc m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */
855*0a6a1f1dSLionel Sambuc e -= L_NBFD; /* this digit goes before the radix point */
856*0a6a1f1dSLionel Sambuc if (m > 0) { /* more digits? */
857*0a6a1f1dSLionel Sambuc buff[n++] = lua_getlocaledecpoint(); /* add radix point */
858*0a6a1f1dSLionel Sambuc do { /* add as many digits as needed */
859*0a6a1f1dSLionel Sambuc m = adddigit(buff, n++, m * 16);
860*0a6a1f1dSLionel Sambuc } while (m > 0);
861*0a6a1f1dSLionel Sambuc }
862*0a6a1f1dSLionel Sambuc n += sprintf(buff + n, "p%+d", e); /* add exponent */
863*0a6a1f1dSLionel Sambuc return n;
864*0a6a1f1dSLionel Sambuc }
865*0a6a1f1dSLionel Sambuc }
866*0a6a1f1dSLionel Sambuc
867*0a6a1f1dSLionel Sambuc
lua_number2strx(lua_State * L,char * buff,const char * fmt,lua_Number x)868*0a6a1f1dSLionel Sambuc static int lua_number2strx (lua_State *L, char *buff, const char *fmt,
869*0a6a1f1dSLionel Sambuc lua_Number x) {
870*0a6a1f1dSLionel Sambuc int n = num2straux(buff, x);
871*0a6a1f1dSLionel Sambuc if (fmt[SIZELENMOD] == 'A') {
872*0a6a1f1dSLionel Sambuc int i;
873*0a6a1f1dSLionel Sambuc for (i = 0; i < n; i++)
874*0a6a1f1dSLionel Sambuc buff[i] = toupper(uchar(buff[i]));
875*0a6a1f1dSLionel Sambuc }
876*0a6a1f1dSLionel Sambuc else if (fmt[SIZELENMOD] != 'a')
877*0a6a1f1dSLionel Sambuc luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
878*0a6a1f1dSLionel Sambuc return n;
879*0a6a1f1dSLionel Sambuc }
880*0a6a1f1dSLionel Sambuc
881*0a6a1f1dSLionel Sambuc #endif /* } */
882*0a6a1f1dSLionel Sambuc
883*0a6a1f1dSLionel Sambuc
884*0a6a1f1dSLionel Sambuc /*
885*0a6a1f1dSLionel Sambuc ** Maximum size of each formatted item. This maximum size is produced
886*0a6a1f1dSLionel Sambuc ** by format('%.99f', minfloat), and is equal to 99 + 2 ('-' and '.') +
887*0a6a1f1dSLionel Sambuc ** number of decimal digits to represent minfloat.
888*0a6a1f1dSLionel Sambuc */
889*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
890*0a6a1f1dSLionel Sambuc #define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
891*0a6a1f1dSLionel Sambuc #else
892*0a6a1f1dSLionel Sambuc #define MAX_ITEM (120)
893*0a6a1f1dSLionel Sambuc #endif
894*0a6a1f1dSLionel Sambuc
89511be35a1SLionel Sambuc /* valid flags in a format specification */
89611be35a1SLionel Sambuc #define FLAGS "-+ #0"
897*0a6a1f1dSLionel Sambuc
89811be35a1SLionel Sambuc /*
899*0a6a1f1dSLionel Sambuc ** maximum size of each format specification (such as "%-099.99d")
90011be35a1SLionel Sambuc */
901*0a6a1f1dSLionel Sambuc #define MAX_FORMAT 32
90211be35a1SLionel Sambuc
90311be35a1SLionel Sambuc
addquoted(lua_State * L,luaL_Buffer * b,int arg)90411be35a1SLionel Sambuc static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
90511be35a1SLionel Sambuc size_t l;
90611be35a1SLionel Sambuc const char *s = luaL_checklstring(L, arg, &l);
90711be35a1SLionel Sambuc luaL_addchar(b, '"');
90811be35a1SLionel Sambuc while (l--) {
909*0a6a1f1dSLionel Sambuc if (*s == '"' || *s == '\\' || *s == '\n') {
91011be35a1SLionel Sambuc luaL_addchar(b, '\\');
91111be35a1SLionel Sambuc luaL_addchar(b, *s);
91211be35a1SLionel Sambuc }
913*0a6a1f1dSLionel Sambuc else if (*s == '\0' || iscntrl(uchar(*s))) {
914*0a6a1f1dSLionel Sambuc char buff[10];
915*0a6a1f1dSLionel Sambuc if (!isdigit(uchar(*(s+1))))
916*0a6a1f1dSLionel Sambuc sprintf(buff, "\\%d", (int)uchar(*s));
917*0a6a1f1dSLionel Sambuc else
918*0a6a1f1dSLionel Sambuc sprintf(buff, "\\%03d", (int)uchar(*s));
919*0a6a1f1dSLionel Sambuc luaL_addstring(b, buff);
92011be35a1SLionel Sambuc }
921*0a6a1f1dSLionel Sambuc else
92211be35a1SLionel Sambuc luaL_addchar(b, *s);
92311be35a1SLionel Sambuc s++;
92411be35a1SLionel Sambuc }
92511be35a1SLionel Sambuc luaL_addchar(b, '"');
92611be35a1SLionel Sambuc }
92711be35a1SLionel Sambuc
scanformat(lua_State * L,const char * strfrmt,char * form)92811be35a1SLionel Sambuc static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
92911be35a1SLionel Sambuc const char *p = strfrmt;
93011be35a1SLionel Sambuc while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
931*0a6a1f1dSLionel Sambuc if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
93211be35a1SLionel Sambuc luaL_error(L, "invalid format (repeated flags)");
93311be35a1SLionel Sambuc if (isdigit(uchar(*p))) p++; /* skip width */
93411be35a1SLionel Sambuc if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
93511be35a1SLionel Sambuc if (*p == '.') {
93611be35a1SLionel Sambuc p++;
93711be35a1SLionel Sambuc if (isdigit(uchar(*p))) p++; /* skip precision */
93811be35a1SLionel Sambuc if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
93911be35a1SLionel Sambuc }
94011be35a1SLionel Sambuc if (isdigit(uchar(*p)))
94111be35a1SLionel Sambuc luaL_error(L, "invalid format (width or precision too long)");
94211be35a1SLionel Sambuc *(form++) = '%';
943*0a6a1f1dSLionel Sambuc memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
944*0a6a1f1dSLionel Sambuc form += (p - strfrmt) + 1;
94511be35a1SLionel Sambuc *form = '\0';
94611be35a1SLionel Sambuc return p;
94711be35a1SLionel Sambuc }
94811be35a1SLionel Sambuc
94911be35a1SLionel Sambuc
950*0a6a1f1dSLionel Sambuc /*
951*0a6a1f1dSLionel Sambuc ** add length modifier into formats
952*0a6a1f1dSLionel Sambuc */
addlenmod(char * form,const char * lenmod)953*0a6a1f1dSLionel Sambuc static void addlenmod (char *form, const char *lenmod) {
95411be35a1SLionel Sambuc size_t l = strlen(form);
955*0a6a1f1dSLionel Sambuc size_t lm = strlen(lenmod);
95611be35a1SLionel Sambuc char spec = form[l - 1];
957*0a6a1f1dSLionel Sambuc strcpy(form + l - 1, lenmod);
958*0a6a1f1dSLionel Sambuc form[l + lm - 1] = spec;
959*0a6a1f1dSLionel Sambuc form[l + lm] = '\0';
96011be35a1SLionel Sambuc }
96111be35a1SLionel Sambuc
96211be35a1SLionel Sambuc
str_format(lua_State * L)96311be35a1SLionel Sambuc static int str_format (lua_State *L) {
96411be35a1SLionel Sambuc int top = lua_gettop(L);
96511be35a1SLionel Sambuc int arg = 1;
96611be35a1SLionel Sambuc size_t sfl;
96711be35a1SLionel Sambuc const char *strfrmt = luaL_checklstring(L, arg, &sfl);
96811be35a1SLionel Sambuc const char *strfrmt_end = strfrmt+sfl;
96911be35a1SLionel Sambuc luaL_Buffer b;
97011be35a1SLionel Sambuc luaL_buffinit(L, &b);
97111be35a1SLionel Sambuc while (strfrmt < strfrmt_end) {
97211be35a1SLionel Sambuc if (*strfrmt != L_ESC)
97311be35a1SLionel Sambuc luaL_addchar(&b, *strfrmt++);
97411be35a1SLionel Sambuc else if (*++strfrmt == L_ESC)
97511be35a1SLionel Sambuc luaL_addchar(&b, *strfrmt++); /* %% */
97611be35a1SLionel Sambuc else { /* format item */
977*0a6a1f1dSLionel Sambuc char form[MAX_FORMAT]; /* to store the format ('%...') */
978*0a6a1f1dSLionel Sambuc char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */
979*0a6a1f1dSLionel Sambuc int nb = 0; /* number of bytes in added item */
98011be35a1SLionel Sambuc if (++arg > top)
98111be35a1SLionel Sambuc luaL_argerror(L, arg, "no value");
98211be35a1SLionel Sambuc strfrmt = scanformat(L, strfrmt, form);
98311be35a1SLionel Sambuc switch (*strfrmt++) {
98411be35a1SLionel Sambuc case 'c': {
985*0a6a1f1dSLionel Sambuc nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
98611be35a1SLionel Sambuc break;
98711be35a1SLionel Sambuc }
988*0a6a1f1dSLionel Sambuc case 'd': case 'i':
98911be35a1SLionel Sambuc case 'o': case 'u': case 'x': case 'X': {
990*0a6a1f1dSLionel Sambuc lua_Integer n = luaL_checkinteger(L, arg);
991*0a6a1f1dSLionel Sambuc addlenmod(form, LUA_INTEGER_FRMLEN);
992*0a6a1f1dSLionel Sambuc nb = sprintf(buff, form, n);
99311be35a1SLionel Sambuc break;
99411be35a1SLionel Sambuc }
995*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
996*0a6a1f1dSLionel Sambuc case 'a': case 'A':
997*0a6a1f1dSLionel Sambuc addlenmod(form, LUA_NUMBER_FRMLEN);
998*0a6a1f1dSLionel Sambuc nb = lua_number2strx(L, buff, form, luaL_checknumber(L, arg));
999*0a6a1f1dSLionel Sambuc break;
100011be35a1SLionel Sambuc case 'e': case 'E': case 'f':
100111be35a1SLionel Sambuc case 'g': case 'G': {
1002*0a6a1f1dSLionel Sambuc addlenmod(form, LUA_NUMBER_FRMLEN);
1003*0a6a1f1dSLionel Sambuc nb = sprintf(buff, form, luaL_checknumber(L, arg));
100411be35a1SLionel Sambuc break;
100511be35a1SLionel Sambuc }
1006*0a6a1f1dSLionel Sambuc #endif
100711be35a1SLionel Sambuc case 'q': {
100811be35a1SLionel Sambuc addquoted(L, &b, arg);
1009*0a6a1f1dSLionel Sambuc break;
101011be35a1SLionel Sambuc }
101111be35a1SLionel Sambuc case 's': {
101211be35a1SLionel Sambuc size_t l;
1013*0a6a1f1dSLionel Sambuc const char *s = luaL_tolstring(L, arg, &l);
101411be35a1SLionel Sambuc if (!strchr(form, '.') && l >= 100) {
101511be35a1SLionel Sambuc /* no precision and string is too long to be formatted;
101611be35a1SLionel Sambuc keep original string */
101711be35a1SLionel Sambuc luaL_addvalue(&b);
101811be35a1SLionel Sambuc }
101911be35a1SLionel Sambuc else {
1020*0a6a1f1dSLionel Sambuc nb = sprintf(buff, form, s);
1021*0a6a1f1dSLionel Sambuc lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
1022*0a6a1f1dSLionel Sambuc }
102311be35a1SLionel Sambuc break;
102411be35a1SLionel Sambuc }
1025*0a6a1f1dSLionel Sambuc default: { /* also treat cases 'pnLlh' */
1026*0a6a1f1dSLionel Sambuc return luaL_error(L, "invalid option '%%%c' to 'format'",
1027*0a6a1f1dSLionel Sambuc *(strfrmt - 1));
102811be35a1SLionel Sambuc }
102911be35a1SLionel Sambuc }
1030*0a6a1f1dSLionel Sambuc luaL_addsize(&b, nb);
103111be35a1SLionel Sambuc }
103211be35a1SLionel Sambuc }
103311be35a1SLionel Sambuc luaL_pushresult(&b);
103411be35a1SLionel Sambuc return 1;
103511be35a1SLionel Sambuc }
103611be35a1SLionel Sambuc
1037*0a6a1f1dSLionel Sambuc /* }====================================================== */
1038*0a6a1f1dSLionel Sambuc
1039*0a6a1f1dSLionel Sambuc
1040*0a6a1f1dSLionel Sambuc /*
1041*0a6a1f1dSLionel Sambuc ** {======================================================
1042*0a6a1f1dSLionel Sambuc ** PACK/UNPACK
1043*0a6a1f1dSLionel Sambuc ** =======================================================
1044*0a6a1f1dSLionel Sambuc */
1045*0a6a1f1dSLionel Sambuc
1046*0a6a1f1dSLionel Sambuc
1047*0a6a1f1dSLionel Sambuc /* value used for padding */
1048*0a6a1f1dSLionel Sambuc #if !defined(LUA_PACKPADBYTE)
1049*0a6a1f1dSLionel Sambuc #define LUA_PACKPADBYTE 0x00
1050*0a6a1f1dSLionel Sambuc #endif
1051*0a6a1f1dSLionel Sambuc
1052*0a6a1f1dSLionel Sambuc /* maximum size for the binary representation of an integer */
1053*0a6a1f1dSLionel Sambuc #define MAXINTSIZE 16
1054*0a6a1f1dSLionel Sambuc
1055*0a6a1f1dSLionel Sambuc /* number of bits in a character */
1056*0a6a1f1dSLionel Sambuc #define NB CHAR_BIT
1057*0a6a1f1dSLionel Sambuc
1058*0a6a1f1dSLionel Sambuc /* mask for one character (NB 1's) */
1059*0a6a1f1dSLionel Sambuc #define MC ((1 << NB) - 1)
1060*0a6a1f1dSLionel Sambuc
1061*0a6a1f1dSLionel Sambuc /* size of a lua_Integer */
1062*0a6a1f1dSLionel Sambuc #define SZINT ((int)sizeof(lua_Integer))
1063*0a6a1f1dSLionel Sambuc
1064*0a6a1f1dSLionel Sambuc
1065*0a6a1f1dSLionel Sambuc /* dummy union to get native endianness */
1066*0a6a1f1dSLionel Sambuc static const union {
1067*0a6a1f1dSLionel Sambuc int dummy;
1068*0a6a1f1dSLionel Sambuc char little; /* true iff machine is little endian */
1069*0a6a1f1dSLionel Sambuc } nativeendian = {1};
1070*0a6a1f1dSLionel Sambuc
1071*0a6a1f1dSLionel Sambuc
1072*0a6a1f1dSLionel Sambuc /* dummy structure to get native alignment requirements */
1073*0a6a1f1dSLionel Sambuc struct cD {
1074*0a6a1f1dSLionel Sambuc char c;
1075*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1076*0a6a1f1dSLionel Sambuc union { double d; void *p; lua_Integer i; lua_Number n; } u;
1077*0a6a1f1dSLionel Sambuc #else /* _KERNEL */
1078*0a6a1f1dSLionel Sambuc union { void *p; lua_Integer i; lua_Number n; } u;
1079*0a6a1f1dSLionel Sambuc #endif
1080*0a6a1f1dSLionel Sambuc };
1081*0a6a1f1dSLionel Sambuc
1082*0a6a1f1dSLionel Sambuc #define MAXALIGN (offsetof(struct cD, u))
1083*0a6a1f1dSLionel Sambuc
1084*0a6a1f1dSLionel Sambuc
1085*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1086*0a6a1f1dSLionel Sambuc /*
1087*0a6a1f1dSLionel Sambuc ** Union for serializing floats
1088*0a6a1f1dSLionel Sambuc */
1089*0a6a1f1dSLionel Sambuc typedef union Ftypes {
1090*0a6a1f1dSLionel Sambuc float f;
1091*0a6a1f1dSLionel Sambuc double d;
1092*0a6a1f1dSLionel Sambuc lua_Number n;
1093*0a6a1f1dSLionel Sambuc char buff[5 * sizeof(lua_Number)]; /* enough for any float type */
1094*0a6a1f1dSLionel Sambuc } Ftypes;
1095*0a6a1f1dSLionel Sambuc #endif
1096*0a6a1f1dSLionel Sambuc
1097*0a6a1f1dSLionel Sambuc
1098*0a6a1f1dSLionel Sambuc /*
1099*0a6a1f1dSLionel Sambuc ** information to pack/unpack stuff
1100*0a6a1f1dSLionel Sambuc */
1101*0a6a1f1dSLionel Sambuc typedef struct Header {
1102*0a6a1f1dSLionel Sambuc lua_State *L;
1103*0a6a1f1dSLionel Sambuc int islittle;
1104*0a6a1f1dSLionel Sambuc int maxalign;
1105*0a6a1f1dSLionel Sambuc } Header;
1106*0a6a1f1dSLionel Sambuc
1107*0a6a1f1dSLionel Sambuc
1108*0a6a1f1dSLionel Sambuc /*
1109*0a6a1f1dSLionel Sambuc ** options for pack/unpack
1110*0a6a1f1dSLionel Sambuc */
1111*0a6a1f1dSLionel Sambuc typedef enum KOption {
1112*0a6a1f1dSLionel Sambuc Kint, /* signed integers */
1113*0a6a1f1dSLionel Sambuc Kuint, /* unsigned integers */
1114*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1115*0a6a1f1dSLionel Sambuc Kfloat, /* floating-point numbers */
1116*0a6a1f1dSLionel Sambuc #endif
1117*0a6a1f1dSLionel Sambuc Kchar, /* fixed-length strings */
1118*0a6a1f1dSLionel Sambuc Kstring, /* strings with prefixed length */
1119*0a6a1f1dSLionel Sambuc Kzstr, /* zero-terminated strings */
1120*0a6a1f1dSLionel Sambuc Kpadding, /* padding */
1121*0a6a1f1dSLionel Sambuc Kpaddalign, /* padding for alignment */
1122*0a6a1f1dSLionel Sambuc Knop /* no-op (configuration or spaces) */
1123*0a6a1f1dSLionel Sambuc } KOption;
1124*0a6a1f1dSLionel Sambuc
1125*0a6a1f1dSLionel Sambuc
1126*0a6a1f1dSLionel Sambuc /*
1127*0a6a1f1dSLionel Sambuc ** Read an integer numeral from string 'fmt' or return 'df' if
1128*0a6a1f1dSLionel Sambuc ** there is no numeral
1129*0a6a1f1dSLionel Sambuc */
digit(int c)1130*0a6a1f1dSLionel Sambuc static int digit (int c) { return '0' <= c && c <= '9'; }
1131*0a6a1f1dSLionel Sambuc
getnum(const char ** fmt,int df)1132*0a6a1f1dSLionel Sambuc static int getnum (const char **fmt, int df) {
1133*0a6a1f1dSLionel Sambuc if (!digit(**fmt)) /* no number? */
1134*0a6a1f1dSLionel Sambuc return df; /* return default value */
1135*0a6a1f1dSLionel Sambuc else {
1136*0a6a1f1dSLionel Sambuc int a = 0;
1137*0a6a1f1dSLionel Sambuc do {
1138*0a6a1f1dSLionel Sambuc a = a*10 + (*((*fmt)++) - '0');
1139*0a6a1f1dSLionel Sambuc } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
1140*0a6a1f1dSLionel Sambuc return a;
1141*0a6a1f1dSLionel Sambuc }
1142*0a6a1f1dSLionel Sambuc }
1143*0a6a1f1dSLionel Sambuc
1144*0a6a1f1dSLionel Sambuc
1145*0a6a1f1dSLionel Sambuc /*
1146*0a6a1f1dSLionel Sambuc ** Read an integer numeral and raises an error if it is larger
1147*0a6a1f1dSLionel Sambuc ** than the maximum size for integers.
1148*0a6a1f1dSLionel Sambuc */
getnumlimit(Header * h,const char ** fmt,int df)1149*0a6a1f1dSLionel Sambuc static int getnumlimit (Header *h, const char **fmt, int df) {
1150*0a6a1f1dSLionel Sambuc int sz = getnum(fmt, df);
1151*0a6a1f1dSLionel Sambuc if (sz > MAXINTSIZE || sz <= 0)
1152*0a6a1f1dSLionel Sambuc luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
1153*0a6a1f1dSLionel Sambuc sz, MAXINTSIZE);
1154*0a6a1f1dSLionel Sambuc return sz;
1155*0a6a1f1dSLionel Sambuc }
1156*0a6a1f1dSLionel Sambuc
1157*0a6a1f1dSLionel Sambuc
1158*0a6a1f1dSLionel Sambuc /*
1159*0a6a1f1dSLionel Sambuc ** Initialize Header
1160*0a6a1f1dSLionel Sambuc */
initheader(lua_State * L,Header * h)1161*0a6a1f1dSLionel Sambuc static void initheader (lua_State *L, Header *h) {
1162*0a6a1f1dSLionel Sambuc h->L = L;
1163*0a6a1f1dSLionel Sambuc h->islittle = nativeendian.little;
1164*0a6a1f1dSLionel Sambuc h->maxalign = 1;
1165*0a6a1f1dSLionel Sambuc }
1166*0a6a1f1dSLionel Sambuc
1167*0a6a1f1dSLionel Sambuc
1168*0a6a1f1dSLionel Sambuc /*
1169*0a6a1f1dSLionel Sambuc ** Read and classify next option. 'size' is filled with option's size.
1170*0a6a1f1dSLionel Sambuc */
getoption(Header * h,const char ** fmt,int * size)1171*0a6a1f1dSLionel Sambuc static KOption getoption (Header *h, const char **fmt, int *size) {
1172*0a6a1f1dSLionel Sambuc int opt = *((*fmt)++);
1173*0a6a1f1dSLionel Sambuc *size = 0; /* default */
1174*0a6a1f1dSLionel Sambuc switch (opt) {
1175*0a6a1f1dSLionel Sambuc case 'b': *size = sizeof(char); return Kint;
1176*0a6a1f1dSLionel Sambuc case 'B': *size = sizeof(char); return Kuint;
1177*0a6a1f1dSLionel Sambuc case 'h': *size = sizeof(short); return Kint;
1178*0a6a1f1dSLionel Sambuc case 'H': *size = sizeof(short); return Kuint;
1179*0a6a1f1dSLionel Sambuc case 'l': *size = sizeof(long); return Kint;
1180*0a6a1f1dSLionel Sambuc case 'L': *size = sizeof(long); return Kuint;
1181*0a6a1f1dSLionel Sambuc case 'j': *size = sizeof(lua_Integer); return Kint;
1182*0a6a1f1dSLionel Sambuc case 'J': *size = sizeof(lua_Integer); return Kuint;
1183*0a6a1f1dSLionel Sambuc case 'T': *size = sizeof(size_t); return Kuint;
1184*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1185*0a6a1f1dSLionel Sambuc case 'f': *size = sizeof(float); return Kfloat;
1186*0a6a1f1dSLionel Sambuc case 'd': *size = sizeof(double); return Kfloat;
1187*0a6a1f1dSLionel Sambuc case 'n': *size = sizeof(lua_Number); return Kfloat;
1188*0a6a1f1dSLionel Sambuc #else /* _KERNEL */
1189*0a6a1f1dSLionel Sambuc case 'n': *size = sizeof(lua_Number); return Kint;
1190*0a6a1f1dSLionel Sambuc #endif
1191*0a6a1f1dSLionel Sambuc case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
1192*0a6a1f1dSLionel Sambuc case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
1193*0a6a1f1dSLionel Sambuc case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
1194*0a6a1f1dSLionel Sambuc case 'c':
1195*0a6a1f1dSLionel Sambuc *size = getnum(fmt, -1);
1196*0a6a1f1dSLionel Sambuc if (*size == -1)
1197*0a6a1f1dSLionel Sambuc luaL_error(h->L, "missing size for format option 'c'");
1198*0a6a1f1dSLionel Sambuc return Kchar;
1199*0a6a1f1dSLionel Sambuc case 'z': return Kzstr;
1200*0a6a1f1dSLionel Sambuc case 'x': *size = 1; return Kpadding;
1201*0a6a1f1dSLionel Sambuc case 'X': return Kpaddalign;
1202*0a6a1f1dSLionel Sambuc case ' ': break;
1203*0a6a1f1dSLionel Sambuc case '<': h->islittle = 1; break;
1204*0a6a1f1dSLionel Sambuc case '>': h->islittle = 0; break;
1205*0a6a1f1dSLionel Sambuc case '=': h->islittle = nativeendian.little; break;
1206*0a6a1f1dSLionel Sambuc case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
1207*0a6a1f1dSLionel Sambuc default: luaL_error(h->L, "invalid format option '%c'", opt);
1208*0a6a1f1dSLionel Sambuc }
1209*0a6a1f1dSLionel Sambuc return Knop;
1210*0a6a1f1dSLionel Sambuc }
1211*0a6a1f1dSLionel Sambuc
1212*0a6a1f1dSLionel Sambuc
1213*0a6a1f1dSLionel Sambuc /*
1214*0a6a1f1dSLionel Sambuc ** Read, classify, and fill other details about the next option.
1215*0a6a1f1dSLionel Sambuc ** 'psize' is filled with option's size, 'notoalign' with its
1216*0a6a1f1dSLionel Sambuc ** alignment requirements.
1217*0a6a1f1dSLionel Sambuc ** Local variable 'size' gets the size to be aligned. (Kpadal option
1218*0a6a1f1dSLionel Sambuc ** always gets its full alignment, other options are limited by
1219*0a6a1f1dSLionel Sambuc ** the maximum alignment ('maxalign'). Kchar option needs no alignment
1220*0a6a1f1dSLionel Sambuc ** despite its size.
1221*0a6a1f1dSLionel Sambuc */
getdetails(Header * h,size_t totalsize,const char ** fmt,int * psize,int * ntoalign)1222*0a6a1f1dSLionel Sambuc static KOption getdetails (Header *h, size_t totalsize,
1223*0a6a1f1dSLionel Sambuc const char **fmt, int *psize, int *ntoalign) {
1224*0a6a1f1dSLionel Sambuc KOption opt = getoption(h, fmt, psize);
1225*0a6a1f1dSLionel Sambuc int align = *psize; /* usually, alignment follows size */
1226*0a6a1f1dSLionel Sambuc if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
1227*0a6a1f1dSLionel Sambuc if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
1228*0a6a1f1dSLionel Sambuc luaL_argerror(h->L, 1, "invalid next option for option 'X'");
1229*0a6a1f1dSLionel Sambuc }
1230*0a6a1f1dSLionel Sambuc if (align <= 1 || opt == Kchar) /* need no alignment? */
1231*0a6a1f1dSLionel Sambuc *ntoalign = 0;
1232*0a6a1f1dSLionel Sambuc else {
1233*0a6a1f1dSLionel Sambuc if (align > h->maxalign) /* enforce maximum alignment */
1234*0a6a1f1dSLionel Sambuc align = h->maxalign;
1235*0a6a1f1dSLionel Sambuc if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */
1236*0a6a1f1dSLionel Sambuc luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
1237*0a6a1f1dSLionel Sambuc *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
1238*0a6a1f1dSLionel Sambuc }
1239*0a6a1f1dSLionel Sambuc return opt;
1240*0a6a1f1dSLionel Sambuc }
1241*0a6a1f1dSLionel Sambuc
1242*0a6a1f1dSLionel Sambuc
1243*0a6a1f1dSLionel Sambuc /*
1244*0a6a1f1dSLionel Sambuc ** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
1245*0a6a1f1dSLionel Sambuc ** The final 'if' handles the case when 'size' is larger than
1246*0a6a1f1dSLionel Sambuc ** the size of a Lua integer, correcting the extra sign-extension
1247*0a6a1f1dSLionel Sambuc ** bytes if necessary (by default they would be zeros).
1248*0a6a1f1dSLionel Sambuc */
packint(luaL_Buffer * b,lua_Unsigned n,int islittle,int size,int neg)1249*0a6a1f1dSLionel Sambuc static void packint (luaL_Buffer *b, lua_Unsigned n,
1250*0a6a1f1dSLionel Sambuc int islittle, int size, int neg) {
1251*0a6a1f1dSLionel Sambuc char *buff = luaL_prepbuffsize(b, size);
1252*0a6a1f1dSLionel Sambuc int i;
1253*0a6a1f1dSLionel Sambuc buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
1254*0a6a1f1dSLionel Sambuc for (i = 1; i < size; i++) {
1255*0a6a1f1dSLionel Sambuc n >>= NB;
1256*0a6a1f1dSLionel Sambuc buff[islittle ? i : size - 1 - i] = (char)(n & MC);
1257*0a6a1f1dSLionel Sambuc }
1258*0a6a1f1dSLionel Sambuc if (neg && size > SZINT) { /* negative number need sign extension? */
1259*0a6a1f1dSLionel Sambuc for (i = SZINT; i < size; i++) /* correct extra bytes */
1260*0a6a1f1dSLionel Sambuc buff[islittle ? i : size - 1 - i] = (char)MC;
1261*0a6a1f1dSLionel Sambuc }
1262*0a6a1f1dSLionel Sambuc luaL_addsize(b, size); /* add result to buffer */
1263*0a6a1f1dSLionel Sambuc }
1264*0a6a1f1dSLionel Sambuc
1265*0a6a1f1dSLionel Sambuc
1266*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1267*0a6a1f1dSLionel Sambuc /*
1268*0a6a1f1dSLionel Sambuc ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
1269*0a6a1f1dSLionel Sambuc ** given 'islittle' is different from native endianness.
1270*0a6a1f1dSLionel Sambuc */
copywithendian(volatile char * dest,volatile const char * src,int size,int islittle)1271*0a6a1f1dSLionel Sambuc static void copywithendian (volatile char *dest, volatile const char *src,
1272*0a6a1f1dSLionel Sambuc int size, int islittle) {
1273*0a6a1f1dSLionel Sambuc if (islittle == nativeendian.little) {
1274*0a6a1f1dSLionel Sambuc while (size-- != 0)
1275*0a6a1f1dSLionel Sambuc *(dest++) = *(src++);
1276*0a6a1f1dSLionel Sambuc }
1277*0a6a1f1dSLionel Sambuc else {
1278*0a6a1f1dSLionel Sambuc dest += size - 1;
1279*0a6a1f1dSLionel Sambuc while (size-- != 0)
1280*0a6a1f1dSLionel Sambuc *(dest--) = *(src++);
1281*0a6a1f1dSLionel Sambuc }
1282*0a6a1f1dSLionel Sambuc }
1283*0a6a1f1dSLionel Sambuc #endif
1284*0a6a1f1dSLionel Sambuc
1285*0a6a1f1dSLionel Sambuc
str_pack(lua_State * L)1286*0a6a1f1dSLionel Sambuc static int str_pack (lua_State *L) {
1287*0a6a1f1dSLionel Sambuc luaL_Buffer b;
1288*0a6a1f1dSLionel Sambuc Header h;
1289*0a6a1f1dSLionel Sambuc const char *fmt = luaL_checkstring(L, 1); /* format string */
1290*0a6a1f1dSLionel Sambuc int arg = 1; /* current argument to pack */
1291*0a6a1f1dSLionel Sambuc size_t totalsize = 0; /* accumulate total size of result */
1292*0a6a1f1dSLionel Sambuc initheader(L, &h);
1293*0a6a1f1dSLionel Sambuc lua_pushnil(L); /* mark to separate arguments from string buffer */
1294*0a6a1f1dSLionel Sambuc luaL_buffinit(L, &b);
1295*0a6a1f1dSLionel Sambuc while (*fmt != '\0') {
1296*0a6a1f1dSLionel Sambuc int size, ntoalign;
1297*0a6a1f1dSLionel Sambuc KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
1298*0a6a1f1dSLionel Sambuc totalsize += ntoalign + size;
1299*0a6a1f1dSLionel Sambuc while (ntoalign-- > 0)
1300*0a6a1f1dSLionel Sambuc luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
1301*0a6a1f1dSLionel Sambuc arg++;
1302*0a6a1f1dSLionel Sambuc switch (opt) {
1303*0a6a1f1dSLionel Sambuc case Kint: { /* signed integers */
1304*0a6a1f1dSLionel Sambuc lua_Integer n = luaL_checkinteger(L, arg);
1305*0a6a1f1dSLionel Sambuc if (size < SZINT) { /* need overflow check? */
1306*0a6a1f1dSLionel Sambuc lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
1307*0a6a1f1dSLionel Sambuc luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
1308*0a6a1f1dSLionel Sambuc }
1309*0a6a1f1dSLionel Sambuc packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
1310*0a6a1f1dSLionel Sambuc break;
1311*0a6a1f1dSLionel Sambuc }
1312*0a6a1f1dSLionel Sambuc case Kuint: { /* unsigned integers */
1313*0a6a1f1dSLionel Sambuc lua_Integer n = luaL_checkinteger(L, arg);
1314*0a6a1f1dSLionel Sambuc if (size < SZINT) /* need overflow check? */
1315*0a6a1f1dSLionel Sambuc luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
1316*0a6a1f1dSLionel Sambuc arg, "unsigned overflow");
1317*0a6a1f1dSLionel Sambuc packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
1318*0a6a1f1dSLionel Sambuc break;
1319*0a6a1f1dSLionel Sambuc }
1320*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1321*0a6a1f1dSLionel Sambuc case Kfloat: { /* floating-point options */
1322*0a6a1f1dSLionel Sambuc volatile Ftypes u;
1323*0a6a1f1dSLionel Sambuc char *buff = luaL_prepbuffsize(&b, size);
1324*0a6a1f1dSLionel Sambuc lua_Number n = luaL_checknumber(L, arg); /* get argument */
1325*0a6a1f1dSLionel Sambuc if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */
1326*0a6a1f1dSLionel Sambuc else if (size == sizeof(u.d)) u.d = (double)n;
1327*0a6a1f1dSLionel Sambuc else u.n = n;
1328*0a6a1f1dSLionel Sambuc /* move 'u' to final result, correcting endianness if needed */
1329*0a6a1f1dSLionel Sambuc copywithendian(buff, u.buff, size, h.islittle);
1330*0a6a1f1dSLionel Sambuc luaL_addsize(&b, size);
1331*0a6a1f1dSLionel Sambuc break;
1332*0a6a1f1dSLionel Sambuc }
1333*0a6a1f1dSLionel Sambuc #endif
1334*0a6a1f1dSLionel Sambuc case Kchar: { /* fixed-size string */
1335*0a6a1f1dSLionel Sambuc size_t len;
1336*0a6a1f1dSLionel Sambuc const char *s = luaL_checklstring(L, arg, &len);
1337*0a6a1f1dSLionel Sambuc luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
1338*0a6a1f1dSLionel Sambuc luaL_addlstring(&b, s, size);
1339*0a6a1f1dSLionel Sambuc break;
1340*0a6a1f1dSLionel Sambuc }
1341*0a6a1f1dSLionel Sambuc case Kstring: { /* strings with length count */
1342*0a6a1f1dSLionel Sambuc size_t len;
1343*0a6a1f1dSLionel Sambuc const char *s = luaL_checklstring(L, arg, &len);
1344*0a6a1f1dSLionel Sambuc luaL_argcheck(L, size >= (int)sizeof(size_t) ||
1345*0a6a1f1dSLionel Sambuc len < ((size_t)1 << (size * NB)),
1346*0a6a1f1dSLionel Sambuc arg, "string length does not fit in given size");
1347*0a6a1f1dSLionel Sambuc packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
1348*0a6a1f1dSLionel Sambuc luaL_addlstring(&b, s, len);
1349*0a6a1f1dSLionel Sambuc totalsize += len;
1350*0a6a1f1dSLionel Sambuc break;
1351*0a6a1f1dSLionel Sambuc }
1352*0a6a1f1dSLionel Sambuc case Kzstr: { /* zero-terminated string */
1353*0a6a1f1dSLionel Sambuc size_t len;
1354*0a6a1f1dSLionel Sambuc const char *s = luaL_checklstring(L, arg, &len);
1355*0a6a1f1dSLionel Sambuc luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
1356*0a6a1f1dSLionel Sambuc luaL_addlstring(&b, s, len);
1357*0a6a1f1dSLionel Sambuc luaL_addchar(&b, '\0'); /* add zero at the end */
1358*0a6a1f1dSLionel Sambuc totalsize += len + 1;
1359*0a6a1f1dSLionel Sambuc break;
1360*0a6a1f1dSLionel Sambuc }
1361*0a6a1f1dSLionel Sambuc case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */
1362*0a6a1f1dSLionel Sambuc case Kpaddalign: case Knop:
1363*0a6a1f1dSLionel Sambuc arg--; /* undo increment */
1364*0a6a1f1dSLionel Sambuc break;
1365*0a6a1f1dSLionel Sambuc }
1366*0a6a1f1dSLionel Sambuc }
1367*0a6a1f1dSLionel Sambuc luaL_pushresult(&b);
1368*0a6a1f1dSLionel Sambuc return 1;
1369*0a6a1f1dSLionel Sambuc }
1370*0a6a1f1dSLionel Sambuc
1371*0a6a1f1dSLionel Sambuc
str_packsize(lua_State * L)1372*0a6a1f1dSLionel Sambuc static int str_packsize (lua_State *L) {
1373*0a6a1f1dSLionel Sambuc Header h;
1374*0a6a1f1dSLionel Sambuc const char *fmt = luaL_checkstring(L, 1); /* format string */
1375*0a6a1f1dSLionel Sambuc size_t totalsize = 0; /* accumulate total size of result */
1376*0a6a1f1dSLionel Sambuc initheader(L, &h);
1377*0a6a1f1dSLionel Sambuc while (*fmt != '\0') {
1378*0a6a1f1dSLionel Sambuc int size, ntoalign;
1379*0a6a1f1dSLionel Sambuc KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
1380*0a6a1f1dSLionel Sambuc size += ntoalign; /* total space used by option */
1381*0a6a1f1dSLionel Sambuc luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
1382*0a6a1f1dSLionel Sambuc "format result too large");
1383*0a6a1f1dSLionel Sambuc totalsize += size;
1384*0a6a1f1dSLionel Sambuc switch (opt) {
1385*0a6a1f1dSLionel Sambuc case Kstring: /* strings with length count */
1386*0a6a1f1dSLionel Sambuc case Kzstr: /* zero-terminated string */
1387*0a6a1f1dSLionel Sambuc luaL_argerror(L, 1, "variable-length format");
1388*0a6a1f1dSLionel Sambuc break;
1389*0a6a1f1dSLionel Sambuc default: break;
1390*0a6a1f1dSLionel Sambuc }
1391*0a6a1f1dSLionel Sambuc }
1392*0a6a1f1dSLionel Sambuc lua_pushinteger(L, (lua_Integer)totalsize);
1393*0a6a1f1dSLionel Sambuc return 1;
1394*0a6a1f1dSLionel Sambuc }
1395*0a6a1f1dSLionel Sambuc
1396*0a6a1f1dSLionel Sambuc
1397*0a6a1f1dSLionel Sambuc /*
1398*0a6a1f1dSLionel Sambuc ** Unpack an integer with 'size' bytes and 'islittle' endianness.
1399*0a6a1f1dSLionel Sambuc ** If size is smaller than the size of a Lua integer and integer
1400*0a6a1f1dSLionel Sambuc ** is signed, must do sign extension (propagating the sign to the
1401*0a6a1f1dSLionel Sambuc ** higher bits); if size is larger than the size of a Lua integer,
1402*0a6a1f1dSLionel Sambuc ** it must check the unread bytes to see whether they do not cause an
1403*0a6a1f1dSLionel Sambuc ** overflow.
1404*0a6a1f1dSLionel Sambuc */
unpackint(lua_State * L,const char * str,int islittle,int size,int issigned)1405*0a6a1f1dSLionel Sambuc static lua_Integer unpackint (lua_State *L, const char *str,
1406*0a6a1f1dSLionel Sambuc int islittle, int size, int issigned) {
1407*0a6a1f1dSLionel Sambuc lua_Unsigned res = 0;
1408*0a6a1f1dSLionel Sambuc int i;
1409*0a6a1f1dSLionel Sambuc int limit = (size <= SZINT) ? size : SZINT;
1410*0a6a1f1dSLionel Sambuc for (i = limit - 1; i >= 0; i--) {
1411*0a6a1f1dSLionel Sambuc res <<= NB;
1412*0a6a1f1dSLionel Sambuc res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];
1413*0a6a1f1dSLionel Sambuc }
1414*0a6a1f1dSLionel Sambuc if (size < SZINT) { /* real size smaller than lua_Integer? */
1415*0a6a1f1dSLionel Sambuc if (issigned) { /* needs sign extension? */
1416*0a6a1f1dSLionel Sambuc lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
1417*0a6a1f1dSLionel Sambuc res = ((res ^ mask) - mask); /* do sign extension */
1418*0a6a1f1dSLionel Sambuc }
1419*0a6a1f1dSLionel Sambuc }
1420*0a6a1f1dSLionel Sambuc else if (size > SZINT) { /* must check unread bytes */
1421*0a6a1f1dSLionel Sambuc int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
1422*0a6a1f1dSLionel Sambuc for (i = limit; i < size; i++) {
1423*0a6a1f1dSLionel Sambuc if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
1424*0a6a1f1dSLionel Sambuc luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
1425*0a6a1f1dSLionel Sambuc }
1426*0a6a1f1dSLionel Sambuc }
1427*0a6a1f1dSLionel Sambuc return (lua_Integer)res;
1428*0a6a1f1dSLionel Sambuc }
1429*0a6a1f1dSLionel Sambuc
1430*0a6a1f1dSLionel Sambuc
str_unpack(lua_State * L)1431*0a6a1f1dSLionel Sambuc static int str_unpack (lua_State *L) {
1432*0a6a1f1dSLionel Sambuc Header h;
1433*0a6a1f1dSLionel Sambuc const char *fmt = luaL_checkstring(L, 1);
1434*0a6a1f1dSLionel Sambuc size_t ld;
1435*0a6a1f1dSLionel Sambuc const char *data = luaL_checklstring(L, 2, &ld);
1436*0a6a1f1dSLionel Sambuc size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;
1437*0a6a1f1dSLionel Sambuc int n = 0; /* number of results */
1438*0a6a1f1dSLionel Sambuc luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
1439*0a6a1f1dSLionel Sambuc initheader(L, &h);
1440*0a6a1f1dSLionel Sambuc while (*fmt != '\0') {
1441*0a6a1f1dSLionel Sambuc int size, ntoalign;
1442*0a6a1f1dSLionel Sambuc KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
1443*0a6a1f1dSLionel Sambuc if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
1444*0a6a1f1dSLionel Sambuc luaL_argerror(L, 2, "data string too short");
1445*0a6a1f1dSLionel Sambuc pos += ntoalign; /* skip alignment */
1446*0a6a1f1dSLionel Sambuc /* stack space for item + next position */
1447*0a6a1f1dSLionel Sambuc luaL_checkstack(L, 2, "too many results");
1448*0a6a1f1dSLionel Sambuc n++;
1449*0a6a1f1dSLionel Sambuc switch (opt) {
1450*0a6a1f1dSLionel Sambuc case Kint:
1451*0a6a1f1dSLionel Sambuc case Kuint: {
1452*0a6a1f1dSLionel Sambuc lua_Integer res = unpackint(L, data + pos, h.islittle, size,
1453*0a6a1f1dSLionel Sambuc (opt == Kint));
1454*0a6a1f1dSLionel Sambuc lua_pushinteger(L, res);
1455*0a6a1f1dSLionel Sambuc break;
1456*0a6a1f1dSLionel Sambuc }
1457*0a6a1f1dSLionel Sambuc #ifndef _KERNEL
1458*0a6a1f1dSLionel Sambuc case Kfloat: {
1459*0a6a1f1dSLionel Sambuc volatile Ftypes u;
1460*0a6a1f1dSLionel Sambuc lua_Number num;
1461*0a6a1f1dSLionel Sambuc copywithendian(u.buff, data + pos, size, h.islittle);
1462*0a6a1f1dSLionel Sambuc if (size == sizeof(u.f)) num = (lua_Number)u.f;
1463*0a6a1f1dSLionel Sambuc else if (size == sizeof(u.d)) num = (lua_Number)u.d;
1464*0a6a1f1dSLionel Sambuc else num = u.n;
1465*0a6a1f1dSLionel Sambuc lua_pushnumber(L, num);
1466*0a6a1f1dSLionel Sambuc break;
1467*0a6a1f1dSLionel Sambuc }
1468*0a6a1f1dSLionel Sambuc #endif
1469*0a6a1f1dSLionel Sambuc case Kchar: {
1470*0a6a1f1dSLionel Sambuc lua_pushlstring(L, data + pos, size);
1471*0a6a1f1dSLionel Sambuc break;
1472*0a6a1f1dSLionel Sambuc }
1473*0a6a1f1dSLionel Sambuc case Kstring: {
1474*0a6a1f1dSLionel Sambuc size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
1475*0a6a1f1dSLionel Sambuc luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short");
1476*0a6a1f1dSLionel Sambuc lua_pushlstring(L, data + pos + size, len);
1477*0a6a1f1dSLionel Sambuc pos += len; /* skip string */
1478*0a6a1f1dSLionel Sambuc break;
1479*0a6a1f1dSLionel Sambuc }
1480*0a6a1f1dSLionel Sambuc case Kzstr: {
1481*0a6a1f1dSLionel Sambuc size_t len = (int)strlen(data + pos);
1482*0a6a1f1dSLionel Sambuc lua_pushlstring(L, data + pos, len);
1483*0a6a1f1dSLionel Sambuc pos += len + 1; /* skip string plus final '\0' */
1484*0a6a1f1dSLionel Sambuc break;
1485*0a6a1f1dSLionel Sambuc }
1486*0a6a1f1dSLionel Sambuc case Kpaddalign: case Kpadding: case Knop:
1487*0a6a1f1dSLionel Sambuc n--; /* undo increment */
1488*0a6a1f1dSLionel Sambuc break;
1489*0a6a1f1dSLionel Sambuc }
1490*0a6a1f1dSLionel Sambuc pos += size;
1491*0a6a1f1dSLionel Sambuc }
1492*0a6a1f1dSLionel Sambuc lua_pushinteger(L, pos + 1); /* next position */
1493*0a6a1f1dSLionel Sambuc return n + 1;
1494*0a6a1f1dSLionel Sambuc }
1495*0a6a1f1dSLionel Sambuc
1496*0a6a1f1dSLionel Sambuc /* }====================================================== */
1497*0a6a1f1dSLionel Sambuc
149811be35a1SLionel Sambuc
149911be35a1SLionel Sambuc static const luaL_Reg strlib[] = {
150011be35a1SLionel Sambuc {"byte", str_byte},
150111be35a1SLionel Sambuc {"char", str_char},
150211be35a1SLionel Sambuc {"dump", str_dump},
150311be35a1SLionel Sambuc {"find", str_find},
150411be35a1SLionel Sambuc {"format", str_format},
150511be35a1SLionel Sambuc {"gmatch", gmatch},
150611be35a1SLionel Sambuc {"gsub", str_gsub},
150711be35a1SLionel Sambuc {"len", str_len},
150811be35a1SLionel Sambuc {"lower", str_lower},
150911be35a1SLionel Sambuc {"match", str_match},
151011be35a1SLionel Sambuc {"rep", str_rep},
151111be35a1SLionel Sambuc {"reverse", str_reverse},
151211be35a1SLionel Sambuc {"sub", str_sub},
151311be35a1SLionel Sambuc {"upper", str_upper},
1514*0a6a1f1dSLionel Sambuc {"pack", str_pack},
1515*0a6a1f1dSLionel Sambuc {"packsize", str_packsize},
1516*0a6a1f1dSLionel Sambuc {"unpack", str_unpack},
151711be35a1SLionel Sambuc {NULL, NULL}
151811be35a1SLionel Sambuc };
151911be35a1SLionel Sambuc
152011be35a1SLionel Sambuc
createmetatable(lua_State * L)152111be35a1SLionel Sambuc static void createmetatable (lua_State *L) {
1522*0a6a1f1dSLionel Sambuc lua_createtable(L, 0, 1); /* table to be metatable for strings */
152311be35a1SLionel Sambuc lua_pushliteral(L, ""); /* dummy string */
1524*0a6a1f1dSLionel Sambuc lua_pushvalue(L, -2); /* copy table */
1525*0a6a1f1dSLionel Sambuc lua_setmetatable(L, -2); /* set table as metatable for strings */
152611be35a1SLionel Sambuc lua_pop(L, 1); /* pop dummy string */
1527*0a6a1f1dSLionel Sambuc lua_pushvalue(L, -2); /* get string library */
1528*0a6a1f1dSLionel Sambuc lua_setfield(L, -2, "__index"); /* metatable.__index = string */
152911be35a1SLionel Sambuc lua_pop(L, 1); /* pop metatable */
153011be35a1SLionel Sambuc }
153111be35a1SLionel Sambuc
153211be35a1SLionel Sambuc
153311be35a1SLionel Sambuc /*
153411be35a1SLionel Sambuc ** Open string library
153511be35a1SLionel Sambuc */
luaopen_string(lua_State * L)1536*0a6a1f1dSLionel Sambuc LUAMOD_API int luaopen_string (lua_State *L) {
1537*0a6a1f1dSLionel Sambuc luaL_newlib(L, strlib);
153811be35a1SLionel Sambuc createmetatable(L);
153911be35a1SLionel Sambuc return 1;
154011be35a1SLionel Sambuc }
154111be35a1SLionel Sambuc
1542