xref: /minix3/external/mit/lua/dist/src/lstrlib.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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