8752e3aba3e194142cfb5c07fc9f68a8b49bbded
[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   const char *src;
521   ms.L = L;
522   ms.src_init = s;
523   ms.src_end = s+ls;
524   for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3));
525        src <= ms.src_end;
526        src++) {
527     const char *e;
528     ms.level = 0;
529     if ((e = match(&ms, src, p)) != NULL) {
530       int newstart = e-s;
531       if (e == src) newstart++;  /* empty match? go at least one position */
532       lua_pushnumber(L, (lua_Number)newstart);
533       lua_replace(L, lua_upvalueindex(3));
534       return push_captures(&ms, src, e);
535     }
536   }
537   return 0;  /* not found */
538 }
539
540
541 static int gfind (lua_State *L) {
542   luaL_checkstring(L, 1);
543   luaL_checkstring(L, 2);
544   lua_settop(L, 2);
545   lua_pushnumber(L, 0);
546   lua_pushcclosure(L, gfind_aux, 3);
547   return 1;
548 }
549
550
551 static void add_s (MatchState *ms, luaL_Buffer *b,
552                    const char *s, const char *e) {
553   lua_State *L = ms->L;
554   if (lua_isstring(L, 3)) {
555     const char *news = lua_tostring(L, 3);
556     size_t l = lua_strlen(L, 3);
557     size_t i;
558     for (i=0; i<l; i++) {
559       if (news[i] != ESC)
560         luaL_putchar(b, news[i]);
561       else {
562         i++;  /* skip ESC */
563         if (!isdigit(uchar(news[i])))
564           luaL_putchar(b, news[i]);
565         else {
566           int level = check_capture(ms, news[i]);
567           push_onecapture(ms, level);
568           luaL_addvalue(b);  /* add capture to accumulated result */
569         }
570       }
571     }
572   }
573   else {  /* is a function */
574     int n;
575     lua_pushvalue(L, 3);
576     n = push_captures(ms, s, e);
577     lua_call(L, n, 1);
578     if (lua_isstring(L, -1))
579       luaL_addvalue(b);  /* add return to accumulated result */
580     else
581       lua_pop(L, 1);  /* function result is not a string: pop it */
582   }
583 }
584
585
586 static int str_gsub (lua_State *L) {
587   size_t srcl;
588   const char *src = luaL_checklstring(L, 1, &srcl);
589   const char *p = luaL_checkstring(L, 2);
590   int max_s = luaL_optint(L, 4, srcl+1);
591   int anchor = (*p == '^') ? (p++, 1) : 0;
592   int n = 0;
593   MatchState ms;
594   luaL_Buffer b;
595   luaL_argcheck(L,
596     lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
597     3, "string or function expected");
598   luaL_buffinit(L, &b);
599   ms.L = L;
600   ms.src_init = src;
601   ms.src_end = src+srcl;
602   while (n < max_s) {
603     const char *e;
604     ms.level = 0;
605     e = match(&ms, src, p);
606     if (e) {
607       n++;
608       add_s(&ms, &b, src, e);
609     }
610     if (e && e>src) /* non empty match? */
611       src = e;  /* skip it */
612     else if (src < ms.src_end)
613       luaL_putchar(&b, *src++);
614     else break;
615     if (anchor) break;
616   }
617   luaL_addlstring(&b, src, ms.src_end-src);
618   luaL_pushresult(&b);
619   lua_pushnumber(L, (lua_Number)n);  /* number of substitutions */
620   return 2;
621 }
622
623 /* }====================================================== */
624
625
626 /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
627 #define MAX_ITEM        512
628 /* maximum size of each format specification (such as '%-099.99d') */
629 #define MAX_FORMAT      20
630
631
632 static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
633   size_t l;
634   const char *s = luaL_checklstring(L, arg, &l);
635   luaL_putchar(b, '"');
636   while (l--) {
637     switch (*s) {
638       case '"': case '\\': case '\n': {
639         luaL_putchar(b, '\\');
640         luaL_putchar(b, *s);
641         break;
642       }
643       case '\0': {
644         luaL_addlstring(b, "\\000", 4);
645         break;
646       }
647       default: {
648         luaL_putchar(b, *s);
649         break;
650       }
651     }
652     s++;
653   }
654   luaL_putchar(b, '"');
655 }
656
657
658 static const char *scanformat (lua_State *L, const char *strfrmt,
659                                  char *form, int *hasprecision) {
660   const char *p = strfrmt;
661   while (strchr("-+ #0", *p)) p++;  /* skip flags */
662   if (isdigit(uchar(*p))) p++;  /* skip width */
663   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
664   if (*p == '.') {
665     p++;
666     *hasprecision = 1;
667     if (isdigit(uchar(*p))) p++;  /* skip precision */
668     if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
669   }
670   if (isdigit(uchar(*p)))
671     luaL_error(L, "invalid format (width or precision too long)");
672   if (p-strfrmt+2 > MAX_FORMAT)  /* +2 to include `%' and the specifier */
673     luaL_error(L, "invalid format (too long)");
674   form[0] = '%';
675   strncpy(form+1, strfrmt, p-strfrmt+1);
676   form[p-strfrmt+2] = 0;
677   return p;
678 }
679
680
681 static int str_format (lua_State *L) {
682   int arg = 1;
683   size_t sfl;
684   const char *strfrmt = luaL_checklstring(L, arg, &sfl);
685   const char *strfrmt_end = strfrmt+sfl;
686   luaL_Buffer b;
687   luaL_buffinit(L, &b);
688   while (strfrmt < strfrmt_end) {
689     if (*strfrmt != '%')
690       luaL_putchar(&b, *strfrmt++);
691     else if (*++strfrmt == '%')
692       luaL_putchar(&b, *strfrmt++);  /* %% */
693     else { /* format item */
694       char form[MAX_FORMAT];  /* to store the format (`%...') */
695       char buff[MAX_ITEM];  /* to store the formatted item */
696       int hasprecision = 0;
697       if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$')
698         return luaL_error(L, "obsolete option (d$) to `format'");
699       arg++;
700       strfrmt = scanformat(L, strfrmt, form, &hasprecision);
701       switch (*strfrmt++) {
702         case 'c':  case 'd':  case 'i': {
703           sprintf(buff, form, luaL_checkint(L, arg));
704           break;
705         }
706         case 'o':  case 'u':  case 'x':  case 'X': {
707           sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg)));
708           break;
709         }
710         case 'e':  case 'E': case 'f':
711         case 'g': case 'G': {
712           sprintf(buff, form, luaL_checknumber(L, arg));
713           break;
714         }
715         case 'q': {
716           luaI_addquoted(L, &b, arg);
717           continue;  /* skip the `addsize' at the end */
718         }
719         case 's': {
720           size_t l;
721           const char *s = luaL_checklstring(L, arg, &l);
722           if (!hasprecision && l >= 100) {
723             /* no precision and string is too long to be formatted;
724                keep original string */
725             lua_pushvalue(L, arg);
726             luaL_addvalue(&b);
727             continue;  /* skip the `addsize' at the end */
728           }
729           else {
730             sprintf(buff, form, s);
731             break;
732           }
733         }
734         default: {  /* also treat cases `pnLlh' */
735           return luaL_error(L, "invalid option to `format'");
736         }
737       }
738       luaL_addlstring(&b, buff, strlen(buff));
739     }
740   }
741   luaL_pushresult(&b);
742   return 1;
743 }
744
745
746 static const luaL_reg strlib[] = {
747   {"len", str_len},
748   {"sub", str_sub},
749   {"lower", str_lower},
750   {"upper", str_upper},
751   {"char", str_char},
752   {"rep", str_rep},
753   {"byte", str_byte},
754   {"format", str_format},
755   {"dump", str_dump},
756   {"find", str_find},
757   {"gfind", gfind},
758   {"gsub", str_gsub},
759   {NULL, NULL}
760 };
761
762
763 /*
764 ** Open string library
765 */
766 LUALIB_API int luaopen_string (lua_State *L) {
767   luaL_openlib(L, LUA_STRLIBNAME, strlib, 0);
768   return 1;
769 }
770