Lua 5.1.4: lstrlib.c


L0001    /*
L0002    ** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $
L0003    ** Standard library for string operations and pattern-matching
L0004    ** See Copyright Notice in lua.h
L0005    */
L0006    
L0007    
L0008    #include <ctype.h>
L0009    #include <stddef.h>
L0010    #include <stdio.h>
L0011    #include <stdlib.h>
L0012    #include <string.h>
L0013    
L0014    #define lstrlib_c
L0015    #define LUA_LIB
L0016    
L0017    #include "lua.h"
L0018    
L0019    #include "lauxlib.h"
L0020    #include "lualib.h"
L0021    
L0022    
L0023    /* macro to `unsign' a character */
L0024    #define uchar(c)        ((unsigned char)(c))
L0025    
L0026    
L0027    
L0028    static int str_len (lua_State *L) {
manl:string.len
L0029 size_t l; L0030 luaL_checklstring(L, 1, &l); L0031 lua_pushinteger(L, l); L0032 return 1; L0033 } L0034 L0035 L0036 static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { L0037 /* relative string position: negative means back from end */ L0038 if (pos < 0) pos += (ptrdiff_t)len + 1; L0039 return (pos >= 0) ? pos : 0; L0040 } L0041 L0042 L0043 static int str_sub (lua_State *L) {
manl:string.sub
L0044 size_t l; L0045 const char *s = luaL_checklstring(L, 1, &l); L0046 ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); L0047 ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); L0048 if (start < 1) start = 1; L0049 if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; L0050 if (start <= end) L0051 lua_pushlstring(L, s+start-1, end-start+1); L0052 else lua_pushliteral(L, ""); L0053 return 1; L0054 } L0055 L0056 L0057 static int str_reverse (lua_State *L) {
manl:string.reverse
L0058 size_t l; L0059 luaL_Buffer b; L0060 const char *s = luaL_checklstring(L, 1, &l); L0061 luaL_buffinit(L, &b); L0062 while (l--) luaL_addchar(&b, s[l]); L0063 luaL_pushresult(&b); L0064 return 1; L0065 } L0066 L0067 L0068 static int str_lower (lua_State *L) {
manl:string.lower
L0069 size_t l; L0070 size_t i; L0071 luaL_Buffer b; L0072 const char *s = luaL_checklstring(L, 1, &l); L0073 luaL_buffinit(L, &b); L0074 for (i=0; i<l; i++) L0075 luaL_addchar(&b, tolower(uchar(s[i]))); L0076 luaL_pushresult(&b); L0077 return 1; L0078 } L0079 L0080 L0081 static int str_upper (lua_State *L) {
manl:string.upper
L0082 size_t l; L0083 size_t i; L0084 luaL_Buffer b; L0085 const char *s = luaL_checklstring(L, 1, &l); L0086 luaL_buffinit(L, &b); L0087 for (i=0; i<l; i++) L0088 luaL_addchar(&b, toupper(uchar(s[i]))); L0089 luaL_pushresult(&b); L0090 return 1; L0091 } L0092 L0093 static int str_rep (lua_State *L) {
manl:string.rep
L0094 size_t l; L0095 luaL_Buffer b; L0096 const char *s = luaL_checklstring(L, 1, &l); L0097 int n = luaL_checkint(L, 2); L0098 luaL_buffinit(L, &b); L0099 while (n-- > 0) L0100 luaL_addlstring(&b, s, l); L0101 luaL_pushresult(&b); L0102 return 1; L0103 } L0104 L0105 L0106 static int str_byte (lua_State *L) {
manl:string.byte
L0107 size_t l; L0108 const char *s = luaL_checklstring(L, 1, &l); L0109 ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); L0110 ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); L0111 int n, i; L0112 if (posi <= 0) posi = 1; L0113 if ((size_t)pose > l) pose = l; L0114 if (posi > pose) return 0; /* empty interval; return no values */ L0115 n = (int)(pose - posi + 1); L0116 if (posi + n <= pose) /* overflow? */ L0117 luaL_error(L, "string slice too long"); L0118 luaL_checkstack(L, n, "string slice too long"); L0119 for (i=0; i<n; i++) L0120 lua_pushinteger(L, uchar(s[posi+i-1])); L0121 return n; L0122 } L0123 L0124 L0125 static int str_char (lua_State *L) {
manl:string.char
L0126 int n = lua_gettop(L); /* number of arguments */ L0127 int i; L0128 luaL_Buffer b; L0129 luaL_buffinit(L, &b); L0130 for (i=1; i<=n; i++) { L0131 int c = luaL_checkint(L, i); L0132 luaL_argcheck(L, uchar(c) == c, i, "invalid value"); L0133 luaL_addchar(&b, uchar(c)); L0134 } L0135 luaL_pushresult(&b); L0136 return 1; L0137 } L0138 L0139 L0140 static int writer (lua_State *L, const void* b, size_t size, void* B) { L0141 (void)L; L0142 luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); L0143 return 0; L0144 } L0145 L0146 L0147 static int str_dump (lua_State *L) {
manl:string.dump
L0148 luaL_Buffer b; L0149 luaL_checktype(L, 1, LUA_TFUNCTION); L0150 lua_settop(L, 1); L0151 luaL_buffinit(L,&b); L0152 if (lua_dump(L, writer, &b) != 0) L0153 luaL_error(L, "unable to dump given function"); L0154 luaL_pushresult(&b); L0155 return 1; L0156 } L0157 L0158 L0159 L0160 /* L0161 ** {====================================================== L0162 ** PATTERN MATCHING L0163 ** ======================================================= L0164 */ L0165 L0166 L0167 #define CAP_UNFINISHED (-1) L0168 #define CAP_POSITION (-2) L0169 L0170 typedef struct MatchState { L0171 const char *src_init; /* init of source string */ L0172 const char *src_end; /* end (`\0') of source string */ L0173 lua_State *L; L0174 int level; /* total number of captures (finished or unfinished) */ L0175 struct { L0176 const char *init; L0177 ptrdiff_t len; L0178 } capture[LUA_MAXCAPTURES]; L0179 } MatchState; L0180 L0181 L0182 #define L_ESC '%' L0183 #define SPECIALS "^$*+?.([%-" L0184 L0185 L0186 static int check_capture (MatchState *ms, int l) { L0187 l -= '1'; L0188 if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) L0189 return luaL_error(ms->L, "invalid capture index"); L0190 return l; L0191 } L0192 L0193 L0194 static int capture_to_close (MatchState *ms) { L0195 int level = ms->level; L0196 for (level--; level>=0; level--) L0197 if (ms->capture[level].len == CAP_UNFINISHED) return level; L0198 return luaL_error(ms->L, "invalid pattern capture"); L0199 } L0200 L0201 L0202 static const char *classend (MatchState *ms, const char *p) { L0203 switch (*p++) { L0204 case L_ESC: { L0205 if (*p == '\0') L0206 luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); L0207 return p+1; L0208 } L0209 case '[': { L0210 if (*p == '^') p++; L0211 do { /* look for a `]' */ L0212 if (*p == '\0') L0213 luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); L0214 if (*(p++) == L_ESC && *p != '\0') L0215 p++; /* skip escapes (e.g. `%]') */ L0216 } while (*p != ']'); L0217 return p+1; L0218 } L0219 default: { L0220 return p; L0221 } L0222 } L0223 } L0224 L0225 L0226 static int match_class (int c, int cl) { L0227 int res; L0228 switch (tolower(cl)) { L0229 case 'a' : res = isalpha(c); break; L0230 case 'c' : res = iscntrl(c); break; L0231 case 'd' : res = isdigit(c); break; L0232 case 'l' : res = islower(c); break; L0233 case 'p' : res = ispunct(c); break; L0234 case 's' : res = isspace(c); break; L0235 case 'u' : res = isupper(c); break; L0236 case 'w' : res = isalnum(c); break; L0237 case 'x' : res = isxdigit(c); break; L0238 case 'z' : res = (c == 0); break; L0239 default: return (cl == c); L0240 } L0241 return (islower(cl) ? res : !res); L0242 } L0243 L0244 L0245 static int matchbracketclass (int c, const char *p, const char *ec) { L0246 int sig = 1; L0247 if (*(p+1) == '^') { L0248 sig = 0; L0249 p++; /* skip the `^' */ L0250 } L0251 while (++p < ec) { L0252 if (*p == L_ESC) { L0253 p++; L0254 if (match_class(c, uchar(*p))) L0255 return sig; L0256 } L0257 else if ((*(p+1) == '-') && (p+2 < ec)) { L0258 p+=2; L0259 if (uchar(*(p-2)) <= c && c <= uchar(*p)) L0260 return sig; L0261 } L0262 else if (uchar(*p) == c) return sig; L0263 } L0264 return !sig; L0265 } L0266 L0267 L0268 static int singlematch (int c, const char *p, const char *ep) { L0269 switch (*p) { L0270 case '.': return 1; /* matches any char */ L0271 case L_ESC: return match_class(c, uchar(*(p+1))); L0272 case '[': return matchbracketclass(c, p, ep-1); L0273 default: return (uchar(*p) == c); L0274 } L0275 } L0276 L0277 L0278 static const char *match (MatchState *ms, const char *s, const char *p); L0279 L0280 L0281 static const char *matchbalance (MatchState *ms, const char *s, L0282 const char *p) { L0283 if (*p == 0 || *(p+1) == 0) L0284 luaL_error(ms->L, "unbalanced pattern"); L0285 if (*s != *p) return NULL; L0286 else { L0287 int b = *p; L0288 int e = *(p+1); L0289 int cont = 1; L0290 while (++s < ms->src_end) { L0291 if (*s == e) { L0292 if (--cont == 0) return s+1; L0293 } L0294 else if (*s == b) cont++; L0295 } L0296 } L0297 return NULL; /* string ends out of balance */ L0298 } L0299 L0300 L0301 static const char *max_expand (MatchState *ms, const char *s, L0302 const char *p, const char *ep) { L0303 ptrdiff_t i = 0; /* counts maximum expand for item */ L0304 while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) L0305 i++; L0306 /* keeps trying to match with the maximum repetitions */ L0307 while (i>=0) { L0308 const char *res = match(ms, (s+i), ep+1); L0309 if (res) return res; L0310 i--; /* else didn't match; reduce 1 repetition to try again */ L0311 } L0312 return NULL; L0313 } L0314 L0315 L0316 static const char *min_expand (MatchState *ms, const char *s, L0317 const char *p, const char *ep) { L0318 for (;;) { L0319 const char *res = match(ms, s, ep+1); L0320 if (res != NULL) L0321 return res; L0322 else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) L0323 s++; /* try with one more repetition */ L0324 else return NULL; L0325 } L0326 } L0327 L0328 L0329 static const char *start_capture (MatchState *ms, const char *s, L0330 const char *p, int what) { L0331 const char *res; L0332 int level = ms->level; L0333 if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); L0334 ms->capture[level].init = s; L0335 ms->capture[level].len = what; L0336 ms->level = level+1; L0337 if ((res=match(ms, s, p)) == NULL) /* match failed? */ L0338 ms->level--; /* undo capture */ L0339 return res; L0340 } L0341 L0342 L0343 static const char *end_capture (MatchState *ms, const char *s, L0344 const char *p) { L0345 int l = capture_to_close(ms); L0346 const char *res; L0347 ms->capture[l].len = s - ms->capture[l].init; /* close capture */ L0348 if ((res = match(ms, s, p)) == NULL) /* match failed? */ L0349 ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ L0350 return res; L0351 } L0352 L0353 L0354 static const char *match_capture (MatchState *ms, const char *s, int l) { L0355 size_t len; L0356 l = check_capture(ms, l); L0357 len = ms->capture[l].len; L0358 if ((size_t)(ms->src_end-s) >= len && L0359 memcmp(ms->capture[l].init, s, len) == 0) L0360 return s+len; L0361 else return NULL; L0362 } L0363 L0364 L0365 static const char *match (MatchState *ms, const char *s, const char *p) { L0366 init: /* using goto's to optimize tail recursion */ L0367 switch (*p) { L0368 case '(': { /* start capture */ L0369 if (*(p+1) == ')') /* position capture? */ L0370 return start_capture(ms, s, p+2, CAP_POSITION); L0371 else L0372 return start_capture(ms, s, p+1, CAP_UNFINISHED); L0373 } L0374 case ')': { /* end capture */ L0375 return end_capture(ms, s, p+1); L0376 } L0377 case L_ESC: { L0378 switch (*(p+1)) { L0379 case 'b': { /* balanced string? */ L0380 s = matchbalance(ms, s, p+2); L0381 if (s == NULL) return NULL; L0382 p+=4; goto init; /* else return match(ms, s, p+4); */ L0383 } L0384 case 'f': { /* frontier? */ L0385 const char *ep; char previous; L0386 p += 2; L0387 if (*p != '[') L0388 luaL_error(ms->L, "missing " LUA_QL("[") " after " L0389 LUA_QL("%%f") " in pattern"); L0390 ep = classend(ms, p); /* points to what is next */ L0391 previous = (s == ms->src_init) ? '\0' : *(s-1); L0392 if (matchbracketclass(uchar(previous), p, ep-1) || L0393 !matchbracketclass(uchar(*s), p, ep-1)) return NULL; L0394 p=ep; goto init; /* else return match(ms, s, ep); */ L0395 } L0396 default: { L0397 if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ L0398 s = match_capture(ms, s, uchar(*(p+1))); L0399 if (s == NULL) return NULL; L0400 p+=2; goto init; /* else return match(ms, s, p+2) */ L0401 } L0402 goto dflt; /* case default */ L0403 } L0404 } L0405 } L0406 case '\0': { /* end of pattern */ L0407 return s; /* match succeeded */ L0408 } L0409 case '$': { L0410 if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ L0411 return (s == ms->src_end) ? s : NULL; /* check end of string */ L0412 else goto dflt; L0413 } L0414 default: dflt: { /* it is a pattern item */ L0415 const char *ep = classend(ms, p); /* points to what is next */ L0416 int m = s<ms->src_end && singlematch(uchar(*s), p, ep); L0417 switch (*ep) { L0418 case '?': { /* optional */ L0419 const char *res; L0420 if (m && ((res=match(ms, s+1, ep+1)) != NULL)) L0421 return res; L0422 p=ep+1; goto init; /* else return match(ms, s, ep+1); */ L0423 } L0424 case '*': { /* 0 or more repetitions */ L0425 return max_expand(ms, s, p, ep); L0426 } L0427 case '+': { /* 1 or more repetitions */ L0428 return (m ? max_expand(ms, s+1, p, ep) : NULL); L0429 } L0430 case '-': { /* 0 or more repetitions (minimum) */ L0431 return min_expand(ms, s, p, ep); L0432 } L0433 default: { L0434 if (!m) return NULL; L0435 s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ L0436 } L0437 } L0438 } L0439 } L0440 } L0441 L0442 L0443 L0444 static const char *lmemfind (const char *s1, size_t l1, L0445 const char *s2, size_t l2) { L0446 if (l2 == 0) return s1; /* empty strings are everywhere */ L0447 else if (l2 > l1) return NULL; /* avoids a negative `l1' */ L0448 else { L0449 const char *init; /* to search for a `*s2' inside `s1' */ L0450 l2--; /* 1st char will be checked by `memchr' */ L0451 l1 = l1-l2; /* `s2' cannot be found after that */ L0452 while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { L0453 init++; /* 1st char is already checked */ L0454 if (memcmp(init, s2+1, l2) == 0) L0455 return init-1; L0456 else { /* correct `l1' and `s1' to try again */ L0457 l1 -= init-s1; L0458 s1 = init; L0459 } L0460 } L0461 return NULL; /* not found */ L0462 } L0463 } L0464 L0465 L0466 static void push_onecapture (MatchState *ms, int i, const char *s, L0467 const char *e) { L0468 if (i >= ms->level) { L0469 if (i == 0) /* ms->level == 0, too */ L0470 lua_pushlstring(ms->L, s, e - s); /* add whole match */ L0471 else L0472 luaL_error(ms->L, "invalid capture index"); L0473 } L0474 else { L0475 ptrdiff_t l = ms->capture[i].len; L0476 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); L0477 if (l == CAP_POSITION) L0478 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); L0479 else L0480 lua_pushlstring(ms->L, ms->capture[i].init, l); L0481 } L0482 } L0483 L0484 L0485 static int push_captures (MatchState *ms, const char *s, const char *e) { L0486 int i; L0487 int nlevels = (ms->level == 0 && s) ? 1 : ms->level; L0488 luaL_checkstack(ms->L, nlevels, "too many captures"); L0489 for (i = 0; i < nlevels; i++) L0490 push_onecapture(ms, i, s, e); L0491 return nlevels; /* number of strings pushed */ L0492 } L0493 L0494 L0495 static int str_find_aux (lua_State *L, int find) { L0496 size_t l1, l2; L0497 const char *s = luaL_checklstring(L, 1, &l1); L0498 const char *p = luaL_checklstring(L, 2, &l2); L0499 ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; L0500 if (init < 0) init = 0; L0501 else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; L0502 if (find && (lua_toboolean(L, 4) || /* explicit request? */ L0503 strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ L0504 /* do a plain search */ L0505 const char *s2 = lmemfind(s+init, l1-init, p, l2); L0506 if (s2) { L0507 lua_pushinteger(L, s2-s+1); L0508 lua_pushinteger(L, s2-s+l2); L0509 return 2; L0510 } L0511 } L0512 else { L0513 MatchState ms; L0514 int anchor = (*p == '^') ? (p++, 1) : 0; L0515 const char *s1=s+init; L0516 ms.L = L; L0517 ms.src_init = s; L0518 ms.src_end = s+l1; L0519 do { L0520 const char *res; L0521 ms.level = 0; L0522 if ((res=match(&ms, s1, p)) != NULL) { L0523 if (find) { L0524 lua_pushinteger(L, s1-s+1); /* start */ L0525 lua_pushinteger(L, res-s); /* end */ L0526 return push_captures(&ms, NULL, 0) + 2; L0527 } L0528 else L0529 return push_captures(&ms, s1, res); L0530 } L0531 } while (s1++ < ms.src_end && !anchor); L0532 } L0533 lua_pushnil(L); /* not found */ L0534 return 1; L0535 } L0536 L0537 L0538 static int str_find (lua_State *L) {
manl:string.find
L0539 return str_find_aux(L, 1); L0540 } L0541 L0542 L0543 static int str_match (lua_State *L) {
manl:string.match
L0544 return str_find_aux(L, 0); L0545 } L0546 L0547 L0548 static int gmatch_aux (lua_State *L) { L0549 MatchState ms; L0550 size_t ls; L0551 const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); L0552 const char *p = lua_tostring(L, lua_upvalueindex(2)); L0553 const char *src; L0554 ms.L = L; L0555 ms.src_init = s; L0556 ms.src_end = s+ls; L0557 for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); L0558 src <= ms.src_end; L0559 src++) { L0560 const char *e; L0561 ms.level = 0; L0562 if ((e = match(&ms, src, p)) != NULL) { L0563 lua_Integer newstart = e-s; L0564 if (e == src) newstart++; /* empty match? go at least one position */ L0565 lua_pushinteger(L, newstart); L0566 lua_replace(L, lua_upvalueindex(3)); L0567 return push_captures(&ms, src, e); L0568 } L0569 } L0570 return 0; /* not found */ L0571 } L0572 L0573 L0574 static int gmatch (lua_State *L) { L0575 luaL_checkstring(L, 1); L0576 luaL_checkstring(L, 2); L0577 lua_settop(L, 2); L0578 lua_pushinteger(L, 0); L0579 lua_pushcclosure(L, gmatch_aux, 3); L0580 return 1; L0581 } L0582 L0583 L0584 static int gfind_nodef (lua_State *L) { L0585 return luaL_error(L, LUA_QL("string.gfind") " was renamed to " L0586 LUA_QL("string.gmatch")); L0587 } L0588 L0589 L0590 static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, L0591 const char *e) { L0592 size_t l, i; L0593 const char *news = lua_tolstring(ms->L, 3, &l); L0594 for (i = 0; i < l; i++) { L0595 if (news[i] != L_ESC) L0596 luaL_addchar(b, news[i]); L0597 else { L0598 i++; /* skip ESC */ L0599 if (!isdigit(uchar(news[i]))) L0600 luaL_addchar(b, news[i]); L0601 else if (news[i] == '0') L0602 luaL_addlstring(b, s, e - s); L0603 else { L0604 push_onecapture(ms, news[i] - '1', s, e); L0605 luaL_addvalue(b); /* add capture to accumulated result */ L0606 } L0607 } L0608 } L0609 } L0610 L0611 L0612 static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, L0613 const char *e) { L0614 lua_State *L = ms->L; L0615 switch (lua_type(L, 3)) { L0616 case LUA_TNUMBER: L0617 case LUA_TSTRING: { L0618 add_s(ms, b, s, e); L0619 return; L0620 } L0621 case LUA_TFUNCTION: { L0622 int n; L0623 lua_pushvalue(L, 3); L0624 n = push_captures(ms, s, e); L0625 lua_call(L, n, 1); L0626 break; L0627 } L0628 case LUA_TTABLE: { L0629 push_onecapture(ms, 0, s, e); L0630 lua_gettable(L, 3); L0631 break; L0632 } L0633 } L0634 if (!lua_toboolean(L, -1)) { /* nil or false? */ L0635 lua_pop(L, 1); L0636 lua_pushlstring(L, s, e - s); /* keep original text */ L0637 } L0638 else if (!lua_isstring(L, -1)) L0639 luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); L0640 luaL_addvalue(b); /* add result to accumulator */ L0641 } L0642 L0643 L0644 static int str_gsub (lua_State *L) {
manl:string.gsub
L0645 size_t srcl; L0646 const char *src = luaL_checklstring(L, 1, &srcl); L0647 const char *p = luaL_checkstring(L, 2); L0648 int tr = lua_type(L, 3); L0649 int max_s = luaL_optint(L, 4, srcl+1); L0650 int anchor = (*p == '^') ? (p++, 1) : 0; L0651 int n = 0; L0652 MatchState ms; L0653 luaL_Buffer b; L0654 luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || L0655 tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, L0656 "string/function/table expected"); L0657 luaL_buffinit(L, &b); L0658 ms.L = L; L0659 ms.src_init = src; L0660 ms.src_end = src+srcl; L0661 while (n < max_s) { L0662 const char *e; L0663 ms.level = 0; L0664 e = match(&ms, src, p); L0665 if (e) { L0666 n++; L0667 add_value(&ms, &b, src, e); L0668 } L0669 if (e && e>src) /* non empty match? */ L0670 src = e; /* skip it */ L0671 else if (src < ms.src_end) L0672 luaL_addchar(&b, *src++); L0673 else break; L0674 if (anchor) break; L0675 } L0676 luaL_addlstring(&b, src, ms.src_end-src); L0677 luaL_pushresult(&b); L0678 lua_pushinteger(L, n); /* number of substitutions */ L0679 return 2; L0680 } L0681 L0682 /* }====================================================== */ L0683 L0684 L0685 /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ L0686 #define MAX_ITEM 512 L0687 /* valid flags in a format specification */ L0688 #define FLAGS "-+ #0" L0689 /* L0690 ** maximum size of each format specification (such as '%-099.99d') L0691 ** (+10 accounts for %99.99x plus margin of error) L0692 */ L0693 #define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) L0694 L0695 L0696 static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { L0697 size_t l; L0698 const char *s = luaL_checklstring(L, arg, &l); L0699 luaL_addchar(b, '"'); L0700 while (l--) { L0701 switch (*s) { L0702 case '"': case '\\': case '\n': { L0703 luaL_addchar(b, '\\'); L0704 luaL_addchar(b, *s); L0705 break; L0706 } L0707 case '\r': { L0708 luaL_addlstring(b, "\\r", 2); L0709 break; L0710 } L0711 case '\0': { L0712 luaL_addlstring(b, "\\000", 4); L0713 break; L0714 } L0715 default: { L0716 luaL_addchar(b, *s); L0717 break; L0718 } L0719 } L0720 s++; L0721 } L0722 luaL_addchar(b, '"'); L0723 } L0724 L0725 static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { L0726 const char *p = strfrmt; L0727 while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ L0728 if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) L0729 luaL_error(L, "invalid format (repeated flags)"); L0730 if (isdigit(uchar(*p))) p++; /* skip width */ L0731 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ L0732 if (*p == '.') { L0733 p++; L0734 if (isdigit(uchar(*p))) p++; /* skip precision */ L0735 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ L0736 } L0737 if (isdigit(uchar(*p))) L0738 luaL_error(L, "invalid format (width or precision too long)"); L0739 *(form++) = '%'; L0740 strncpy(form, strfrmt, p - strfrmt + 1); L0741 form += p - strfrmt + 1; L0742 *form = '\0'; L0743 return p; L0744 } L0745 L0746 L0747 static void addintlen (char *form) { L0748 size_t l = strlen(form); L0749 char spec = form[l - 1]; L0750 strcpy(form + l - 1, LUA_INTFRMLEN); L0751 form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; L0752 form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; L0753 } L0754 L0755 L0756 static int str_format (lua_State *L) {
manl:string.format
L0757 int arg = 1; L0758 size_t sfl; L0759 const char *strfrmt = luaL_checklstring(L, arg, &sfl); L0760 const char *strfrmt_end = strfrmt+sfl; L0761 luaL_Buffer b; L0762 luaL_buffinit(L, &b); L0763 while (strfrmt < strfrmt_end) { L0764 if (*strfrmt != L_ESC) L0765 luaL_addchar(&b, *strfrmt++); L0766 else if (*++strfrmt == L_ESC) L0767 luaL_addchar(&b, *strfrmt++); /* %% */ L0768 else { /* format item */ L0769 char form[MAX_FORMAT]; /* to store the format (`%...') */ L0770 char buff[MAX_ITEM]; /* to store the formatted item */ L0771 arg++; L0772 strfrmt = scanformat(L, strfrmt, form); L0773 switch (*strfrmt++) { L0774 case 'c': { L0775 sprintf(buff, form, (int)luaL_checknumber(L, arg)); L0776 break; L0777 } L0778 case 'd': case 'i': { L0779 addintlen(form); L0780 sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); L0781 break; L0782 } L0783 case 'o': case 'u': case 'x': case 'X': { L0784 addintlen(form); L0785 sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); L0786 break; L0787 } L0788 case 'e': case 'E': case 'f': L0789 case 'g': case 'G': { L0790 sprintf(buff, form, (double)luaL_checknumber(L, arg)); L0791 break; L0792 } L0793 case 'q': { L0794 addquoted(L, &b, arg); L0795 continue; /* skip the 'addsize' at the end */ L0796 } L0797 case 's': { L0798 size_t l; L0799 const char *s = luaL_checklstring(L, arg, &l); L0800 if (!strchr(form, '.') && l >= 100) { L0801 /* no precision and string is too long to be formatted; L0802 keep original string */ L0803 lua_pushvalue(L, arg); L0804 luaL_addvalue(&b); L0805 continue; /* skip the `addsize' at the end */ L0806 } L0807 else { L0808 sprintf(buff, form, s); L0809 break; L0810 } L0811 } L0812 default: { /* also treat cases `pnLlh' */ L0813 return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " L0814 LUA_QL("format"), *(strfrmt - 1)); L0815 } L0816 } L0817 luaL_addlstring(&b, buff, strlen(buff)); L0818 } L0819 } L0820 luaL_pushresult(&b); L0821 return 1; L0822 } L0823 L0824 L0825 static const luaL_Reg strlib[] = { L0826 {"byte", str_byte}, L0827 {"char", str_char}, L0828 {"dump", str_dump}, L0829 {"find", str_find}, L0830 {"format", str_format}, L0831 {"gfind", gfind_nodef}, L0832 {"gmatch", gmatch}, L0833 {"gsub", str_gsub}, L0834 {"len", str_len}, L0835 {"lower", str_lower}, L0836 {"match", str_match}, L0837 {"rep", str_rep}, L0838 {"reverse", str_reverse}, L0839 {"sub", str_sub}, L0840 {"upper", str_upper}, L0841 {NULL, NULL} L0842 }; L0843 L0844 L0845 static void createmetatable (lua_State *L) { L0846 lua_createtable(L, 0, 1); /* create metatable for strings */ L0847 lua_pushliteral(L, ""); /* dummy string */ L0848 lua_pushvalue(L, -2); L0849 lua_setmetatable(L, -2); /* set string metatable */ L0850 lua_pop(L, 1); /* pop dummy string */ L0851 lua_pushvalue(L, -2); /* string library... */ L0852 lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ L0853 lua_pop(L, 1); /* pop metatable */ L0854 } L0855 L0856 L0857 /* L0858 ** Open string library L0859 */ L0860 LUALIB_API int luaopen_string (lua_State *L) { L0861 luaL_register(L, LUA_STRLIBNAME, strlib); L0862 #if defined(LUA_COMPAT_GFIND) L0863 lua_getfield(L, -1, "gmatch"); L0864 lua_setfield(L, -2, "gfind"); L0865 #endif L0866 createmetatable(L); L0867 return 1; L0868 } L0869

Generated by pretty.lua