1/* $NetBSD$ */ 2 3/* 4** Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp 5** Standard library for string operations and pattern-matching 6** See Copyright Notice in lua.h 7*/ 8 9 10#include <ctype.h> 11#include <stddef.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15 16#define lstrlib_c 17#define LUA_LIB 18 19#include "lua.h" 20 21#include "lauxlib.h" 22#include "lualib.h" 23 24 25/* macro to `unsign' a character */ 26#define uchar(c) ((unsigned char)(c)) 27 28 29 30static int str_len (lua_State *L) { 31 size_t l; 32 luaL_checklstring(L, 1, &l); 33 lua_pushinteger(L, l); 34 return 1; 35} 36 37 38static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { 39 /* relative string position: negative means back from end */ 40 if (pos < 0) pos += (ptrdiff_t)len + 1; 41 return (pos >= 0) ? pos : 0; 42} 43 44 45static int str_sub (lua_State *L) { 46 size_t l; 47 const char *s = luaL_checklstring(L, 1, &l); 48 ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); 49 ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); 50 if (start < 1) start = 1; 51 if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; 52 if (start <= end) 53 lua_pushlstring(L, s+start-1, end-start+1); 54 else lua_pushliteral(L, ""); 55 return 1; 56} 57 58 59static int str_reverse (lua_State *L) { 60 size_t l; 61 luaL_Buffer b; 62 const char *s = luaL_checklstring(L, 1, &l); 63 luaL_buffinit(L, &b); 64 while (l--) luaL_addchar(&b, s[l]); 65 luaL_pushresult(&b); 66 return 1; 67} 68 69 70static int str_lower (lua_State *L) { 71 size_t l; 72 size_t i; 73 luaL_Buffer b; 74 const char *s = luaL_checklstring(L, 1, &l); 75 luaL_buffinit(L, &b); 76 for (i=0; i<l; i++) 77 luaL_addchar(&b, tolower(uchar(s[i]))); 78 luaL_pushresult(&b); 79 return 1; 80} 81 82 83static int str_upper (lua_State *L) { 84 size_t l; 85 size_t i; 86 luaL_Buffer b; 87 const char *s = luaL_checklstring(L, 1, &l); 88 luaL_buffinit(L, &b); 89 for (i=0; i<l; i++) 90 luaL_addchar(&b, toupper(uchar(s[i]))); 91 luaL_pushresult(&b); 92 return 1; 93} 94 95static int str_rep (lua_State *L) { 96 size_t l; 97 luaL_Buffer b; 98 const char *s = luaL_checklstring(L, 1, &l); 99 int n = luaL_checkint(L, 2); 100 luaL_buffinit(L, &b); 101 while (n-- > 0) 102 luaL_addlstring(&b, s, l); 103 luaL_pushresult(&b); 104 return 1; 105} 106 107 108static int str_byte (lua_State *L) { 109 size_t l; 110 const char *s = luaL_checklstring(L, 1, &l); 111 ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); 112 ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); 113 int n, i; 114 if (posi <= 0) posi = 1; 115 if ((size_t)pose > l) pose = l; 116 if (posi > pose) return 0; /* empty interval; return no values */ 117 n = (int)(pose - posi + 1); 118 if (posi + n <= pose) /* overflow? */ 119 luaL_error(L, "string slice too long"); 120 luaL_checkstack(L, n, "string slice too long"); 121 for (i=0; i<n; i++) 122 lua_pushinteger(L, uchar(s[posi+i-1])); 123 return n; 124} 125 126 127static int str_char (lua_State *L) { 128 int n = lua_gettop(L); /* number of arguments */ 129 int i; 130 luaL_Buffer b; 131 luaL_buffinit(L, &b); 132 for (i=1; i<=n; i++) { 133 int c = luaL_checkint(L, i); 134 luaL_argcheck(L, uchar(c) == c, i, "invalid value"); 135 luaL_addchar(&b, uchar(c)); 136 } 137 luaL_pushresult(&b); 138 return 1; 139} 140 141 142static int writer (lua_State *L, const void* b, size_t size, void* B) { 143 (void)L; 144 luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); 145 return 0; 146} 147 148 149static int str_dump (lua_State *L) { 150 luaL_Buffer b; 151 luaL_checktype(L, 1, LUA_TFUNCTION); 152 lua_settop(L, 1); 153 luaL_buffinit(L,&b); 154 if (lua_dump(L, writer, &b) != 0) 155 luaL_error(L, "unable to dump given function"); 156 luaL_pushresult(&b); 157 return 1; 158} 159 160 161 162/* 163** {====================================================== 164** PATTERN MATCHING 165** ======================================================= 166*/ 167 168 169#define CAP_UNFINISHED (-1) 170#define CAP_POSITION (-2) 171 172typedef struct MatchState { 173 const char *src_init; /* init of source string */ 174 const char *src_end; /* end (`\0') of source string */ 175 lua_State *L; 176 int level; /* total number of captures (finished or unfinished) */ 177 struct { 178 const char *init; 179 ptrdiff_t len; 180 } capture[LUA_MAXCAPTURES]; 181} MatchState; 182 183 184#define L_ESC '%' 185#define SPECIALS "^$*+?.([%-" 186 187 188static int check_capture (MatchState *ms, int l) { 189 l -= '1'; 190 if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) 191 return luaL_error(ms->L, "invalid capture index"); 192 return l; 193} 194 195 196static int capture_to_close (MatchState *ms) { 197 int level = ms->level; 198 for (level--; level>=0; level--) 199 if (ms->capture[level].len == CAP_UNFINISHED) return level; 200 return luaL_error(ms->L, "invalid pattern capture"); 201} 202 203 204static const char *classend (MatchState *ms, const char *p) { 205 switch (*p++) { 206 case L_ESC: { 207 if (*p == '\0') 208 luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); 209 return p+1; 210 } 211 case '[': { 212 if (*p == '^') p++; 213 do { /* look for a `]' */ 214 if (*p == '\0') 215 luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); 216 if (*(p++) == L_ESC && *p != '\0') 217 p++; /* skip escapes (e.g. `%]') */ 218 } while (*p != ']'); 219 return p+1; 220 } 221 default: { 222 return p; 223 } 224 } 225} 226 227 228static int match_class (int c, int cl) { 229 int res; 230 switch (tolower(cl)) { 231 case 'a' : res = isalpha(c); break; 232 case 'c' : res = iscntrl(c); break; 233 case 'd' : res = isdigit(c); break; 234 case 'l' : res = islower(c); break; 235 case 'p' : res = ispunct(c); break; 236 case 's' : res = isspace(c); break; 237 case 'u' : res = isupper(c); break; 238 case 'w' : res = isalnum(c); break; 239 case 'x' : res = isxdigit(c); break; 240 case 'z' : res = (c == 0); break; 241 default: return (cl == c); 242 } 243 return (islower(cl) ? res : !res); 244} 245 246 247static int matchbracketclass (int c, const char *p, const char *ec) { 248 int sig = 1; 249 if (*(p+1) == '^') { 250 sig = 0; 251 p++; /* skip the `^' */ 252 } 253 while (++p < ec) { 254 if (*p == L_ESC) { 255 p++; 256 if (match_class(c, uchar(*p))) 257 return sig; 258 } 259 else if ((*(p+1) == '-') && (p+2 < ec)) { 260 p+=2; 261 if (uchar(*(p-2)) <= c && c <= uchar(*p)) 262 return sig; 263 } 264 else if (uchar(*p) == c) return sig; 265 } 266 return !sig; 267} 268 269 270static int singlematch (int c, const char *p, const char *ep) { 271 switch (*p) { 272 case '.': return 1; /* matches any char */ 273 case L_ESC: return match_class(c, uchar(*(p+1))); 274 case '[': return matchbracketclass(c, p, ep-1); 275 default: return (uchar(*p) == c); 276 } 277} 278 279 280static const char *match (MatchState *ms, const char *s, const char *p); 281 282 283static const char *matchbalance (MatchState *ms, const char *s, 284 const char *p) { 285 if (*p == 0 || *(p+1) == 0) 286 luaL_error(ms->L, "unbalanced pattern"); 287 if (*s != *p) return NULL; 288 else { 289 int b = *p; 290 int e = *(p+1); 291 int cont = 1; 292 while (++s < ms->src_end) { 293 if (*s == e) { 294 if (--cont == 0) return s+1; 295 } 296 else if (*s == b) cont++; 297 } 298 } 299 return NULL; /* string ends out of balance */ 300} 301 302 303static const char *max_expand (MatchState *ms, const char *s, 304 const char *p, const char *ep) { 305 ptrdiff_t i = 0; /* counts maximum expand for item */ 306 while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) 307 i++; 308 /* keeps trying to match with the maximum repetitions */ 309 while (i>=0) { 310 const char *res = match(ms, (s+i), ep+1); 311 if (res) return res; 312 i--; /* else didn't match; reduce 1 repetition to try again */ 313 } 314 return NULL; 315} 316 317 318static const char *min_expand (MatchState *ms, const char *s, 319 const char *p, const char *ep) { 320 for (;;) { 321 const char *res = match(ms, s, ep+1); 322 if (res != NULL) 323 return res; 324 else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) 325 s++; /* try with one more repetition */ 326 else return NULL; 327 } 328} 329 330 331static const char *start_capture (MatchState *ms, const char *s, 332 const char *p, int what) { 333 const char *res; 334 int level = ms->level; 335 if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); 336 ms->capture[level].init = s; 337 ms->capture[level].len = what; 338 ms->level = level+1; 339 if ((res=match(ms, s, p)) == NULL) /* match failed? */ 340 ms->level--; /* undo capture */ 341 return res; 342} 343 344 345static const char *end_capture (MatchState *ms, const char *s, 346 const char *p) { 347 int l = capture_to_close(ms); 348 const char *res; 349 ms->capture[l].len = s - ms->capture[l].init; /* close capture */ 350 if ((res = match(ms, s, p)) == NULL) /* match failed? */ 351 ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ 352 return res; 353} 354 355 356static const char *match_capture (MatchState *ms, const char *s, int l) { 357 size_t len; 358 l = check_capture(ms, l); 359 len = ms->capture[l].len; 360 if ((size_t)(ms->src_end-s) >= len && 361 memcmp(ms->capture[l].init, s, len) == 0) 362 return s+len; 363 else return NULL; 364} 365 366 367static const char *match (MatchState *ms, const char *s, const char *p) { 368 init: /* using goto's to optimize tail recursion */ 369 switch (*p) { 370 case '(': { /* start capture */ 371 if (*(p+1) == ')') /* position capture? */ 372 return start_capture(ms, s, p+2, CAP_POSITION); 373 else 374 return start_capture(ms, s, p+1, CAP_UNFINISHED); 375 } 376 case ')': { /* end capture */ 377 return end_capture(ms, s, p+1); 378 } 379 case L_ESC: { 380 switch (*(p+1)) { 381 case 'b': { /* balanced string? */ 382 s = matchbalance(ms, s, p+2); 383 if (s == NULL) return NULL; 384 p+=4; goto init; /* else return match(ms, s, p+4); */ 385 } 386 case 'f': { /* frontier? */ 387 const char *ep; char previous; 388 p += 2; 389 if (*p != '[') 390 luaL_error(ms->L, "missing " LUA_QL("[") " after " 391 LUA_QL("%%f") " in pattern"); 392 ep = classend(ms, p); /* points to what is next */ 393 previous = (s == ms->src_init) ? '\0' : *(s-1); 394 if (matchbracketclass(uchar(previous), p, ep-1) || 395 !matchbracketclass(uchar(*s), p, ep-1)) return NULL; 396 p=ep; goto init; /* else return match(ms, s, ep); */ 397 } 398 default: { 399 if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ 400 s = match_capture(ms, s, uchar(*(p+1))); 401 if (s == NULL) return NULL; 402 p+=2; goto init; /* else return match(ms, s, p+2) */ 403 } 404 goto dflt; /* case default */ 405 } 406 } 407 } 408 case '\0': { /* end of pattern */ 409 return s; /* match succeeded */ 410 } 411 case '$': { 412 if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ 413 return (s == ms->src_end) ? s : NULL; /* check end of string */ 414 else goto dflt; 415 } 416 default: dflt: { /* it is a pattern item */ 417 const char *ep = classend(ms, p); /* points to what is next */ 418 int m = s<ms->src_end && singlematch(uchar(*s), p, ep); 419 switch (*ep) { 420 case '?': { /* optional */ 421 const char *res; 422 if (m && ((res=match(ms, s+1, ep+1)) != NULL)) 423 return res; 424 p=ep+1; goto init; /* else return match(ms, s, ep+1); */ 425 } 426 case '*': { /* 0 or more repetitions */ 427 return max_expand(ms, s, p, ep); 428 } 429 case '+': { /* 1 or more repetitions */ 430 return (m ? max_expand(ms, s+1, p, ep) : NULL); 431 } 432 case '-': { /* 0 or more repetitions (minimum) */ 433 return min_expand(ms, s, p, ep); 434 } 435 default: { 436 if (!m) return NULL; 437 s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ 438 } 439 } 440 } 441 } 442} 443 444 445 446static const char *lmemfind (const char *s1, size_t l1, 447 const char *s2, size_t l2) { 448 if (l2 == 0) return s1; /* empty strings are everywhere */ 449 else if (l2 > l1) return NULL; /* avoids a negative `l1' */ 450 else { 451 const char *init; /* to search for a `*s2' inside `s1' */ 452 l2--; /* 1st char will be checked by `memchr' */ 453 l1 = l1-l2; /* `s2' cannot be found after that */ 454 while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { 455 init++; /* 1st char is already checked */ 456 if (memcmp(init, s2+1, l2) == 0) 457 return init-1; 458 else { /* correct `l1' and `s1' to try again */ 459 l1 -= init-s1; 460 s1 = init; 461 } 462 } 463 return NULL; /* not found */ 464 } 465} 466 467 468static void push_onecapture (MatchState *ms, int i, const char *s, 469 const char *e) { 470 if (i >= ms->level) { 471 if (i == 0) /* ms->level == 0, too */ 472 lua_pushlstring(ms->L, s, e - s); /* add whole match */ 473 else 474 luaL_error(ms->L, "invalid capture index"); 475 } 476 else { 477 ptrdiff_t l = ms->capture[i].len; 478 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); 479 if (l == CAP_POSITION) 480 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); 481 else 482 lua_pushlstring(ms->L, ms->capture[i].init, l); 483 } 484} 485 486 487static int push_captures (MatchState *ms, const char *s, const char *e) { 488 int i; 489 int nlevels = (ms->level == 0 && s) ? 1 : ms->level; 490 luaL_checkstack(ms->L, nlevels, "too many captures"); 491 for (i = 0; i < nlevels; i++) 492 push_onecapture(ms, i, s, e); 493 return nlevels; /* number of strings pushed */ 494} 495 496 497static int str_find_aux (lua_State *L, int find) { 498 size_t l1, l2; 499 const char *s = luaL_checklstring(L, 1, &l1); 500 const char *p = luaL_checklstring(L, 2, &l2); 501 ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; 502 if (init < 0) init = 0; 503 else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; 504 if (find && (lua_toboolean(L, 4) || /* explicit request? */ 505 strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ 506 /* do a plain search */ 507 const char *s2 = lmemfind(s+init, l1-init, p, l2); 508 if (s2) { 509 lua_pushinteger(L, s2-s+1); 510 lua_pushinteger(L, s2-s+l2); 511 return 2; 512 } 513 } 514 else { 515 MatchState ms; 516 int anchor = (*p == '^') ? (p++, 1) : 0; 517 const char *s1=s+init; 518 ms.L = L; 519 ms.src_init = s; 520 ms.src_end = s+l1; 521 do { 522 const char *res; 523 ms.level = 0; 524 if ((res=match(&ms, s1, p)) != NULL) { 525 if (find) { 526 lua_pushinteger(L, s1-s+1); /* start */ 527 lua_pushinteger(L, res-s); /* end */ 528 return push_captures(&ms, NULL, 0) + 2; 529 } 530 else 531 return push_captures(&ms, s1, res); 532 } 533 } while (s1++ < ms.src_end && !anchor); 534 } 535 lua_pushnil(L); /* not found */ 536 return 1; 537} 538 539 540static int str_find (lua_State *L) { 541 return str_find_aux(L, 1); 542} 543 544 545static int str_match (lua_State *L) { 546 return str_find_aux(L, 0); 547} 548 549 550static int gmatch_aux (lua_State *L) { 551 MatchState ms; 552 size_t ls; 553 const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); 554 const char *p = lua_tostring(L, lua_upvalueindex(2)); 555 const char *src; 556 ms.L = L; 557 ms.src_init = s; 558 ms.src_end = s+ls; 559 for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); 560 src <= ms.src_end; 561 src++) { 562 const char *e; 563 ms.level = 0; 564 if ((e = match(&ms, src, p)) != NULL) { 565 lua_Integer newstart = e-s; 566 if (e == src) newstart++; /* empty match? go at least one position */ 567 lua_pushinteger(L, newstart); 568 lua_replace(L, lua_upvalueindex(3)); 569 return push_captures(&ms, src, e); 570 } 571 } 572 return 0; /* not found */ 573} 574 575 576static int gmatch (lua_State *L) { 577 luaL_checkstring(L, 1); 578 luaL_checkstring(L, 2); 579 lua_settop(L, 2); 580 lua_pushinteger(L, 0); 581 lua_pushcclosure(L, gmatch_aux, 3); 582 return 1; 583} 584 585 586static int gfind_nodef (lua_State *L) { 587 return luaL_error(L, LUA_QL("string.gfind") " was renamed to " 588 LUA_QL("string.gmatch")); 589} 590 591 592static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, 593 const char *e) { 594 size_t l, i; 595 const char *news = lua_tolstring(ms->L, 3, &l); 596 for (i = 0; i < l; i++) { 597 if (news[i] != L_ESC) 598 luaL_addchar(b, news[i]); 599 else { 600 i++; /* skip ESC */ 601 if (!isdigit(uchar(news[i]))) 602 luaL_addchar(b, news[i]); 603 else if (news[i] == '0') 604 luaL_addlstring(b, s, e - s); 605 else { 606 push_onecapture(ms, news[i] - '1', s, e); 607 luaL_addvalue(b); /* add capture to accumulated result */ 608 } 609 } 610 } 611} 612 613 614static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, 615 const char *e) { 616 lua_State *L = ms->L; 617 switch (lua_type(L, 3)) { 618 case LUA_TNUMBER: 619 case LUA_TSTRING: { 620 add_s(ms, b, s, e); 621 return; 622 } 623 case LUA_TFUNCTION: { 624 int n; 625 lua_pushvalue(L, 3); 626 n = push_captures(ms, s, e); 627 lua_call(L, n, 1); 628 break; 629 } 630 case LUA_TTABLE: { 631 push_onecapture(ms, 0, s, e); 632 lua_gettable(L, 3); 633 break; 634 } 635 } 636 if (!lua_toboolean(L, -1)) { /* nil or false? */ 637 lua_pop(L, 1); 638 lua_pushlstring(L, s, e - s); /* keep original text */ 639 } 640 else if (!lua_isstring(L, -1)) 641 luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); 642 luaL_addvalue(b); /* add result to accumulator */ 643} 644 645 646static int str_gsub (lua_State *L) { 647 size_t srcl; 648 const char *src = luaL_checklstring(L, 1, &srcl); 649 const char *p = luaL_checkstring(L, 2); 650 int tr = lua_type(L, 3); 651 int max_s = luaL_optint(L, 4, srcl+1); 652 int anchor = (*p == '^') ? (p++, 1) : 0; 653 int n = 0; 654 MatchState ms; 655 luaL_Buffer b; 656 luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || 657 tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, 658 "string/function/table expected"); 659 luaL_buffinit(L, &b); 660 ms.L = L; 661 ms.src_init = src; 662 ms.src_end = src+srcl; 663 while (n < max_s) { 664 const char *e; 665 ms.level = 0; 666 e = match(&ms, src, p); 667 if (e) { 668 n++; 669 add_value(&ms, &b, src, e); 670 } 671 if (e && e>src) /* non empty match? */ 672 src = e; /* skip it */ 673 else if (src < ms.src_end) 674 luaL_addchar(&b, *src++); 675 else break; 676 if (anchor) break; 677 } 678 luaL_addlstring(&b, src, ms.src_end-src); 679 luaL_pushresult(&b); 680 lua_pushinteger(L, n); /* number of substitutions */ 681 return 2; 682} 683 684/* }====================================================== */ 685 686 687/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ 688#define MAX_ITEM 512 689/* valid flags in a format specification */ 690#define FLAGS "-+ #0" 691/* 692** maximum size of each format specification (such as '%-099.99d') 693** (+10 accounts for %99.99x plus margin of error) 694*/ 695#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) 696 697 698static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { 699 size_t l; 700 const char *s = luaL_checklstring(L, arg, &l); 701 luaL_addchar(b, '"'); 702 while (l--) { 703 switch (*s) { 704 case '"': case '\\': case '\n': { 705 luaL_addchar(b, '\\'); 706 luaL_addchar(b, *s); 707 break; 708 } 709 case '\r': { 710 luaL_addlstring(b, "\\r", 2); 711 break; 712 } 713 case '\0': { 714 luaL_addlstring(b, "\\000", 4); 715 break; 716 } 717 default: { 718 luaL_addchar(b, *s); 719 break; 720 } 721 } 722 s++; 723 } 724 luaL_addchar(b, '"'); 725} 726 727static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { 728 const char *p = strfrmt; 729 while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ 730 if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) 731 luaL_error(L, "invalid format (repeated flags)"); 732 if (isdigit(uchar(*p))) p++; /* skip width */ 733 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 734 if (*p == '.') { 735 p++; 736 if (isdigit(uchar(*p))) p++; /* skip precision */ 737 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 738 } 739 if (isdigit(uchar(*p))) 740 luaL_error(L, "invalid format (width or precision too long)"); 741 *(form++) = '%'; 742 strncpy(form, strfrmt, p - strfrmt + 1); 743 form += p - strfrmt + 1; 744 *form = '\0'; 745 return p; 746} 747 748 749static void addintlen (char *form) { 750 size_t l = strlen(form); 751 char spec = form[l - 1]; 752 strcpy(form + l - 1, LUA_INTFRMLEN); 753 form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; 754 form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; 755} 756 757 758static int str_format (lua_State *L) { 759 int arg = 1; 760 size_t sfl; 761 const char *strfrmt = luaL_checklstring(L, arg, &sfl); 762 const char *strfrmt_end = strfrmt+sfl; 763 luaL_Buffer b; 764 luaL_buffinit(L, &b); 765 while (strfrmt < strfrmt_end) { 766 if (*strfrmt != L_ESC) 767 luaL_addchar(&b, *strfrmt++); 768 else if (*++strfrmt == L_ESC) 769 luaL_addchar(&b, *strfrmt++); /* %% */ 770 else { /* format item */ 771 char form[MAX_FORMAT]; /* to store the format (`%...') */ 772 char buff[MAX_ITEM]; /* to store the formatted item */ 773 arg++; 774 strfrmt = scanformat(L, strfrmt, form); 775 switch (*strfrmt++) { 776 case 'c': { 777 sprintf(buff, form, (int)luaL_checknumber(L, arg)); 778 break; 779 } 780 case 'd': case 'i': { 781 addintlen(form); 782 sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); 783 break; 784 } 785 case 'o': case 'u': case 'x': case 'X': { 786 addintlen(form); 787 sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); 788 break; 789 } 790 case 'e': case 'E': case 'f': 791 case 'g': case 'G': { 792 sprintf(buff, form, (double)luaL_checknumber(L, arg)); 793 break; 794 } 795 case 'q': { 796 addquoted(L, &b, arg); 797 continue; /* skip the 'addsize' at the end */ 798 } 799 case 's': { 800 size_t l; 801 const char *s = luaL_checklstring(L, arg, &l); 802 if (!strchr(form, '.') && l >= 100) { 803 /* no precision and string is too long to be formatted; 804 keep original string */ 805 lua_pushvalue(L, arg); 806 luaL_addvalue(&b); 807 continue; /* skip the `addsize' at the end */ 808 } 809 else { 810 sprintf(buff, form, s); 811 break; 812 } 813 } 814 default: { /* also treat cases `pnLlh' */ 815 return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " 816 LUA_QL("format"), *(strfrmt - 1)); 817 } 818 } 819 luaL_addlstring(&b, buff, strlen(buff)); 820 } 821 } 822 luaL_pushresult(&b); 823 return 1; 824} 825 826 827static const luaL_Reg strlib[] = { 828 {"byte", str_byte}, 829 {"char", str_char}, 830 {"dump", str_dump}, 831 {"find", str_find}, 832 {"format", str_format}, 833 {"gfind", gfind_nodef}, 834 {"gmatch", gmatch}, 835 {"gsub", str_gsub}, 836 {"len", str_len}, 837 {"lower", str_lower}, 838 {"match", str_match}, 839 {"rep", str_rep}, 840 {"reverse", str_reverse}, 841 {"sub", str_sub}, 842 {"upper", str_upper}, 843 {NULL, NULL} 844}; 845 846 847static void createmetatable (lua_State *L) { 848 lua_createtable(L, 0, 1); /* create metatable for strings */ 849 lua_pushliteral(L, ""); /* dummy string */ 850 lua_pushvalue(L, -2); 851 lua_setmetatable(L, -2); /* set string metatable */ 852 lua_pop(L, 1); /* pop dummy string */ 853 lua_pushvalue(L, -2); /* string library... */ 854 lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ 855 lua_pop(L, 1); /* pop metatable */ 856} 857 858 859/* 860** Open string library 861*/ 862LUALIB_API int luaopen_string (lua_State *L) { 863 luaL_register(L, LUA_STRLIBNAME, strlib); 864#if defined(LUA_COMPAT_GFIND) 865 lua_getfield(L, -1, "gmatch"); 866 lua_setfield(L, -2, "gfind"); 867#endif 868 createmetatable(L); 869 return 1; 870} 871 872