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