aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lstrlib.c (renamed from strlib.c)261
-rw-r--r--strlib.h13
2 files changed, 127 insertions, 147 deletions
diff --git a/strlib.c b/lstrlib.c
index 6d16043a..eba282de 100644
--- a/strlib.c
+++ b/lstrlib.c
@@ -1,17 +1,17 @@
1/* 1/*
2** strlib.c 2** $Id: lstrlib.c,v 1.1 1997/08/14 19:47:57 roberto Exp roberto $
3** String library to LUA 3** Standard library for strings and pattern-matching
4** See Copyright Notice in lua.h
4*/ 5*/
5 6
6char *rcs_strlib="$Id: strlib.c,v 1.46 1997/06/19 18:49:40 roberto Exp roberto $";
7 7
8#include <string.h> 8#include <ctype.h>
9#include <stdio.h> 9#include <stdio.h>
10#include <stdlib.h> 10#include <stdlib.h>
11#include <ctype.h> 11#include <string.h>
12 12
13#include "lauxlib.h"
13#include "lua.h" 14#include "lua.h"
14#include "auxlib.h"
15#include "lualib.h" 15#include "lualib.h"
16 16
17 17
@@ -37,12 +37,14 @@ static char *strbuffer (unsigned long size)
37 return lbuffer.b; 37 return lbuffer.b;
38} 38}
39 39
40
40static char *openspace (unsigned long size) 41static char *openspace (unsigned long size)
41{ 42{
42 char *buff = strbuffer(lbuffer.size+size); 43 char *buff = strbuffer(lbuffer.size+size);
43 return buff+lbuffer.size; 44 return buff+lbuffer.size;
44} 45}
45 46
47
46char *luaI_addchar (int c) 48char *luaI_addchar (int c)
47{ 49{
48 if (lbuffer.size >= lbuffer.max) 50 if (lbuffer.size >= lbuffer.max)
@@ -51,6 +53,7 @@ char *luaI_addchar (int c)
51 return lbuffer.b; 53 return lbuffer.b;
52} 54}
53 55
56
54void luaI_emptybuff (void) 57void luaI_emptybuff (void)
55{ 58{
56 lbuffer.size = 0; /* prepare for next string */ 59 lbuffer.size = 0; /* prepare for next string */
@@ -64,23 +67,19 @@ static void addnchar (char *s, int n)
64 lbuffer.size += n; 67 lbuffer.size += n;
65} 68}
66 69
70
67static void addstr (char *s) 71static void addstr (char *s)
68{ 72{
69 addnchar(s, strlen(s)); 73 addnchar(s, strlen(s));
70} 74}
71 75
72 76
73/*
74** Return the string length
75*/
76static void str_len (void) 77static void str_len (void)
77{ 78{
78 lua_pushnumber(strlen(luaL_check_string(1))); 79 lua_pushnumber(strlen(luaL_check_string(1)));
79} 80}
80 81
81/* 82
82** Return the substring of a string
83*/
84static void str_sub (void) 83static void str_sub (void)
85{ 84{
86 char *s = luaL_check_string(1); 85 char *s = luaL_check_string(1);
@@ -97,9 +96,7 @@ static void str_sub (void)
97 else lua_pushstring(""); 96 else lua_pushstring("");
98} 97}
99 98
100/* 99
101** Convert a string to lower case.
102*/
103static void str_lower (void) 100static void str_lower (void)
104{ 101{
105 char *s; 102 char *s;
@@ -109,9 +106,7 @@ static void str_lower (void)
109 lua_pushstring(luaI_addchar(0)); 106 lua_pushstring(luaI_addchar(0));
110} 107}
111 108
112/* 109
113** Convert a string to upper case.
114*/
115static void str_upper (void) 110static void str_upper (void)
116{ 111{
117 char *s; 112 char *s;
@@ -131,9 +126,7 @@ static void str_rep (void)
131 lua_pushstring(luaI_addchar(0)); 126 lua_pushstring(luaI_addchar(0));
132} 127}
133 128
134/* 129
135** get ascii value of a character in a string
136*/
137static void str_ascii (void) 130static void str_ascii (void)
138{ 131{
139 char *s = luaL_check_string(1); 132 char *s = luaL_check_string(1);
@@ -143,36 +136,69 @@ static void str_ascii (void)
143} 136}
144 137
145 138
146/* pattern matching */ 139
140/*
141** =======================================================
142** PATTERN MATCHING
143** =======================================================
144*/
145
146#define MAX_CAPT 9
147
148static struct {
149 char *init;
150 int len; /* -1 signals unfinished capture */
151} capture[MAX_CAPT];
152
153static int num_captures; /* only valid after a sucessful call to match */
154
147 155
148#define ESC '%' 156#define ESC '%'
149#define SPECIALS "^$*?.([%-" 157#define SPECIALS "^$*?.([%-"
150 158
151static char *bracket_end (char *p) 159
160static void push_captures (void)
152{ 161{
153 return (*p == 0) ? NULL : strchr((*p=='^') ? p+2 : p+1, ']'); 162 int i;
163 for (i=0; i<num_captures; i++) {
164 int l = capture[i].len;
165 char *buff = openspace(l+1);
166 if (l == -1) lua_error("unfinished capture");
167 strncpy(buff, capture[i].init, l);
168 buff[l] = 0;
169 lua_pushstring(buff);
170 }
154} 171}
155 172
156char *luaL_item_end (char *p) 173
174static int check_cap (int l, int level)
157{ 175{
158 switch (*p++) { 176 l -= '1';
159 case '\0': return p-1; 177 if (!(0 <= l && l < level && capture[l].len != -1))
160 case ESC: 178 lua_error("invalid capture index");
161 if (*p == 0) luaL_verror("incorrect pattern (ends with `%c')", ESC); 179 return l;
162 return p+1; 180}
163 case '[': { 181
164 char *end = bracket_end(p); 182
165 if (end == NULL) lua_error("incorrect pattern (missing `]')"); 183static int capture_to_close (int level)
166 return end+1; 184{
167 } 185 for (level--; level>=0; level--)
168 default: 186 if (capture[level].len == -1) return level;
169 return p; 187 lua_error("invalid pattern capture");
170 } 188 return 0; /* to avoid warnings */
171} 189}
172 190
191
192static char *bracket_end (char *p)
193{
194 return (*p == 0) ? NULL : strchr((*p=='^') ? p+2 : p+1, ']');
195}
196
197
173static int matchclass (int c, int cl) 198static int matchclass (int c, int cl)
174{ 199{
175 int res; 200 int res;
201 if (c == 0) return 0;
176 switch (tolower((unsigned char)cl)) { 202 switch (tolower((unsigned char)cl)) {
177 case 'a' : res = isalpha((unsigned char)c); break; 203 case 'a' : res = isalpha((unsigned char)c); break;
178 case 'c' : res = iscntrl((unsigned char)c); break; 204 case 'c' : res = iscntrl((unsigned char)c); break;
@@ -187,15 +213,27 @@ static int matchclass (int c, int cl)
187 return (islower((unsigned char)cl) ? res : !res); 213 return (islower((unsigned char)cl) ? res : !res);
188} 214}
189 215
190int luaL_singlematch (int c, char *p) 216
217int luaI_singlematch (int c, char *p, char **ep)
191{ 218{
192 if (c == 0) return 0;
193 switch (*p) { 219 switch (*p) {
194 case '.': return 1; 220 case '\0':
195 case ESC: return matchclass(c, *(p+1)); 221 *ep = p;
222 return 0;
223 case '.':
224 *ep = p+1;
225 return (c != 0);
226 case ESC:
227 if (*(++p) == '\0')
228 luaL_verror("incorrect pattern (ends with `%c')", ESC);
229 *ep = p+1;
230 return matchclass(c, *p);
196 case '[': { 231 case '[': {
197 char *end = bracket_end(p+1); 232 char *end = bracket_end(p+1);
198 int sig = *(p+1) == '^' ? (p++, 0) : 1; 233 int sig = *(p+1) == '^' ? (p++, 0) : 1;
234 if (end == NULL) lua_error("incorrect pattern (missing `]')");
235 *ep = end+1;
236 if (c == 0) return 0;
199 while (++p < end) { 237 while (++p < end) {
200 if (*p == ESC) { 238 if (*p == ESC) {
201 if (((p+1) < end) && matchclass(c, *++p)) return sig; 239 if (((p+1) < end) && matchclass(c, *++p)) return sig;
@@ -208,48 +246,12 @@ int luaL_singlematch (int c, char *p)
208 } 246 }
209 return !sig; 247 return !sig;
210 } 248 }
211 default: return (*p == c); 249 default:
250 *ep = p+1;
251 return (*p == c);
212 } 252 }
213} 253}
214 254
215#define MAX_CAPT 9
216
217static struct {
218 char *init;
219 int len; /* -1 signals unfinished capture */
220} capture[MAX_CAPT];
221
222static int num_captures; /* only valid after a sucessful call to match */
223
224
225static void push_captures (void)
226{
227 int i;
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);
233 buff[l] = 0;
234 lua_pushstring(buff);
235 }
236}
237
238static int check_cap (int l, int level)
239{
240 l -= '1';
241 if (!(0 <= l && l < level && capture[l].len != -1))
242 lua_error("invalid capture index");
243 return l;
244}
245
246static int capture_to_close (int level)
247{
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 */
252}
253 255
254static char *matchbalance (char *s, int b, int e) 256static char *matchbalance (char *s, int b, int e)
255{ 257{
@@ -266,6 +268,31 @@ static char *matchbalance (char *s, int b, int e)
266 return NULL; /* string ends out of balance */ 268 return NULL; /* string ends out of balance */
267} 269}
268 270
271
272static char *matchitem (char *s, char *p, int level, char **ep)
273{
274 if (*p == ESC) {
275 p++;
276 if (isdigit((unsigned char)*p)) { /* capture */
277 int l = check_cap(*p, level);
278 *ep = p+1;
279 if (strncmp(capture[l].init, s, capture[l].len) == 0)
280 return s+capture[l].len;
281 else return NULL;
282 }
283 else if (*p == 'b') { /* balanced string */
284 p++;
285 if (*p == 0 || *(p+1) == 0)
286 lua_error("bad balanced pattern specification");
287 *ep = p+2;
288 return matchbalance(s, *p, *(p+1));
289 }
290 else p--; /* and go through */
291 }
292 return (luaI_singlematch(*s, p, ep) ? s+1 : NULL);
293}
294
295
269static char *match (char *s, char *p, int level) 296static char *match (char *s, char *p, int level)
270{ 297{
271 init: /* using goto's to optimize tail recursion */ 298 init: /* using goto's to optimize tail recursion */
@@ -283,38 +310,19 @@ static char *match (char *s, char *p, int level)
283 capture[l].len = -1; /* undo capture */ 310 capture[l].len = -1; /* undo capture */
284 return res; 311 return res;
285 } 312 }
286 case ESC:
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;
292 }
293 else return NULL;
294 }
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); */
301 p+=4; goto init;
302 }
303 }
304 else goto dflt;
305 case '\0': case '$': /* (possibly) end of pattern */ 313 case '\0': case '$': /* (possibly) end of pattern */
306 if (*p == 0 || (*(p+1) == 0 && *s == 0)) { 314 if (*p == 0 || (*(p+1) == 0 && *s == 0)) {
307 num_captures = level; 315 num_captures = level;
308 return s; 316 return s;
309 } 317 }
310 else goto dflt; 318 /* else go through */
311 default: dflt: { /* it is a pattern item */ 319 default: { /* it is a pattern item */
312 int m = luaL_singlematch(*s, p); 320 char *ep; /* get what is next */
313 char *ep = luaL_item_end(p); /* get what is next */ 321 char *s1 = matchitem(s, p, level, &ep);
314 switch (*ep) { 322 switch (*ep) {
315 case '*': { /* repetition */ 323 case '*': { /* repetition */
316 char *res; 324 char *res;
317 if (m && (res = match(s+1, p, level))) 325 if (s1 && (res = match(s1, p, level)))
318 return res; 326 return res;
319 p=ep+1; goto init; /* else return match(s, ep+1, level); */ 327 p=ep+1; goto init; /* else return match(s, ep+1, level); */
320 } 328 }
@@ -322,34 +330,35 @@ static char *match (char *s, char *p, int level)
322 char *res; 330 char *res;
323 if ((res = match(s, ep+1, level)) != 0) 331 if ((res = match(s, ep+1, level)) != 0)
324 return res; 332 return res;
325 else if (m) { 333 else if (s1) {
326 s++; 334 s = s1;
327 goto init; /* return match(s+1, p, level); */ 335 goto init; /* return match(s1, p, level); */
328 } 336 }
329 else 337 else
330 return NULL; 338 return NULL;
331 } 339 }
332 case '?': { /* optional */ 340 case '?': { /* optional */
333 char *res; 341 char *res;
334 if (m && (res = match(s+1, ep+1, level))) 342 if (s1 && (res = match(s1, ep+1, level)))
335 return res; 343 return res;
336 p=ep+1; goto init; /* else return match(s, ep+1, level); */ 344 p=ep+1; goto init; /* else return match(s, ep+1, level); */
337 } 345 }
338 default: 346 default:
339 if (m) { s++; p=ep; goto init; } /* return match(s+1, ep, level); */ 347 if (s1) { s=s1; p=ep; goto init; } /* return match(s1, ep, level); */
340 else return NULL; 348 else return NULL;
341 } 349 }
342 } 350 }
343 } 351 }
344} 352}
345 353
354
346static void str_find (void) 355static void str_find (void)
347{ 356{
348 char *s = luaL_check_string(1); 357 char *s = luaL_check_string(1);
349 char *p = luaL_check_string(2); 358 char *p = luaL_check_string(2);
350 long init = (long)luaL_opt_number(3, 1) - 1; 359 long init = (long)luaL_opt_number(3, 1) - 1;
351 luaL_arg_check(0 <= init && init <= strlen(s), 3, "out of range"); 360 luaL_arg_check(0 <= init && init <= strlen(s), 3, "out of range");
352 if (lua_getparam(4) != LUA_NOOBJECT || 361 if (lua_getparam(4) != LUA_NOOBJECT ||
353 strpbrk(p, SPECIALS) == NULL) { /* no special caracters? */ 362 strpbrk(p, SPECIALS) == NULL) { /* no special caracters? */
354 char *s2 = strstr(s+init, p); 363 char *s2 = strstr(s+init, p);
355 if (s2) { 364 if (s2) {
@@ -372,7 +381,8 @@ static void str_find (void)
372 } 381 }
373} 382}
374 383
375static void add_s (lua_Object newp, lua_Object table, int n) 384
385static void add_s (lua_Object newp)
376{ 386{
377 if (lua_isstring(newp)) { 387 if (lua_isstring(newp)) {
378 char *news = lua_getstring(newp); 388 char *news = lua_getstring(newp);
@@ -390,12 +400,8 @@ static void add_s (lua_Object newp, lua_Object table, int n)
390 struct lbuff oldbuff; 400 struct lbuff oldbuff;
391 int status; 401 int status;
392 lua_beginblock(); 402 lua_beginblock();
393 if (lua_istable(table)) {
394 lua_pushobject(table);
395 lua_pushnumber(n);
396 }
397 push_captures(); 403 push_captures();
398 /* function may use lbuffer, so save it and create a new one */ 404 /* function may use lbuffer, so save it and create a luaM_new one */
399 oldbuff = lbuffer; 405 oldbuff = lbuffer;
400 lbuffer.b = NULL; lbuffer.max = lbuffer.size = 0; 406 lbuffer.b = NULL; lbuffer.max = lbuffer.size = 0;
401 status = lua_callfunction(newp); 407 status = lua_callfunction(newp);
@@ -411,13 +417,13 @@ static void add_s (lua_Object newp, lua_Object table, int n)
411 else luaL_arg_check(0, 3, NULL); 417 else luaL_arg_check(0, 3, NULL);
412} 418}
413 419
420
414static void str_gsub (void) 421static void str_gsub (void)
415{ 422{
416 char *src = luaL_check_string(1); 423 char *src = luaL_check_string(1);
417 char *p = luaL_check_string(2); 424 char *p = luaL_check_string(2);
418 lua_Object newp = lua_getparam(3); 425 lua_Object newp = lua_getparam(3);
419 lua_Object table = lua_getparam(4); 426 int max_s = (int)luaL_opt_number(4, strlen(src)+1);
420 int max_s = (int)luaL_opt_number(lua_istable(table)?5:4, strlen(src)+1);
421 int anchor = (*p == '^') ? (p++, 1) : 0; 427 int anchor = (*p == '^') ? (p++, 1) : 0;
422 int n = 0; 428 int n = 0;
423 luaI_emptybuff(); 429 luaI_emptybuff();
@@ -425,7 +431,7 @@ static void str_gsub (void)
425 char *e = match(src, p, 0); 431 char *e = match(src, p, 0);
426 if (e) { 432 if (e) {
427 n++; 433 n++;
428 add_s(newp, table, n); 434 add_s(newp);
429 } 435 }
430 if (e && e>src) /* non empty match? */ 436 if (e && e>src) /* non empty match? */
431 src = e; /* skip it */ 437 src = e; /* skip it */
@@ -439,18 +445,6 @@ static void str_gsub (void)
439 lua_pushnumber(n); /* number of substitutions */ 445 lua_pushnumber(n); /* number of substitutions */
440} 446}
441 447
442static void str_set (void)
443{
444 char *item = luaL_check_string(1);
445 int i;
446 luaL_arg_check(*luaL_item_end(item) == 0, 1, "wrong format");
447 luaI_emptybuff();
448 for (i=1; i<256; i++) /* 0 cannot be part of a set */
449 if (luaL_singlematch(i, item))
450 luaI_addchar(i);
451 lua_pushstring(luaI_addchar(0));
452}
453
454 448
455void luaI_addquoted (char *s) 449void luaI_addquoted (char *s)
456{ 450{
@@ -505,7 +499,7 @@ static void str_format (void)
505 case 'u': case 'x': case 'X': 499 case 'u': case 'x': case 'X':
506 sprintf(buff, form, (int)luaL_check_number(arg)); 500 sprintf(buff, form, (int)luaL_check_number(arg));
507 break; 501 break;
508 case 'e': case 'E': case 'f': case 'g': 502 case 'e': case 'E': case 'f': case 'g': case 'G':
509 sprintf(buff, form, luaL_check_number(arg)); 503 sprintf(buff, form, luaL_check_number(arg));
510 break; 504 break;
511 default: /* also treat cases 'pnLlh' */ 505 default: /* also treat cases 'pnLlh' */
@@ -521,7 +515,6 @@ static void str_format (void)
521static struct luaL_reg strlib[] = { 515static struct luaL_reg strlib[] = {
522{"strlen", str_len}, 516{"strlen", str_len},
523{"strsub", str_sub}, 517{"strsub", str_sub},
524{"strset", str_set},
525{"strlower", str_lower}, 518{"strlower", str_lower},
526{"strupper", str_upper}, 519{"strupper", str_upper},
527{"strrep", str_rep}, 520{"strrep", str_rep},
diff --git a/strlib.h b/strlib.h
deleted file mode 100644
index 3e650be5..00000000
--- a/strlib.h
+++ /dev/null
@@ -1,13 +0,0 @@
1/*
2** String library to LUA
3** TeCGraf - PUC-Rio
4** $Id: $
5*/
6
7
8#ifndef strlib_h
9
10void strlib_open (void);
11
12#endif
13