Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/lua/lstrlib.c @ 2163

Last change on this file since 2163 was 1806, checked in by rgrieder, 16 years ago

added single 5.1.3 directory for lua since CEGUILua 0.5 can also build against lua 5.1

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