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