3 ** String library to LUA
6 char *rcs_strlib
="$Id: strlib.c,v 1.46 1997/06/19 18:49:40 roberto Exp $";
24 static struct lbuff lbuffer
= {NULL
, 0, 0};
27 static char *strbuffer (unsigned long size
)
29 if (size
> lbuffer
.max
) {
30 /* ANSI "realloc" doesn't need this test, but some machines (Sun!)
32 lbuffer
.b
= (lbuffer
.b
) ? realloc(lbuffer
.b
, lbuffer
.max
=size
) :
33 malloc(lbuffer
.max
=size
);
34 if (lbuffer
.b
== NULL
)
35 lua_error("memory overflow");
40 static char *openspace (unsigned long size
)
42 char *buff
= strbuffer(lbuffer
.size
+size
);
43 return buff
+lbuffer
.size
;
46 char *luaI_addchar (int c
)
48 if (lbuffer
.size
>= lbuffer
.max
)
49 strbuffer(lbuffer
.max
== 0 ? 100 : lbuffer
.max
*2);
50 lbuffer
.b
[lbuffer
.size
++] = c
;
54 void luaI_emptybuff (void)
56 lbuffer
.size
= 0; /* prepare for next string */
60 static void addnchar (char *s
, int n
)
62 char *b
= openspace(n
);
67 static void addstr (char *s
)
69 addnchar(s
, strlen(s
));
74 ** Return the string length
76 static void str_len (void)
78 lua_pushnumber(strlen(luaL_check_string(1)));
82 ** Return the substring of a string
84 static void str_sub (void)
86 char *s
= luaL_check_string(1);
88 long start
= (long)luaL_check_number(2);
89 long end
= (long)luaL_opt_number(3, -1);
90 if (start
< 0) start
= l
+start
+1;
91 if (end
< 0) end
= l
+end
+1;
92 if (1 <= start
&& start
<= end
&& end
<= l
) {
94 addnchar(s
+start
-1, end
-start
+1);
95 lua_pushstring(luaI_addchar(0));
97 else lua_pushstring("");
101 ** Convert a string to lower case.
103 static void str_lower (void)
107 for (s
= luaL_check_string(1); *s
; s
++)
108 luaI_addchar(tolower((unsigned char)*s
));
109 lua_pushstring(luaI_addchar(0));
113 ** Convert a string to upper case.
115 static void str_upper (void)
119 for (s
= luaL_check_string(1); *s
; s
++)
120 luaI_addchar(toupper((unsigned char)*s
));
121 lua_pushstring(luaI_addchar(0));
124 static void str_rep (void)
126 char *s
= luaL_check_string(1);
127 int n
= (int)luaL_check_number(2);
131 lua_pushstring(luaI_addchar(0));
135 ** get ascii value of a character in a string
137 static void str_ascii (void)
139 char *s
= luaL_check_string(1);
140 long pos
= (long)luaL_opt_number(2, 1) - 1;
141 luaL_arg_check(0<=pos
&& pos
<strlen(s
), 2, "out of range");
142 lua_pushnumber((unsigned char)s
[pos
]);
146 /* pattern matching */
149 #define SPECIALS "^$*?.([%-"
151 static char *bracket_end (char *p
)
153 return (*p
== 0) ? NULL
: strchr((*p
=='^') ? p
+2 : p
+1, ']');
156 char *luaL_item_end (char *p
)
159 case '\0': return p
-1;
161 if (*p
== 0) luaL_verror("incorrect pattern (ends with `%c')", ESC
);
164 char *end
= bracket_end(p
);
165 if (end
== NULL
) lua_error("incorrect pattern (missing `]')");
173 static int matchclass (int c
, int cl
)
176 switch (tolower((unsigned char)cl
)) {
177 case 'a' : res
= isalpha((unsigned char)c
); break;
178 case 'c' : res
= iscntrl((unsigned char)c
); break;
179 case 'd' : res
= isdigit((unsigned char)c
); break;
180 case 'l' : res
= islower((unsigned char)c
); break;
181 case 'p' : res
= ispunct((unsigned char)c
); break;
182 case 's' : res
= isspace((unsigned char)c
); break;
183 case 'u' : res
= isupper((unsigned char)c
); break;
184 case 'w' : res
= isalnum((unsigned char)c
); break;
185 default: return (cl
== c
);
187 return (islower((unsigned char)cl
) ? res
: !res
);
190 int luaL_singlematch (int c
, char *p
)
192 if (c
== 0) return 0;
195 case ESC
: return matchclass(c
, *(p
+1));
197 char *end
= bracket_end(p
+1);
198 int sig
= *(p
+1) == '^' ? (p
++, 0) : 1;
201 if (((p
+1) < end
) && matchclass(c
, *++p
)) return sig
;
203 else if ((*(p
+1) == '-') && (p
+2 < end
)) {
205 if (*(p
-2) <= c
&& c
<= *p
) return sig
;
207 else if (*p
== c
) return sig
;
211 default: return (*p
== c
);
219 int len
; /* -1 signals unfinished capture */
222 static int num_captures
; /* only valid after a sucessful call to match */
225 static void push_captures (void)
228 for (i
=0; i
<num_captures
; i
++) {
229 int l
= capture
[i
].len
;
230 char *buff
= openspace(l
+1);
231 if (l
== -1) lua_error("unfinished capture");
232 strncpy(buff
, capture
[i
].init
, l
);
234 lua_pushstring(buff
);
238 static int check_cap (int l
, int level
)
241 if (!(0 <= l
&& l
< level
&& capture
[l
].len
!= -1))
242 lua_error("invalid capture index");
246 static int capture_to_close (int level
)
248 for (level
--; level
>=0; level
--)
249 if (capture
[level
].len
== -1) return level
;
250 lua_error("invalid pattern capture");
251 return 0; /* to avoid warnings */
254 static char *matchbalance (char *s
, int b
, int e
)
256 if (*s
!= b
) return NULL
;
261 if (--cont
== 0) return s
+1;
263 else if (*s
== b
) cont
++;
266 return NULL
; /* string ends out of balance */
269 static char *match (char *s
, char *p
, int level
)
271 init
: /* using goto's to optimize tail recursion */
273 case '(': /* start capture */
274 if (level
>= MAX_CAPT
) lua_error("too many captures");
275 capture
[level
].init
= s
;
276 capture
[level
].len
= -1;
277 level
++; p
++; goto init
; /* return match(s, p+1, level); */
278 case ')': { /* end capture */
279 int l
= capture_to_close(level
);
281 capture
[l
].len
= s
- capture
[l
].init
; /* close capture */
282 if ((res
= match(s
, p
+1, level
)) == NULL
) /* match failed? */
283 capture
[l
].len
= -1; /* undo capture */
287 if (isdigit((unsigned char)(*(p
+1)))) { /* capture */
288 int l
= check_cap(*(p
+1), level
);
289 if (strncmp(capture
[l
].init
, s
, capture
[l
].len
) == 0) {
290 /* return match(p+2, s+capture[l].len, level); */
291 p
+=2; s
+=capture
[l
].len
; goto init
;
295 else if (*(p
+1) == 'b') { /* balanced string */
296 if (*(p
+2) == 0 || *(p
+3) == 0)
297 lua_error("bad balanced pattern specification");
298 s
= matchbalance(s
, *(p
+2), *(p
+3));
299 if (s
== NULL
) return NULL
;
300 else { /* return match(p+4, s, level); */
305 case '\0': case '$': /* (possibly) end of pattern */
306 if (*p
== 0 || (*(p
+1) == 0 && *s
== 0)) {
307 num_captures
= level
;
311 default: dflt
: { /* it is a pattern item */
312 int m
= luaL_singlematch(*s
, p
);
313 char *ep
= luaL_item_end(p
); /* get what is next */
315 case '*': { /* repetition */
317 if (m
&& (res
= match(s
+1, p
, level
)))
319 p
=ep
+1; goto init
; /* else return match(s, ep+1, level); */
321 case '-': { /* repetition */
323 if ((res
= match(s
, ep
+1, level
)) != 0)
327 goto init
; /* return match(s+1, p, level); */
332 case '?': { /* optional */
334 if (m
&& (res
= match(s
+1, ep
+1, level
)))
336 p
=ep
+1; goto init
; /* else return match(s, ep+1, level); */
339 if (m
) { s
++; p
=ep
; goto init
; } /* return match(s+1, ep, level); */
346 static void str_find (void)
348 char *s
= luaL_check_string(1);
349 char *p
= luaL_check_string(2);
350 long init
= (long)luaL_opt_number(3, 1) - 1;
351 luaL_arg_check(0 <= init
&& init
<= strlen(s
), 3, "out of range");
352 if (lua_getparam(4) != LUA_NOOBJECT
||
353 strpbrk(p
, SPECIALS
) == NULL
) { /* no special caracters? */
354 char *s2
= strstr(s
+init
, p
);
356 lua_pushnumber(s2
-s
+1);
357 lua_pushnumber(s2
-s
+strlen(p
));
361 int anchor
= (*p
== '^') ? (p
++, 1) : 0;
365 if ((res
=match(s1
, p
, 0)) != NULL
) {
366 lua_pushnumber(s1
-s
+1); /* start */
367 lua_pushnumber(res
-s
); /* end */
371 } while (*s1
++ && !anchor
);
375 static void add_s (lua_Object newp
, lua_Object table
, int n
)
377 if (lua_isstring(newp
)) {
378 char *news
= lua_getstring(newp
);
380 if (*news
!= ESC
|| !isdigit((unsigned char)*++news
))
381 luaI_addchar(*news
++);
383 int l
= check_cap(*news
++, num_captures
);
384 addnchar(capture
[l
].init
, capture
[l
].len
);
388 else if (lua_isfunction(newp
)) {
390 struct lbuff oldbuff
;
393 if (lua_istable(table
)) {
394 lua_pushobject(table
);
398 /* function may use lbuffer, so save it and create a new one */
400 lbuffer
.b
= NULL
; lbuffer
.max
= lbuffer
.size
= 0;
401 status
= lua_callfunction(newp
);
402 /* restore old buffer */
407 res
= lua_getresult(1);
408 addstr(lua_isstring(res
) ? lua_getstring(res
) : "");
411 else luaL_arg_check(0, 3, NULL
);
414 static void str_gsub (void)
416 char *src
= luaL_check_string(1);
417 char *p
= luaL_check_string(2);
418 lua_Object newp
= lua_getparam(3);
419 lua_Object table
= lua_getparam(4);
420 int max_s
= (int)luaL_opt_number(lua_istable(table
)?5:4, strlen(src
)+1);
421 int anchor
= (*p
== '^') ? (p
++, 1) : 0;
425 char *e
= match(src
, p
, 0);
428 add_s(newp
, table
, n
);
430 if (e
&& e
>src
) /* non empty match? */
431 src
= e
; /* skip it */
433 luaI_addchar(*src
++);
438 lua_pushstring(luaI_addchar(0));
439 lua_pushnumber(n
); /* number of substitutions */
442 static void str_set (void)
444 char *item
= luaL_check_string(1);
446 luaL_arg_check(*luaL_item_end(item
) == 0, 1, "wrong format");
448 for (i
=1; i
<256; i
++) /* 0 cannot be part of a set */
449 if (luaL_singlematch(i
, item
))
451 lua_pushstring(luaI_addchar(0));
455 void luaI_addquoted (char *s
)
459 if (strchr("\"\\\n", *s
))
466 #define MAX_FORMAT 200
468 static void str_format (void)
471 char *strfrmt
= luaL_check_string(arg
++);
472 luaI_emptybuff(); /* initialize */
475 luaI_addchar(*strfrmt
++);
476 else if (*++strfrmt
== '%')
477 luaI_addchar(*strfrmt
++); /* %% */
478 else { /* format item */
479 char form
[MAX_FORMAT
]; /* store the format ('%...') */
481 char *initf
= strfrmt
-1; /* -1 to include % */
482 strfrmt
= match(strfrmt
, "[-+ #]*(%d*)%.?(%d*)", 0);
483 if (capture
[0].len
> 3 || capture
[1].len
> 3) /* < 1000? */
484 lua_error("invalid format (width or precision too long)");
485 strncpy(form
, initf
, strfrmt
-initf
+1); /* +1 to include convertion */
486 form
[strfrmt
-initf
+1] = 0;
487 buff
= openspace(1000); /* to store the formated value */
488 switch (*strfrmt
++) {
490 luaI_addquoted(luaL_check_string(arg
++));
493 char *s
= luaL_check_string(arg
++);
494 buff
= openspace(strlen(s
));
495 sprintf(buff
, form
, s
);
498 case 'c': case 'd': case 'i': case 'o':
499 case 'u': case 'x': case 'X':
500 sprintf(buff
, form
, (int)luaL_check_number(arg
++));
502 case 'e': case 'E': case 'f': case 'g':
503 sprintf(buff
, form
, luaL_check_number(arg
++));
505 default: /* also treat cases 'pnLlh' */
506 lua_error("invalid format option in function `format'");
508 lbuffer
.size
+= strlen(buff
);
511 lua_pushstring(luaI_addchar(0)); /* push the result */
515 static struct luaL_reg strlib
[] = {
519 {"strlower", str_lower
},
520 {"strupper", str_upper
},
522 {"ascii", str_ascii
},
523 {"format", str_format
},
524 {"strfind", str_find
},
530 ** Open string library
532 void strlib_open (void)
534 luaL_openlib(strlib
, (sizeof(strlib
)/sizeof(strlib
[0])));