lstrlib.c

Go to the documentation of this file.
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