Mercurial > vba-clojure
diff src/lua/lstrlib.c @ 11:27763b933818
raise lua sources up one level
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 11:07:39 -0600 |
parents | src/lua/src/lstrlib.c@f9f4f1b99eed |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/lua/lstrlib.c Sat Mar 03 11:07:39 2012 -0600 1.3 @@ -0,0 +1,869 @@ 1.4 +/* 1.5 +** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ 1.6 +** Standard library for string operations and pattern-matching 1.7 +** See Copyright Notice in lua.h 1.8 +*/ 1.9 + 1.10 + 1.11 +#include <ctype.h> 1.12 +#include <stddef.h> 1.13 +#include <stdio.h> 1.14 +#include <stdlib.h> 1.15 +#include <string.h> 1.16 + 1.17 +#define lstrlib_c 1.18 +#define LUA_LIB 1.19 + 1.20 +#include "lua.h" 1.21 + 1.22 +#include "lauxlib.h" 1.23 +#include "lualib.h" 1.24 + 1.25 + 1.26 +/* macro to `unsign' a character */ 1.27 +#define uchar(c) ((unsigned char)(c)) 1.28 + 1.29 + 1.30 + 1.31 +static int str_len (lua_State *L) { 1.32 + size_t l; 1.33 + luaL_checklstring(L, 1, &l); 1.34 + lua_pushinteger(L, l); 1.35 + return 1; 1.36 +} 1.37 + 1.38 + 1.39 +static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { 1.40 + /* relative string position: negative means back from end */ 1.41 + if (pos < 0) pos += (ptrdiff_t)len + 1; 1.42 + return (pos >= 0) ? pos : 0; 1.43 +} 1.44 + 1.45 + 1.46 +static int str_sub (lua_State *L) { 1.47 + size_t l; 1.48 + const char *s = luaL_checklstring(L, 1, &l); 1.49 + ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); 1.50 + ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); 1.51 + if (start < 1) start = 1; 1.52 + if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; 1.53 + if (start <= end) 1.54 + lua_pushlstring(L, s+start-1, end-start+1); 1.55 + else lua_pushliteral(L, ""); 1.56 + return 1; 1.57 +} 1.58 + 1.59 + 1.60 +static int str_reverse (lua_State *L) { 1.61 + size_t l; 1.62 + luaL_Buffer b; 1.63 + const char *s = luaL_checklstring(L, 1, &l); 1.64 + luaL_buffinit(L, &b); 1.65 + while (l--) luaL_addchar(&b, s[l]); 1.66 + luaL_pushresult(&b); 1.67 + return 1; 1.68 +} 1.69 + 1.70 + 1.71 +static int str_lower (lua_State *L) { 1.72 + size_t l; 1.73 + size_t i; 1.74 + luaL_Buffer b; 1.75 + const char *s = luaL_checklstring(L, 1, &l); 1.76 + luaL_buffinit(L, &b); 1.77 + for (i=0; i<l; i++) 1.78 + luaL_addchar(&b, tolower(uchar(s[i]))); 1.79 + luaL_pushresult(&b); 1.80 + return 1; 1.81 +} 1.82 + 1.83 + 1.84 +static int str_upper (lua_State *L) { 1.85 + size_t l; 1.86 + size_t i; 1.87 + luaL_Buffer b; 1.88 + const char *s = luaL_checklstring(L, 1, &l); 1.89 + luaL_buffinit(L, &b); 1.90 + for (i=0; i<l; i++) 1.91 + luaL_addchar(&b, toupper(uchar(s[i]))); 1.92 + luaL_pushresult(&b); 1.93 + return 1; 1.94 +} 1.95 + 1.96 +static int str_rep (lua_State *L) { 1.97 + size_t l; 1.98 + luaL_Buffer b; 1.99 + const char *s = luaL_checklstring(L, 1, &l); 1.100 + int n = luaL_checkint(L, 2); 1.101 + luaL_buffinit(L, &b); 1.102 + while (n-- > 0) 1.103 + luaL_addlstring(&b, s, l); 1.104 + luaL_pushresult(&b); 1.105 + return 1; 1.106 +} 1.107 + 1.108 + 1.109 +static int str_byte (lua_State *L) { 1.110 + size_t l; 1.111 + const char *s = luaL_checklstring(L, 1, &l); 1.112 + ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); 1.113 + ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); 1.114 + int n, i; 1.115 + if (posi <= 0) posi = 1; 1.116 + if ((size_t)pose > l) pose = l; 1.117 + if (posi > pose) return 0; /* empty interval; return no values */ 1.118 + n = (int)(pose - posi + 1); 1.119 + if (posi + n <= pose) /* overflow? */ 1.120 + luaL_error(L, "string slice too long"); 1.121 + luaL_checkstack(L, n, "string slice too long"); 1.122 + for (i=0; i<n; i++) 1.123 + lua_pushinteger(L, uchar(s[posi+i-1])); 1.124 + return n; 1.125 +} 1.126 + 1.127 + 1.128 +static int str_char (lua_State *L) { 1.129 + int n = lua_gettop(L); /* number of arguments */ 1.130 + int i; 1.131 + luaL_Buffer b; 1.132 + luaL_buffinit(L, &b); 1.133 + for (i=1; i<=n; i++) { 1.134 + int c = luaL_checkint(L, i); 1.135 + luaL_argcheck(L, uchar(c) == c, i, "invalid value"); 1.136 + luaL_addchar(&b, uchar(c)); 1.137 + } 1.138 + luaL_pushresult(&b); 1.139 + return 1; 1.140 +} 1.141 + 1.142 + 1.143 +static int writer (lua_State *L, const void* b, size_t size, void* B) { 1.144 + (void)L; 1.145 + luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); 1.146 + return 0; 1.147 +} 1.148 + 1.149 + 1.150 +static int str_dump (lua_State *L) { 1.151 + luaL_Buffer b; 1.152 + luaL_checktype(L, 1, LUA_TFUNCTION); 1.153 + lua_settop(L, 1); 1.154 + luaL_buffinit(L,&b); 1.155 + if (lua_dump(L, writer, &b) != 0) 1.156 + luaL_error(L, "unable to dump given function"); 1.157 + luaL_pushresult(&b); 1.158 + return 1; 1.159 +} 1.160 + 1.161 + 1.162 + 1.163 +/* 1.164 +** {====================================================== 1.165 +** PATTERN MATCHING 1.166 +** ======================================================= 1.167 +*/ 1.168 + 1.169 + 1.170 +#define CAP_UNFINISHED (-1) 1.171 +#define CAP_POSITION (-2) 1.172 + 1.173 +typedef struct MatchState { 1.174 + const char *src_init; /* init of source string */ 1.175 + const char *src_end; /* end (`\0') of source string */ 1.176 + lua_State *L; 1.177 + int level; /* total number of captures (finished or unfinished) */ 1.178 + struct { 1.179 + const char *init; 1.180 + ptrdiff_t len; 1.181 + } capture[LUA_MAXCAPTURES]; 1.182 +} MatchState; 1.183 + 1.184 + 1.185 +#define L_ESC '%' 1.186 +#define SPECIALS "^$*+?.([%-" 1.187 + 1.188 + 1.189 +static int check_capture (MatchState *ms, int l) { 1.190 + l -= '1'; 1.191 + if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) 1.192 + return luaL_error(ms->L, "invalid capture index"); 1.193 + return l; 1.194 +} 1.195 + 1.196 + 1.197 +static int capture_to_close (MatchState *ms) { 1.198 + int level = ms->level; 1.199 + for (level--; level>=0; level--) 1.200 + if (ms->capture[level].len == CAP_UNFINISHED) return level; 1.201 + return luaL_error(ms->L, "invalid pattern capture"); 1.202 +} 1.203 + 1.204 + 1.205 +static const char *classend (MatchState *ms, const char *p) { 1.206 + switch (*p++) { 1.207 + case L_ESC: { 1.208 + if (*p == '\0') 1.209 + luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); 1.210 + return p+1; 1.211 + } 1.212 + case '[': { 1.213 + if (*p == '^') p++; 1.214 + do { /* look for a `]' */ 1.215 + if (*p == '\0') 1.216 + luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); 1.217 + if (*(p++) == L_ESC && *p != '\0') 1.218 + p++; /* skip escapes (e.g. `%]') */ 1.219 + } while (*p != ']'); 1.220 + return p+1; 1.221 + } 1.222 + default: { 1.223 + return p; 1.224 + } 1.225 + } 1.226 +} 1.227 + 1.228 + 1.229 +static int match_class (int c, int cl) { 1.230 + int res; 1.231 + switch (tolower(cl)) { 1.232 + case 'a' : res = isalpha(c); break; 1.233 + case 'c' : res = iscntrl(c); break; 1.234 + case 'd' : res = isdigit(c); break; 1.235 + case 'l' : res = islower(c); break; 1.236 + case 'p' : res = ispunct(c); break; 1.237 + case 's' : res = isspace(c); break; 1.238 + case 'u' : res = isupper(c); break; 1.239 + case 'w' : res = isalnum(c); break; 1.240 + case 'x' : res = isxdigit(c); break; 1.241 + case 'z' : res = (c == 0); break; 1.242 + default: return (cl == c); 1.243 + } 1.244 + return (islower(cl) ? res : !res); 1.245 +} 1.246 + 1.247 + 1.248 +static int matchbracketclass (int c, const char *p, const char *ec) { 1.249 + int sig = 1; 1.250 + if (*(p+1) == '^') { 1.251 + sig = 0; 1.252 + p++; /* skip the `^' */ 1.253 + } 1.254 + while (++p < ec) { 1.255 + if (*p == L_ESC) { 1.256 + p++; 1.257 + if (match_class(c, uchar(*p))) 1.258 + return sig; 1.259 + } 1.260 + else if ((*(p+1) == '-') && (p+2 < ec)) { 1.261 + p+=2; 1.262 + if (uchar(*(p-2)) <= c && c <= uchar(*p)) 1.263 + return sig; 1.264 + } 1.265 + else if (uchar(*p) == c) return sig; 1.266 + } 1.267 + return !sig; 1.268 +} 1.269 + 1.270 + 1.271 +static int singlematch (int c, const char *p, const char *ep) { 1.272 + switch (*p) { 1.273 + case '.': return 1; /* matches any char */ 1.274 + case L_ESC: return match_class(c, uchar(*(p+1))); 1.275 + case '[': return matchbracketclass(c, p, ep-1); 1.276 + default: return (uchar(*p) == c); 1.277 + } 1.278 +} 1.279 + 1.280 + 1.281 +static const char *match (MatchState *ms, const char *s, const char *p); 1.282 + 1.283 + 1.284 +static const char *matchbalance (MatchState *ms, const char *s, 1.285 + const char *p) { 1.286 + if (*p == 0 || *(p+1) == 0) 1.287 + luaL_error(ms->L, "unbalanced pattern"); 1.288 + if (*s != *p) return NULL; 1.289 + else { 1.290 + int b = *p; 1.291 + int e = *(p+1); 1.292 + int cont = 1; 1.293 + while (++s < ms->src_end) { 1.294 + if (*s == e) { 1.295 + if (--cont == 0) return s+1; 1.296 + } 1.297 + else if (*s == b) cont++; 1.298 + } 1.299 + } 1.300 + return NULL; /* string ends out of balance */ 1.301 +} 1.302 + 1.303 + 1.304 +static const char *max_expand (MatchState *ms, const char *s, 1.305 + const char *p, const char *ep) { 1.306 + ptrdiff_t i = 0; /* counts maximum expand for item */ 1.307 + while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) 1.308 + i++; 1.309 + /* keeps trying to match with the maximum repetitions */ 1.310 + while (i>=0) { 1.311 + const char *res = match(ms, (s+i), ep+1); 1.312 + if (res) return res; 1.313 + i--; /* else didn't match; reduce 1 repetition to try again */ 1.314 + } 1.315 + return NULL; 1.316 +} 1.317 + 1.318 + 1.319 +static const char *min_expand (MatchState *ms, const char *s, 1.320 + const char *p, const char *ep) { 1.321 + for (;;) { 1.322 + const char *res = match(ms, s, ep+1); 1.323 + if (res != NULL) 1.324 + return res; 1.325 + else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) 1.326 + s++; /* try with one more repetition */ 1.327 + else return NULL; 1.328 + } 1.329 +} 1.330 + 1.331 + 1.332 +static const char *start_capture (MatchState *ms, const char *s, 1.333 + const char *p, int what) { 1.334 + const char *res; 1.335 + int level = ms->level; 1.336 + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); 1.337 + ms->capture[level].init = s; 1.338 + ms->capture[level].len = what; 1.339 + ms->level = level+1; 1.340 + if ((res=match(ms, s, p)) == NULL) /* match failed? */ 1.341 + ms->level--; /* undo capture */ 1.342 + return res; 1.343 +} 1.344 + 1.345 + 1.346 +static const char *end_capture (MatchState *ms, const char *s, 1.347 + const char *p) { 1.348 + int l = capture_to_close(ms); 1.349 + const char *res; 1.350 + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ 1.351 + if ((res = match(ms, s, p)) == NULL) /* match failed? */ 1.352 + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ 1.353 + return res; 1.354 +} 1.355 + 1.356 + 1.357 +static const char *match_capture (MatchState *ms, const char *s, int l) { 1.358 + size_t len; 1.359 + l = check_capture(ms, l); 1.360 + len = ms->capture[l].len; 1.361 + if ((size_t)(ms->src_end-s) >= len && 1.362 + memcmp(ms->capture[l].init, s, len) == 0) 1.363 + return s+len; 1.364 + else return NULL; 1.365 +} 1.366 + 1.367 + 1.368 +static const char *match (MatchState *ms, const char *s, const char *p) { 1.369 + init: /* using goto's to optimize tail recursion */ 1.370 + switch (*p) { 1.371 + case '(': { /* start capture */ 1.372 + if (*(p+1) == ')') /* position capture? */ 1.373 + return start_capture(ms, s, p+2, CAP_POSITION); 1.374 + else 1.375 + return start_capture(ms, s, p+1, CAP_UNFINISHED); 1.376 + } 1.377 + case ')': { /* end capture */ 1.378 + return end_capture(ms, s, p+1); 1.379 + } 1.380 + case L_ESC: { 1.381 + switch (*(p+1)) { 1.382 + case 'b': { /* balanced string? */ 1.383 + s = matchbalance(ms, s, p+2); 1.384 + if (s == NULL) return NULL; 1.385 + p+=4; goto init; /* else return match(ms, s, p+4); */ 1.386 + } 1.387 + case 'f': { /* frontier? */ 1.388 + const char *ep; char previous; 1.389 + p += 2; 1.390 + if (*p != '[') 1.391 + luaL_error(ms->L, "missing " LUA_QL("[") " after " 1.392 + LUA_QL("%%f") " in pattern"); 1.393 + ep = classend(ms, p); /* points to what is next */ 1.394 + previous = (s == ms->src_init) ? '\0' : *(s-1); 1.395 + if (matchbracketclass(uchar(previous), p, ep-1) || 1.396 + !matchbracketclass(uchar(*s), p, ep-1)) return NULL; 1.397 + p=ep; goto init; /* else return match(ms, s, ep); */ 1.398 + } 1.399 + default: { 1.400 + if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ 1.401 + s = match_capture(ms, s, uchar(*(p+1))); 1.402 + if (s == NULL) return NULL; 1.403 + p+=2; goto init; /* else return match(ms, s, p+2) */ 1.404 + } 1.405 + goto dflt; /* case default */ 1.406 + } 1.407 + } 1.408 + } 1.409 + case '\0': { /* end of pattern */ 1.410 + return s; /* match succeeded */ 1.411 + } 1.412 + case '$': { 1.413 + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ 1.414 + return (s == ms->src_end) ? s : NULL; /* check end of string */ 1.415 + else goto dflt; 1.416 + } 1.417 + default: dflt: { /* it is a pattern item */ 1.418 + const char *ep = classend(ms, p); /* points to what is next */ 1.419 + int m = s<ms->src_end && singlematch(uchar(*s), p, ep); 1.420 + switch (*ep) { 1.421 + case '?': { /* optional */ 1.422 + const char *res; 1.423 + if (m && ((res=match(ms, s+1, ep+1)) != NULL)) 1.424 + return res; 1.425 + p=ep+1; goto init; /* else return match(ms, s, ep+1); */ 1.426 + } 1.427 + case '*': { /* 0 or more repetitions */ 1.428 + return max_expand(ms, s, p, ep); 1.429 + } 1.430 + case '+': { /* 1 or more repetitions */ 1.431 + return (m ? max_expand(ms, s+1, p, ep) : NULL); 1.432 + } 1.433 + case '-': { /* 0 or more repetitions (minimum) */ 1.434 + return min_expand(ms, s, p, ep); 1.435 + } 1.436 + default: { 1.437 + if (!m) return NULL; 1.438 + s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ 1.439 + } 1.440 + } 1.441 + } 1.442 + } 1.443 +} 1.444 + 1.445 + 1.446 + 1.447 +static const char *lmemfind (const char *s1, size_t l1, 1.448 + const char *s2, size_t l2) { 1.449 + if (l2 == 0) return s1; /* empty strings are everywhere */ 1.450 + else if (l2 > l1) return NULL; /* avoids a negative `l1' */ 1.451 + else { 1.452 + const char *init; /* to search for a `*s2' inside `s1' */ 1.453 + l2--; /* 1st char will be checked by `memchr' */ 1.454 + l1 = l1-l2; /* `s2' cannot be found after that */ 1.455 + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { 1.456 + init++; /* 1st char is already checked */ 1.457 + if (memcmp(init, s2+1, l2) == 0) 1.458 + return init-1; 1.459 + else { /* correct `l1' and `s1' to try again */ 1.460 + l1 -= init-s1; 1.461 + s1 = init; 1.462 + } 1.463 + } 1.464 + return NULL; /* not found */ 1.465 + } 1.466 +} 1.467 + 1.468 + 1.469 +static void push_onecapture (MatchState *ms, int i, const char *s, 1.470 + const char *e) { 1.471 + if (i >= ms->level) { 1.472 + if (i == 0) /* ms->level == 0, too */ 1.473 + lua_pushlstring(ms->L, s, e - s); /* add whole match */ 1.474 + else 1.475 + luaL_error(ms->L, "invalid capture index"); 1.476 + } 1.477 + else { 1.478 + ptrdiff_t l = ms->capture[i].len; 1.479 + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); 1.480 + if (l == CAP_POSITION) 1.481 + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); 1.482 + else 1.483 + lua_pushlstring(ms->L, ms->capture[i].init, l); 1.484 + } 1.485 +} 1.486 + 1.487 + 1.488 +static int push_captures (MatchState *ms, const char *s, const char *e) { 1.489 + int i; 1.490 + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; 1.491 + luaL_checkstack(ms->L, nlevels, "too many captures"); 1.492 + for (i = 0; i < nlevels; i++) 1.493 + push_onecapture(ms, i, s, e); 1.494 + return nlevels; /* number of strings pushed */ 1.495 +} 1.496 + 1.497 + 1.498 +static int str_find_aux (lua_State *L, int find) { 1.499 + size_t l1, l2; 1.500 + const char *s = luaL_checklstring(L, 1, &l1); 1.501 + const char *p = luaL_checklstring(L, 2, &l2); 1.502 + ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; 1.503 + if (init < 0) init = 0; 1.504 + else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; 1.505 + if (find && (lua_toboolean(L, 4) || /* explicit request? */ 1.506 + strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ 1.507 + /* do a plain search */ 1.508 + const char *s2 = lmemfind(s+init, l1-init, p, l2); 1.509 + if (s2) { 1.510 + lua_pushinteger(L, s2-s+1); 1.511 + lua_pushinteger(L, s2-s+l2); 1.512 + return 2; 1.513 + } 1.514 + } 1.515 + else { 1.516 + MatchState ms; 1.517 + int anchor = (*p == '^') ? (p++, 1) : 0; 1.518 + const char *s1=s+init; 1.519 + ms.L = L; 1.520 + ms.src_init = s; 1.521 + ms.src_end = s+l1; 1.522 + do { 1.523 + const char *res; 1.524 + ms.level = 0; 1.525 + if ((res=match(&ms, s1, p)) != NULL) { 1.526 + if (find) { 1.527 + lua_pushinteger(L, s1-s+1); /* start */ 1.528 + lua_pushinteger(L, res-s); /* end */ 1.529 + return push_captures(&ms, NULL, 0) + 2; 1.530 + } 1.531 + else 1.532 + return push_captures(&ms, s1, res); 1.533 + } 1.534 + } while (s1++ < ms.src_end && !anchor); 1.535 + } 1.536 + lua_pushnil(L); /* not found */ 1.537 + return 1; 1.538 +} 1.539 + 1.540 + 1.541 +static int str_find (lua_State *L) { 1.542 + return str_find_aux(L, 1); 1.543 +} 1.544 + 1.545 + 1.546 +static int str_match (lua_State *L) { 1.547 + return str_find_aux(L, 0); 1.548 +} 1.549 + 1.550 + 1.551 +static int gmatch_aux (lua_State *L) { 1.552 + MatchState ms; 1.553 + size_t ls; 1.554 + const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); 1.555 + const char *p = lua_tostring(L, lua_upvalueindex(2)); 1.556 + const char *src; 1.557 + ms.L = L; 1.558 + ms.src_init = s; 1.559 + ms.src_end = s+ls; 1.560 + for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); 1.561 + src <= ms.src_end; 1.562 + src++) { 1.563 + const char *e; 1.564 + ms.level = 0; 1.565 + if ((e = match(&ms, src, p)) != NULL) { 1.566 + lua_Integer newstart = e-s; 1.567 + if (e == src) newstart++; /* empty match? go at least one position */ 1.568 + lua_pushinteger(L, newstart); 1.569 + lua_replace(L, lua_upvalueindex(3)); 1.570 + return push_captures(&ms, src, e); 1.571 + } 1.572 + } 1.573 + return 0; /* not found */ 1.574 +} 1.575 + 1.576 + 1.577 +static int gmatch (lua_State *L) { 1.578 + luaL_checkstring(L, 1); 1.579 + luaL_checkstring(L, 2); 1.580 + lua_settop(L, 2); 1.581 + lua_pushinteger(L, 0); 1.582 + lua_pushcclosure(L, gmatch_aux, 3); 1.583 + return 1; 1.584 +} 1.585 + 1.586 + 1.587 +static int gfind_nodef (lua_State *L) { 1.588 + return luaL_error(L, LUA_QL("string.gfind") " was renamed to " 1.589 + LUA_QL("string.gmatch")); 1.590 +} 1.591 + 1.592 + 1.593 +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, 1.594 + const char *e) { 1.595 + size_t l, i; 1.596 + const char *news = lua_tolstring(ms->L, 3, &l); 1.597 + for (i = 0; i < l; i++) { 1.598 + if (news[i] != L_ESC) 1.599 + luaL_addchar(b, news[i]); 1.600 + else { 1.601 + i++; /* skip ESC */ 1.602 + if (!isdigit(uchar(news[i]))) 1.603 + luaL_addchar(b, news[i]); 1.604 + else if (news[i] == '0') 1.605 + luaL_addlstring(b, s, e - s); 1.606 + else { 1.607 + push_onecapture(ms, news[i] - '1', s, e); 1.608 + luaL_addvalue(b); /* add capture to accumulated result */ 1.609 + } 1.610 + } 1.611 + } 1.612 +} 1.613 + 1.614 + 1.615 +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, 1.616 + const char *e) { 1.617 + lua_State *L = ms->L; 1.618 + switch (lua_type(L, 3)) { 1.619 + case LUA_TNUMBER: 1.620 + case LUA_TSTRING: { 1.621 + add_s(ms, b, s, e); 1.622 + return; 1.623 + } 1.624 + case LUA_TFUNCTION: { 1.625 + int n; 1.626 + lua_pushvalue(L, 3); 1.627 + n = push_captures(ms, s, e); 1.628 + lua_call(L, n, 1); 1.629 + break; 1.630 + } 1.631 + case LUA_TTABLE: { 1.632 + push_onecapture(ms, 0, s, e); 1.633 + lua_gettable(L, 3); 1.634 + break; 1.635 + } 1.636 + } 1.637 + if (!lua_toboolean(L, -1)) { /* nil or false? */ 1.638 + lua_pop(L, 1); 1.639 + lua_pushlstring(L, s, e - s); /* keep original text */ 1.640 + } 1.641 + else if (!lua_isstring(L, -1)) 1.642 + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); 1.643 + luaL_addvalue(b); /* add result to accumulator */ 1.644 +} 1.645 + 1.646 + 1.647 +static int str_gsub (lua_State *L) { 1.648 + size_t srcl; 1.649 + const char *src = luaL_checklstring(L, 1, &srcl); 1.650 + const char *p = luaL_checkstring(L, 2); 1.651 + int tr = lua_type(L, 3); 1.652 + int max_s = luaL_optint(L, 4, srcl+1); 1.653 + int anchor = (*p == '^') ? (p++, 1) : 0; 1.654 + int n = 0; 1.655 + MatchState ms; 1.656 + luaL_Buffer b; 1.657 + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || 1.658 + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, 1.659 + "string/function/table expected"); 1.660 + luaL_buffinit(L, &b); 1.661 + ms.L = L; 1.662 + ms.src_init = src; 1.663 + ms.src_end = src+srcl; 1.664 + while (n < max_s) { 1.665 + const char *e; 1.666 + ms.level = 0; 1.667 + e = match(&ms, src, p); 1.668 + if (e) { 1.669 + n++; 1.670 + add_value(&ms, &b, src, e); 1.671 + } 1.672 + if (e && e>src) /* non empty match? */ 1.673 + src = e; /* skip it */ 1.674 + else if (src < ms.src_end) 1.675 + luaL_addchar(&b, *src++); 1.676 + else break; 1.677 + if (anchor) break; 1.678 + } 1.679 + luaL_addlstring(&b, src, ms.src_end-src); 1.680 + luaL_pushresult(&b); 1.681 + lua_pushinteger(L, n); /* number of substitutions */ 1.682 + return 2; 1.683 +} 1.684 + 1.685 +/* }====================================================== */ 1.686 + 1.687 + 1.688 +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ 1.689 +#define MAX_ITEM 512 1.690 +/* valid flags in a format specification */ 1.691 +#define FLAGS "-+ #0" 1.692 +/* 1.693 +** maximum size of each format specification (such as '%-099.99d') 1.694 +** (+10 accounts for %99.99x plus margin of error) 1.695 +*/ 1.696 +#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) 1.697 + 1.698 + 1.699 +static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { 1.700 + size_t l; 1.701 + const char *s = luaL_checklstring(L, arg, &l); 1.702 + luaL_addchar(b, '"'); 1.703 + while (l--) { 1.704 + switch (*s) { 1.705 + case '"': case '\\': case '\n': { 1.706 + luaL_addchar(b, '\\'); 1.707 + luaL_addchar(b, *s); 1.708 + break; 1.709 + } 1.710 + case '\r': { 1.711 + luaL_addlstring(b, "\\r", 2); 1.712 + break; 1.713 + } 1.714 + case '\0': { 1.715 + luaL_addlstring(b, "\\000", 4); 1.716 + break; 1.717 + } 1.718 + default: { 1.719 + luaL_addchar(b, *s); 1.720 + break; 1.721 + } 1.722 + } 1.723 + s++; 1.724 + } 1.725 + luaL_addchar(b, '"'); 1.726 +} 1.727 + 1.728 +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { 1.729 + const char *p = strfrmt; 1.730 + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ 1.731 + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) 1.732 + luaL_error(L, "invalid format (repeated flags)"); 1.733 + if (isdigit(uchar(*p))) p++; /* skip width */ 1.734 + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 1.735 + if (*p == '.') { 1.736 + p++; 1.737 + if (isdigit(uchar(*p))) p++; /* skip precision */ 1.738 + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 1.739 + } 1.740 + if (isdigit(uchar(*p))) 1.741 + luaL_error(L, "invalid format (width or precision too long)"); 1.742 + *(form++) = '%'; 1.743 + strncpy(form, strfrmt, p - strfrmt + 1); 1.744 + form += p - strfrmt + 1; 1.745 + *form = '\0'; 1.746 + return p; 1.747 +} 1.748 + 1.749 + 1.750 +static void addintlen (char *form) { 1.751 + size_t l = strlen(form); 1.752 + char spec = form[l - 1]; 1.753 + strcpy(form + l - 1, LUA_INTFRMLEN); 1.754 + form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; 1.755 + form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; 1.756 +} 1.757 + 1.758 + 1.759 +static int str_format (lua_State *L) { 1.760 + int arg = 1; 1.761 + size_t sfl; 1.762 + const char *strfrmt = luaL_checklstring(L, arg, &sfl); 1.763 + const char *strfrmt_end = strfrmt+sfl; 1.764 + luaL_Buffer b; 1.765 + luaL_buffinit(L, &b); 1.766 + while (strfrmt < strfrmt_end) { 1.767 + if (*strfrmt != L_ESC) 1.768 + luaL_addchar(&b, *strfrmt++); 1.769 + else if (*++strfrmt == L_ESC) 1.770 + luaL_addchar(&b, *strfrmt++); /* %% */ 1.771 + else { /* format item */ 1.772 + char form[MAX_FORMAT]; /* to store the format (`%...') */ 1.773 + char buff[MAX_ITEM]; /* to store the formatted item */ 1.774 + arg++; 1.775 + strfrmt = scanformat(L, strfrmt, form); 1.776 + switch (*strfrmt++) { 1.777 + case 'c': { 1.778 + sprintf(buff, form, (int)luaL_checknumber(L, arg)); 1.779 + break; 1.780 + } 1.781 + case 'd': case 'i': { 1.782 + addintlen(form); 1.783 + sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); 1.784 + break; 1.785 + } 1.786 + case 'o': case 'u': case 'x': case 'X': { 1.787 + addintlen(form); 1.788 + sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); 1.789 + break; 1.790 + } 1.791 + case 'e': case 'E': case 'f': 1.792 + case 'g': case 'G': { 1.793 + sprintf(buff, form, (double)luaL_checknumber(L, arg)); 1.794 + break; 1.795 + } 1.796 + case 'q': { 1.797 + addquoted(L, &b, arg); 1.798 + continue; /* skip the 'addsize' at the end */ 1.799 + } 1.800 + case 's': { 1.801 + size_t l; 1.802 + const char *s = luaL_checklstring(L, arg, &l); 1.803 + if (!strchr(form, '.') && l >= 100) { 1.804 + /* no precision and string is too long to be formatted; 1.805 + keep original string */ 1.806 + lua_pushvalue(L, arg); 1.807 + luaL_addvalue(&b); 1.808 + continue; /* skip the `addsize' at the end */ 1.809 + } 1.810 + else { 1.811 + sprintf(buff, form, s); 1.812 + break; 1.813 + } 1.814 + } 1.815 + default: { /* also treat cases `pnLlh' */ 1.816 + return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " 1.817 + LUA_QL("format"), *(strfrmt - 1)); 1.818 + } 1.819 + } 1.820 + luaL_addlstring(&b, buff, strlen(buff)); 1.821 + } 1.822 + } 1.823 + luaL_pushresult(&b); 1.824 + return 1; 1.825 +} 1.826 + 1.827 + 1.828 +static const luaL_Reg strlib[] = { 1.829 + {"byte", str_byte}, 1.830 + {"char", str_char}, 1.831 + {"dump", str_dump}, 1.832 + {"find", str_find}, 1.833 + {"format", str_format}, 1.834 + {"gfind", gfind_nodef}, 1.835 + {"gmatch", gmatch}, 1.836 + {"gsub", str_gsub}, 1.837 + {"len", str_len}, 1.838 + {"lower", str_lower}, 1.839 + {"match", str_match}, 1.840 + {"rep", str_rep}, 1.841 + {"reverse", str_reverse}, 1.842 + {"sub", str_sub}, 1.843 + {"upper", str_upper}, 1.844 + {NULL, NULL} 1.845 +}; 1.846 + 1.847 + 1.848 +static void createmetatable (lua_State *L) { 1.849 + lua_createtable(L, 0, 1); /* create metatable for strings */ 1.850 + lua_pushliteral(L, ""); /* dummy string */ 1.851 + lua_pushvalue(L, -2); 1.852 + lua_setmetatable(L, -2); /* set string metatable */ 1.853 + lua_pop(L, 1); /* pop dummy string */ 1.854 + lua_pushvalue(L, -2); /* string library... */ 1.855 + lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ 1.856 + lua_pop(L, 1); /* pop metatable */ 1.857 +} 1.858 + 1.859 + 1.860 +/* 1.861 +** Open string library 1.862 +*/ 1.863 +LUALIB_API int luaopen_string (lua_State *L) { 1.864 + luaL_register(L, LUA_STRLIBNAME, strlib); 1.865 +#if defined(LUA_COMPAT_GFIND) 1.866 + lua_getfield(L, -1, "gmatch"); 1.867 + lua_setfield(L, -2, "gfind"); 1.868 +#endif 1.869 + createmetatable(L); 1.870 + return 1; 1.871 +} 1.872 +