00001 /* 00002 ** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ 00003 ** Standard library for string operations and pattern-matching 00004 ** See Copyright Notice in lua.h 00005 */ 00006 00007 00008 #include <ctype.h> 00009 #include <stddef.h> 00010 #include <stdio.h> 00011 #include <stdlib.h> 00012 #include <string.h> 00013 00014 #define lstrlib_c 00015 #define LUA_LIB 00016 00017 #include "lua.h" 00018 00019 #include "lauxlib.h" 00020 #include "lualib.h" 00021 00022 00023 /* macro to `unsign' a character */ 00024 #define uchar(c) ((unsigned char)(c)) 00025 00026 00027 00028 static int str_len (lua_State *L) { 00029 size_t l; 00030 luaL_checklstring(L, 1, &l); 00031 lua_pushinteger(L, l); 00032 return 1; 00033 } 00034 00035 00036 static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { 00037 /* relative string position: negative means back from end */ 00038 if (pos < 0) pos += (ptrdiff_t)len + 1; 00039 return (pos >= 0) ? pos : 0; 00040 } 00041 00042 00043 static int str_sub (lua_State *L) { 00044 size_t l; 00045 const char *s = luaL_checklstring(L, 1, &l); 00046 ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); 00047 ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); 00048 if (start < 1) start = 1; 00049 if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; 00050 if (start <= end) 00051 lua_pushlstring(L, s+start-1, end-start+1); 00052 else lua_pushliteral(L, ""); 00053 return 1; 00054 } 00055 00056 00057 static int str_reverse (lua_State *L) { 00058 size_t l; 00059 luaL_Buffer b; 00060 const char *s = luaL_checklstring(L, 1, &l); 00061 luaL_buffinit(L, &b); 00062 while (l--) luaL_addchar(&b, s[l]); 00063 luaL_pushresult(&b); 00064 return 1; 00065 } 00066 00067 00068 static int str_lower (lua_State *L) { 00069 size_t l; 00070 size_t i; 00071 luaL_Buffer b; 00072 const char *s = luaL_checklstring(L, 1, &l); 00073 luaL_buffinit(L, &b); 00074 for (i=0; i<l; i++) 00075 luaL_addchar(&b, tolower(uchar(s[i]))); 00076 luaL_pushresult(&b); 00077 return 1; 00078 } 00079 00080 00081 static int str_upper (lua_State *L) { 00082 size_t l; 00083 size_t i; 00084 luaL_Buffer b; 00085 const char *s = luaL_checklstring(L, 1, &l); 00086 luaL_buffinit(L, &b); 00087 for (i=0; i<l; i++) 00088 luaL_addchar(&b, toupper(uchar(s[i]))); 00089 luaL_pushresult(&b); 00090 return 1; 00091 } 00092 00093 static int str_rep (lua_State *L) { 00094 size_t l; 00095 luaL_Buffer b; 00096 const char *s = luaL_checklstring(L, 1, &l); 00097 int n = luaL_checkint(L, 2); 00098 luaL_buffinit(L, &b); 00099 while (n-- > 0) 00100 luaL_addlstring(&b, s, l); 00101 luaL_pushresult(&b); 00102 return 1; 00103 } 00104 00105 00106 static int str_byte (lua_State *L) { 00107 size_t l; 00108 const char *s = luaL_checklstring(L, 1, &l); 00109 ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); 00110 ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); 00111 int n, i; 00112 if (posi <= 0) posi = 1; 00113 if ((size_t)pose > l) pose = l; 00114 if (posi > pose) return 0; /* empty interval; return no values */ 00115 n = (int)(pose - posi + 1); 00116 if (posi + n <= pose) /* overflow? */ 00117 luaL_error(L, "string slice too long"); 00118 luaL_checkstack(L, n, "string slice too long"); 00119 for (i=0; i<n; i++) 00120 lua_pushinteger(L, uchar(s[posi+i-1])); 00121 return n; 00122 } 00123 00124 00125 static int str_char (lua_State *L) { 00126 int n = lua_gettop(L); /* number of arguments */ 00127 int i; 00128 luaL_Buffer b; 00129 luaL_buffinit(L, &b); 00130 for (i=1; i<=n; i++) { 00131 int c = luaL_checkint(L, i); 00132 luaL_argcheck(L, uchar(c) == c, i, "invalid value"); 00133 luaL_addchar(&b, uchar(c)); 00134 } 00135 luaL_pushresult(&b); 00136 return 1; 00137 } 00138 00139 00140 static int writer (lua_State *L, const void* b, size_t size, void* B) { 00141 (void)L; 00142 luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); 00143 return 0; 00144 } 00145 00146 00147 static int str_dump (lua_State *L) { 00148 luaL_Buffer b; 00149 luaL_checktype(L, 1, LUA_TFUNCTION); 00150 lua_settop(L, 1); 00151 luaL_buffinit(L,&b); 00152 if (lua_dump(L, writer, &b) != 0) 00153 luaL_error(L, "unable to dump given function"); 00154 luaL_pushresult(&b); 00155 return 1; 00156 } 00157 00158 00159 00160 /* 00161 ** {====================================================== 00162 ** PATTERN MATCHING 00163 ** ======================================================= 00164 */ 00165 00166 00167 #define CAP_UNFINISHED (-1) 00168 #define CAP_POSITION (-2) 00169 00170 typedef struct MatchState { 00171 const char *src_init; /* init of source string */ 00172 const char *src_end; /* end (`\0') of source string */ 00173 lua_State *L; 00174 int level; /* total number of captures (finished or unfinished) */ 00175 struct { 00176 const char *init; 00177 ptrdiff_t len; 00178 } capture[LUA_MAXCAPTURES]; 00179 } MatchState; 00180 00181 00182 #define L_ESC '%' 00183 #define SPECIALS "^$*+?.([%-" 00184 00185 00186 static int check_capture (MatchState *ms, int l) { 00187 l -= '1'; 00188 if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) 00189 return luaL_error(ms->L, "invalid capture index"); 00190 return l; 00191 } 00192 00193 00194 static int capture_to_close (MatchState *ms) { 00195 int level = ms->level; 00196 for (level--; level>=0; level--) 00197 if (ms->capture[level].len == CAP_UNFINISHED) return level; 00198 return luaL_error(ms->L, "invalid pattern capture"); 00199 } 00200 00201 00202 static const char *classend (MatchState *ms, const char *p) { 00203 switch (*p++) { 00204 case L_ESC: { 00205 if (*p == '\0') 00206 luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); 00207 return p+1; 00208 } 00209 case '[': { 00210 if (*p == '^') p++; 00211 do { /* look for a `]' */ 00212 if (*p == '\0') 00213 luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); 00214 if (*(p++) == L_ESC && *p != '\0') 00215 p++; /* skip escapes (e.g. `%]') */ 00216 } while (*p != ']'); 00217 return p+1; 00218 } 00219 default: { 00220 return p; 00221 } 00222 } 00223 } 00224 00225 00226 static int match_class (int c, int cl) { 00227 int res; 00228 switch (tolower(cl)) { 00229 case 'a' : res = isalpha(c); break; 00230 case 'c' : res = iscntrl(c); break; 00231 case 'd' : res = isdigit(c); break; 00232 case 'l' : res = islower(c); break; 00233 case 'p' : res = ispunct(c); break; 00234 case 's' : res = isspace(c); break; 00235 case 'u' : res = isupper(c); break; 00236 case 'w' : res = isalnum(c); break; 00237 case 'x' : res = isxdigit(c); break; 00238 case 'z' : res = (c == 0); break; 00239 default: return (cl == c); 00240 } 00241 return (islower(cl) ? res : !res); 00242 } 00243 00244 00245 static int matchbracketclass (int c, const char *p, const char *ec) { 00246 int sig = 1; 00247 if (*(p+1) == '^') { 00248 sig = 0; 00249 p++; /* skip the `^' */ 00250 } 00251 while (++p < ec) { 00252 if (*p == L_ESC) { 00253 p++; 00254 if (match_class(c, uchar(*p))) 00255 return sig; 00256 } 00257 else if ((*(p+1) == '-') && (p+2 < ec)) { 00258 p+=2; 00259 if (uchar(*(p-2)) <= c && c <= uchar(*p)) 00260 return sig; 00261 } 00262 else if (uchar(*p) == c) return sig; 00263 } 00264 return !sig; 00265 } 00266 00267 00268 static int singlematch (int c, const char *p, const char *ep) { 00269 switch (*p) { 00270 case '.': return 1; /* matches any char */ 00271 case L_ESC: return match_class(c, uchar(*(p+1))); 00272 case '[': return matchbracketclass(c, p, ep-1); 00273 default: return (uchar(*p) == c); 00274 } 00275 } 00276 00277 00278 static const char *match (MatchState *ms, const char *s, const char *p); 00279 00280 00281 static const char *matchbalance (MatchState *ms, const char *s, 00282 const char *p) { 00283 if (*p == 0 || *(p+1) == 0) 00284 luaL_error(ms->L, "unbalanced pattern"); 00285 if (*s != *p) return NULL; 00286 else { 00287 int b = *p; 00288 int e = *(p+1); 00289 int cont = 1; 00290 while (++s < ms->src_end) { 00291 if (*s == e) { 00292 if (--cont == 0) return s+1; 00293 } 00294 else if (*s == b) cont++; 00295 } 00296 } 00297 return NULL; /* string ends out of balance */ 00298 } 00299 00300 00301 static const char *max_expand (MatchState *ms, const char *s, 00302 const char *p, const char *ep) { 00303 ptrdiff_t i = 0; /* counts maximum expand for item */ 00304 while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) 00305 i++; 00306 /* keeps trying to match with the maximum repetitions */ 00307 while (i>=0) { 00308 const char *res = match(ms, (s+i), ep+1); 00309 if (res) return res; 00310 i--; /* else didn't match; reduce 1 repetition to try again */ 00311 } 00312 return NULL; 00313 } 00314 00315 00316 static const char *min_expand (MatchState *ms, const char *s, 00317 const char *p, const char *ep) { 00318 for (;;) { 00319 const char *res = match(ms, s, ep+1); 00320 if (res != NULL) 00321 return res; 00322 else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) 00323 s++; /* try with one more repetition */ 00324 else return NULL; 00325 } 00326 } 00327 00328 00329 static const char *start_capture (MatchState *ms, const char *s, 00330 const char *p, int what) { 00331 const char *res; 00332 int level = ms->level; 00333 if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); 00334 ms->capture[level].init = s; 00335 ms->capture[level].len = what; 00336 ms->level = level+1; 00337 if ((res=match(ms, s, p)) == NULL) /* match failed? */ 00338 ms->level--; /* undo capture */ 00339 return res; 00340 } 00341 00342 00343 static const char *end_capture (MatchState *ms, const char *s, 00344 const char *p) { 00345 int l = capture_to_close(ms); 00346 const char *res; 00347 ms->capture[l].len = s - ms->capture[l].init; /* close capture */ 00348 if ((res = match(ms, s, p)) == NULL) /* match failed? */ 00349 ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ 00350 return res; 00351 } 00352 00353 00354 static const char *match_capture (MatchState *ms, const char *s, int l) { 00355 size_t len; 00356 l = check_capture(ms, l); 00357 len = ms->capture[l].len; 00358 if ((size_t)(ms->src_end-s) >= len && 00359 memcmp(ms->capture[l].init, s, len) == 0) 00360 return s+len; 00361 else return NULL; 00362 } 00363 00364 00365 static const char *match (MatchState *ms, const char *s, const char *p) { 00366 init: /* using goto's to optimize tail recursion */ 00367 switch (*p) { 00368 case '(': { /* start capture */ 00369 if (*(p+1) == ')') /* position capture? */ 00370 return start_capture(ms, s, p+2, CAP_POSITION); 00371 else 00372 return start_capture(ms, s, p+1, CAP_UNFINISHED); 00373 } 00374 case ')': { /* end capture */ 00375 return end_capture(ms, s, p+1); 00376 } 00377 case L_ESC: { 00378 switch (*(p+1)) { 00379 case 'b': { /* balanced string? */ 00380 s = matchbalance(ms, s, p+2); 00381 if (s == NULL) return NULL; 00382 p+=4; goto init; /* else return match(ms, s, p+4); */ 00383 } 00384 case 'f': { /* frontier? */ 00385 const char *ep; char previous; 00386 p += 2; 00387 if (*p != '[') 00388 luaL_error(ms->L, "missing " LUA_QL("[") " after " 00389 LUA_QL("%%f") " in pattern"); 00390 ep = classend(ms, p); /* points to what is next */ 00391 previous = (s == ms->src_init) ? '\0' : *(s-1); 00392 if (matchbracketclass(uchar(previous), p, ep-1) || 00393 !matchbracketclass(uchar(*s), p, ep-1)) return NULL; 00394 p=ep; goto init; /* else return match(ms, s, ep); */ 00395 } 00396 default: { 00397 if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ 00398 s = match_capture(ms, s, uchar(*(p+1))); 00399 if (s == NULL) return NULL; 00400 p+=2; goto init; /* else return match(ms, s, p+2) */ 00401 } 00402 goto dflt; /* case default */ 00403 } 00404 } 00405 } 00406 case '\0': { /* end of pattern */ 00407 return s; /* match succeeded */ 00408 } 00409 case '$': { 00410 if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ 00411 return (s == ms->src_end) ? s : NULL; /* check end of string */ 00412 else goto dflt; 00413 } 00414 default: dflt: { /* it is a pattern item */ 00415 const char *ep = classend(ms, p); /* points to what is next */ 00416 int m = s<ms->src_end && singlematch(uchar(*s), p, ep); 00417 switch (*ep) { 00418 case '?': { /* optional */ 00419 const char *res; 00420 if (m && ((res=match(ms, s+1, ep+1)) != NULL)) 00421 return res; 00422 p=ep+1; goto init; /* else return match(ms, s, ep+1); */ 00423 } 00424 case '*': { /* 0 or more repetitions */ 00425 return max_expand(ms, s, p, ep); 00426 } 00427 case '+': { /* 1 or more repetitions */ 00428 return (m ? max_expand(ms, s+1, p, ep) : NULL); 00429 } 00430 case '-': { /* 0 or more repetitions (minimum) */ 00431 return min_expand(ms, s, p, ep); 00432 } 00433 default: { 00434 if (!m) return NULL; 00435 s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ 00436 } 00437 } 00438 } 00439 } 00440 } 00441 00442 00443 00444 static const char *lmemfind (const char *s1, size_t l1, 00445 const char *s2, size_t l2) { 00446 if (l2 == 0) return s1; /* empty strings are everywhere */ 00447 else if (l2 > l1) return NULL; /* avoids a negative `l1' */ 00448 else { 00449 const char *init; /* to search for a `*s2' inside `s1' */ 00450 l2--; /* 1st char will be checked by `memchr' */ 00451 l1 = l1-l2; /* `s2' cannot be found after that */ 00452 while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { 00453 init++; /* 1st char is already checked */ 00454 if (memcmp(init, s2+1, l2) == 0) 00455 return init-1; 00456 else { /* correct `l1' and `s1' to try again */ 00457 l1 -= init-s1; 00458 s1 = init; 00459 } 00460 } 00461 return NULL; /* not found */ 00462 } 00463 } 00464 00465 00466 static void push_onecapture (MatchState *ms, int i, const char *s, 00467 const char *e) { 00468 if (i >= ms->level) { 00469 if (i == 0) /* ms->level == 0, too */ 00470 lua_pushlstring(ms->L, s, e - s); /* add whole match */ 00471 else 00472 luaL_error(ms->L, "invalid capture index"); 00473 } 00474 else { 00475 ptrdiff_t l = ms->capture[i].len; 00476 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); 00477 if (l == CAP_POSITION) 00478 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); 00479 else 00480 lua_pushlstring(ms->L, ms->capture[i].init, l); 00481 } 00482 } 00483 00484 00485 static int push_captures (MatchState *ms, const char *s, const char *e) { 00486 int i; 00487 int nlevels = (ms->level == 0 && s) ? 1 : ms->level; 00488 luaL_checkstack(ms->L, nlevels, "too many captures"); 00489 for (i = 0; i < nlevels; i++) 00490 push_onecapture(ms, i, s, e); 00491 return nlevels; /* number of strings pushed */ 00492 } 00493 00494 00495 static int str_find_aux (lua_State *L, int find) { 00496 size_t l1, l2; 00497 const char *s = luaL_checklstring(L, 1, &l1); 00498 const char *p = luaL_checklstring(L, 2, &l2); 00499 ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; 00500 if (init < 0) init = 0; 00501 else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; 00502 if (find && (lua_toboolean(L, 4) || /* explicit request? */ 00503 strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ 00504 /* do a plain search */ 00505 const char *s2 = lmemfind(s+init, l1-init, p, l2); 00506 if (s2) { 00507 lua_pushinteger(L, s2-s+1); 00508 lua_pushinteger(L, s2-s+l2); 00509 return 2; 00510 } 00511 } 00512 else { 00513 MatchState ms; 00514 int anchor = (*p == '^') ? (p++, 1) : 0; 00515 const char *s1=s+init; 00516 ms.L = L; 00517 ms.src_init = s; 00518 ms.src_end = s+l1; 00519 do { 00520 const char *res; 00521 ms.level = 0; 00522 if ((res=match(&ms, s1, p)) != NULL) { 00523 if (find) { 00524 lua_pushinteger(L, s1-s+1); /* start */ 00525 lua_pushinteger(L, res-s); /* end */ 00526 return push_captures(&ms, NULL, 0) + 2; 00527 } 00528 else 00529 return push_captures(&ms, s1, res); 00530 } 00531 } while (s1++ < ms.src_end && !anchor); 00532 } 00533 lua_pushnil(L); /* not found */ 00534 return 1; 00535 } 00536 00537 00538 static int str_find (lua_State *L) { 00539 return str_find_aux(L, 1); 00540 } 00541 00542 00543 static int str_match (lua_State *L) { 00544 return str_find_aux(L, 0); 00545 } 00546 00547 00548 static int gmatch_aux (lua_State *L) { 00549 MatchState ms; 00550 size_t ls; 00551 const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); 00552 const char *p = lua_tostring(L, lua_upvalueindex(2)); 00553 const char *src; 00554 ms.L = L; 00555 ms.src_init = s; 00556 ms.src_end = s+ls; 00557 for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); 00558 src <= ms.src_end; 00559 src++) { 00560 const char *e; 00561 ms.level = 0; 00562 if ((e = match(&ms, src, p)) != NULL) { 00563 lua_Integer newstart = e-s; 00564 if (e == src) newstart++; /* empty match? go at least one position */ 00565 lua_pushinteger(L, newstart); 00566 lua_replace(L, lua_upvalueindex(3)); 00567 return push_captures(&ms, src, e); 00568 } 00569 } 00570 return 0; /* not found */ 00571 } 00572 00573 00574 static int gmatch (lua_State *L) { 00575 luaL_checkstring(L, 1); 00576 luaL_checkstring(L, 2); 00577 lua_settop(L, 2); 00578 lua_pushinteger(L, 0); 00579 lua_pushcclosure(L, gmatch_aux, 3); 00580 return 1; 00581 } 00582 00583 00584 static int gfind_nodef (lua_State *L) { 00585 return luaL_error(L, LUA_QL("string.gfind") " was renamed to " 00586 LUA_QL("string.gmatch")); 00587 } 00588 00589 00590 static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, 00591 const char *e) { 00592 size_t l, i; 00593 const char *news = lua_tolstring(ms->L, 3, &l); 00594 for (i = 0; i < l; i++) { 00595 if (news[i] != L_ESC) 00596 luaL_addchar(b, news[i]); 00597 else { 00598 i++; /* skip ESC */ 00599 if (!isdigit(uchar(news[i]))) 00600 luaL_addchar(b, news[i]); 00601 else if (news[i] == '0') 00602 luaL_addlstring(b, s, e - s); 00603 else { 00604 push_onecapture(ms, news[i] - '1', s, e); 00605 luaL_addvalue(b); /* add capture to accumulated result */ 00606 } 00607 } 00608 } 00609 } 00610 00611 00612 static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, 00613 const char *e) { 00614 lua_State *L = ms->L; 00615 switch (lua_type(L, 3)) { 00616 case LUA_TNUMBER: 00617 case LUA_TSTRING: { 00618 add_s(ms, b, s, e); 00619 return; 00620 } 00621 case LUA_TFUNCTION: { 00622 int n; 00623 lua_pushvalue(L, 3); 00624 n = push_captures(ms, s, e); 00625 lua_call(L, n, 1); 00626 break; 00627 } 00628 case LUA_TTABLE: { 00629 push_onecapture(ms, 0, s, e); 00630 lua_gettable(L, 3); 00631 break; 00632 } 00633 } 00634 if (!lua_toboolean(L, -1)) { /* nil or false? */ 00635 lua_pop(L, 1); 00636 lua_pushlstring(L, s, e - s); /* keep original text */ 00637 } 00638 else if (!lua_isstring(L, -1)) 00639 luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); 00640 luaL_addvalue(b); /* add result to accumulator */ 00641 } 00642 00643 00644 static int str_gsub (lua_State *L) { 00645 size_t srcl; 00646 const char *src = luaL_checklstring(L, 1, &srcl); 00647 const char *p = luaL_checkstring(L, 2); 00648 int tr = lua_type(L, 3); 00649 int max_s = luaL_optint(L, 4, srcl+1); 00650 int anchor = (*p == '^') ? (p++, 1) : 0; 00651 int n = 0; 00652 MatchState ms; 00653 luaL_Buffer b; 00654 luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || 00655 tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, 00656 "string/function/table expected"); 00657 luaL_buffinit(L, &b); 00658 ms.L = L; 00659 ms.src_init = src; 00660 ms.src_end = src+srcl; 00661 while (n < max_s) { 00662 const char *e; 00663 ms.level = 0; 00664 e = match(&ms, src, p); 00665 if (e) { 00666 n++; 00667 add_value(&ms, &b, src, e); 00668 } 00669 if (e && e>src) /* non empty match? */ 00670 src = e; /* skip it */ 00671 else if (src < ms.src_end) 00672 luaL_addchar(&b, *src++); 00673 else break; 00674 if (anchor) break; 00675 } 00676 luaL_addlstring(&b, src, ms.src_end-src); 00677 luaL_pushresult(&b); 00678 lua_pushinteger(L, n); /* number of substitutions */ 00679 return 2; 00680 } 00681 00682 /* }====================================================== */ 00683 00684 00685 /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ 00686 #define MAX_ITEM 512 00687 /* valid flags in a format specification */ 00688 #define FLAGS "-+ #0" 00689 /* 00690 ** maximum size of each format specification (such as '%-099.99d') 00691 ** (+10 accounts for %99.99x plus margin of error) 00692 */ 00693 #define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) 00694 00695 00696 static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { 00697 size_t l; 00698 const char *s = luaL_checklstring(L, arg, &l); 00699 luaL_addchar(b, '"'); 00700 while (l--) { 00701 switch (*s) { 00702 case '"': case '\\': case '\n': { 00703 luaL_addchar(b, '\\'); 00704 luaL_addchar(b, *s); 00705 break; 00706 } 00707 case '\r': { 00708 luaL_addlstring(b, "\\r", 2); 00709 break; 00710 } 00711 case '\0': { 00712 luaL_addlstring(b, "\\000", 4); 00713 break; 00714 } 00715 default: { 00716 luaL_addchar(b, *s); 00717 break; 00718 } 00719 } 00720 s++; 00721 } 00722 luaL_addchar(b, '"'); 00723 } 00724 00725 static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { 00726 const char *p = strfrmt; 00727 while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ 00728 if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) 00729 luaL_error(L, "invalid format (repeated flags)"); 00730 if (isdigit(uchar(*p))) p++; /* skip width */ 00731 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 00732 if (*p == '.') { 00733 p++; 00734 if (isdigit(uchar(*p))) p++; /* skip precision */ 00735 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 00736 } 00737 if (isdigit(uchar(*p))) 00738 luaL_error(L, "invalid format (width or precision too long)"); 00739 *(form++) = '%'; 00740 strncpy(form, strfrmt, p - strfrmt + 1); 00741 form += p - strfrmt + 1; 00742 *form = '\0'; 00743 return p; 00744 } 00745 00746 00747 static void addintlen (char *form) { 00748 size_t l = strlen(form); 00749 char spec = form[l - 1]; 00750 strcpy(form + l - 1, LUA_INTFRMLEN); 00751 form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; 00752 form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; 00753 } 00754 00755 00756 static int str_format (lua_State *L) { 00757 //logt("str_format"); 00758 int arg = 1; 00759 size_t sfl; 00760 const char *strfrmt = luaL_checklstring(L, arg, &sfl); 00761 //logt(strfrmt); 00762 const char *strfrmt_end = strfrmt+sfl; 00763 luaL_Buffer b; 00764 luaL_buffinit(L, &b); 00765 while (strfrmt < strfrmt_end) { 00766 if (*strfrmt != L_ESC) 00767 luaL_addchar(&b, *strfrmt++); 00768 else if (*++strfrmt == L_ESC) 00769 luaL_addchar(&b, *strfrmt++); /* %% */ 00770 else { /* format item */ 00771 char form[MAX_FORMAT]; /* to store the format (`%...') */ 00772 char buff[MAX_ITEM]; /* to store the formatted item */ 00773 arg++; 00774 //logt("entering scanformat"); 00775 strfrmt = scanformat(L, strfrmt, form); 00776 //logt("exiting scanformat"); 00777 //logt(strfrmt); 00778 switch (*strfrmt++) { 00779 case 'c': { 00780 sprintf(buff, form, (int)luaL_checknumber(L, arg)); 00781 break; 00782 } 00783 case 'd': case 'i': { 00784 addintlen(form); 00785 sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); 00786 break; 00787 } 00788 case 'o': case 'u': case 'x': case 'X': { 00789 addintlen(form); 00790 sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); 00791 break; 00792 } 00793 case 'e': case 'E': case 'f': 00794 case 'g': case 'G': { 00795 sprintf(buff, form, (double)luaL_checknumber(L, arg)); 00796 break; 00797 } 00798 case 'q': { 00799 addquoted(L, &b, arg); 00800 continue; /* skip the 'addsize' at the end */ 00801 } 00802 case 's': { 00803 size_t l; 00804 const char *s = luaL_checklstring(L, arg, &l); 00805 if (!strchr(form, '.') && l >= 100) { 00806 /* no precision and string is too long to be formatted; 00807 keep original string */ 00808 lua_pushvalue(L, arg); 00809 luaL_addvalue(&b); 00810 continue; /* skip the `addsize' at the end */ 00811 } 00812 else { 00813 sprintf(buff, form, s); 00814 break; 00815 } 00816 } 00817 default: { /* also treat cases `pnLlh' */ 00818 return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " 00819 LUA_QL("format"), *(strfrmt - 1)); 00820 } 00821 } 00822 luaL_addlstring(&b, buff, strlen(buff)); 00823 } 00824 } 00825 luaL_pushresult(&b); 00826 return 1; 00827 } 00828 00829 00830 static const luaL_Reg strlib[] = { 00831 {"byte", str_byte}, 00832 {"char", str_char}, 00833 {"dump", str_dump}, 00834 {"find", str_find}, 00835 {"format", str_format}, 00836 {"gfind", gfind_nodef}, 00837 {"gmatch", gmatch}, 00838 {"gsub", str_gsub}, 00839 {"len", str_len}, 00840 {"lower", str_lower}, 00841 {"match", str_match}, 00842 {"rep", str_rep}, 00843 {"reverse", str_reverse}, 00844 {"sub", str_sub}, 00845 {"upper", str_upper}, 00846 {NULL, NULL} 00847 }; 00848 00849 00850 static void createmetatable (lua_State *L) { 00851 lua_createtable(L, 0, 1); /* create metatable for strings */ 00852 lua_pushliteral(L, ""); /* dummy string */ 00853 lua_pushvalue(L, -2); 00854 lua_setmetatable(L, -2); /* set string metatable */ 00855 lua_pop(L, 1); /* pop dummy string */ 00856 lua_pushvalue(L, -2); /* string library... */ 00857 lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ 00858 lua_pop(L, 1); /* pop metatable */ 00859 } 00860 00861 00862 /* 00863 ** Open string library 00864 */ 00865 LUALIB_API int luaopen_string (lua_State *L) { 00866 luaL_register(L, LUA_STRLIBNAME, strlib); 00867 #if defined(LUA_COMPAT_GFIND) 00868 lua_getfield(L, -1, "gmatch"); 00869 lua_setfield(L, -2, "gfind"); 00870 #endif 00871 createmetatable(L); 00872 return 1; 00873 } 00874
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:54 2011 by Doxygen 1.6.1