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