diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1996-08-01 11:55:33 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1996-08-01 11:55:33 -0300 |
| commit | 1630c2533a99e808ecf4649b637f45c964b1c477 (patch) | |
| tree | 302dbc8cff93763066fa754a2464496ac51898da /strlib.c | |
| parent | 1d373d77de72ee8baacf69ba53e9e61af6b9caa3 (diff) | |
| download | lua-1630c2533a99e808ecf4649b637f45c964b1c477.tar.gz lua-1630c2533a99e808ecf4649b637f45c964b1c477.tar.bz2 lua-1630c2533a99e808ecf4649b637f45c964b1c477.zip | |
Pattern-Matching!
plus several other changes...
Diffstat (limited to 'strlib.c')
| -rw-r--r-- | strlib.c | 494 |
1 files changed, 359 insertions, 135 deletions
| @@ -3,42 +3,68 @@ | |||
| 3 | ** String library to LUA | 3 | ** String library to LUA |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | char *rcs_strlib="$Id: strlib.c,v 1.23 1996/04/30 21:13:55 roberto Exp roberto $"; | 6 | char *rcs_strlib="$Id: strlib.c,v 1.24 1996/05/22 21:59:07 roberto Exp roberto $"; |
| 7 | 7 | ||
| 8 | #include <string.h> | 8 | #include <string.h> |
| 9 | #include <stdio.h> | 9 | #include <stdio.h> |
| 10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
| 11 | #include <ctype.h> | 11 | #include <ctype.h> |
| 12 | #include <limits.h> | ||
| 13 | 12 | ||
| 14 | #include "lua.h" | 13 | #include "lua.h" |
| 15 | #include "lualib.h" | 14 | #include "lualib.h" |
| 16 | 15 | ||
| 17 | 16 | ||
| 18 | void lua_arg_error(char *funcname) | 17 | static char *buffer = NULL; |
| 18 | static size_t maxbuff = 0; | ||
| 19 | static size_t buff_size = 0; | ||
| 20 | |||
| 21 | |||
| 22 | static char *lua_strbuffer (unsigned long size) | ||
| 23 | { | ||
| 24 | if (size > maxbuff) { | ||
| 25 | buffer = (buffer) ? realloc(buffer, maxbuff=size) : malloc(maxbuff=size); | ||
| 26 | if (buffer == NULL) | ||
| 27 | lua_error("memory overflow"); | ||
| 28 | } | ||
| 29 | return buffer; | ||
| 30 | } | ||
| 31 | |||
| 32 | static char *openspace (unsigned long size) | ||
| 19 | { | 33 | { |
| 20 | char buff[100]; | 34 | char *buff = lua_strbuffer(buff_size+size); |
| 21 | sprintf(buff, "incorrect arguments to function `%s'", funcname); | 35 | return buff+buff_size; |
| 22 | lua_error(buff); | 36 | } |
| 37 | |||
| 38 | void lua_arg_check(int cond, char *funcname) | ||
| 39 | { | ||
| 40 | if (!cond) { | ||
| 41 | char buff[100]; | ||
| 42 | sprintf(buff, "incorrect argument to function `%s'", funcname); | ||
| 43 | lua_error(buff); | ||
| 44 | } | ||
| 23 | } | 45 | } |
| 24 | 46 | ||
| 25 | char *lua_check_string (int numArg, char *funcname) | 47 | char *lua_check_string (int numArg, char *funcname) |
| 26 | { | 48 | { |
| 27 | lua_Object o = lua_getparam(numArg); | 49 | lua_Object o = lua_getparam(numArg); |
| 28 | if (!lua_isstring(o)) | 50 | lua_arg_check(lua_isstring(o), funcname); |
| 29 | lua_arg_error(funcname); | ||
| 30 | return lua_getstring(o); | 51 | return lua_getstring(o); |
| 31 | } | 52 | } |
| 32 | 53 | ||
| 54 | char *lua_opt_string (int numArg, char *def, char *funcname) | ||
| 55 | { | ||
| 56 | return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : | ||
| 57 | lua_check_string(numArg, funcname); | ||
| 58 | } | ||
| 59 | |||
| 33 | double lua_check_number (int numArg, char *funcname) | 60 | double lua_check_number (int numArg, char *funcname) |
| 34 | { | 61 | { |
| 35 | lua_Object o = lua_getparam(numArg); | 62 | lua_Object o = lua_getparam(numArg); |
| 36 | if (!lua_isnumber(o)) | 63 | lua_arg_check(lua_isnumber(o), funcname); |
| 37 | lua_arg_error(funcname); | ||
| 38 | return lua_getnumber(o); | 64 | return lua_getnumber(o); |
| 39 | } | 65 | } |
| 40 | 66 | ||
| 41 | static long lua_opt_number (int numArg, long def, char *funcname) | 67 | long lua_opt_number (int numArg, long def, char *funcname) |
| 42 | { | 68 | { |
| 43 | return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : | 69 | return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : |
| 44 | (long)lua_check_number(numArg, funcname); | 70 | (long)lua_check_number(numArg, funcname); |
| @@ -46,54 +72,45 @@ static long lua_opt_number (int numArg, long def, char *funcname) | |||
| 46 | 72 | ||
| 47 | char *luaI_addchar (int c) | 73 | char *luaI_addchar (int c) |
| 48 | { | 74 | { |
| 49 | static char *buff = NULL; | 75 | if (buff_size >= maxbuff) |
| 50 | static size_t max = 0; | 76 | lua_strbuffer(maxbuff == 0 ? 100 : maxbuff*2); |
| 51 | static size_t n = 0; | 77 | buffer[buff_size++] = c; |
| 52 | if (n >= max) | ||
| 53 | { | ||
| 54 | if (max == 0) | ||
| 55 | { | ||
| 56 | max = 100; | ||
| 57 | buff = (char *)malloc(max); | ||
| 58 | } | ||
| 59 | else | ||
| 60 | { | ||
| 61 | max *= 2; | ||
| 62 | buff = (char *)realloc(buff, max); | ||
| 63 | } | ||
| 64 | if (buff == NULL) | ||
| 65 | lua_error("memory overflow"); | ||
| 66 | } | ||
| 67 | buff[n++] = c; | ||
| 68 | if (c == 0) | 78 | if (c == 0) |
| 69 | n = 0; /* prepare for next string */ | 79 | buff_size = 0; /* prepare for next string */ |
| 70 | return buff; | 80 | return buffer; |
| 81 | } | ||
| 82 | |||
| 83 | static void addnchar (char *s, int n) | ||
| 84 | { | ||
| 85 | char *b = openspace(n); | ||
| 86 | strncpy(b, s, n); | ||
| 87 | buff_size += n; | ||
| 71 | } | 88 | } |
| 72 | 89 | ||
| 73 | 90 | ||
| 74 | /* | 91 | /* |
| 75 | ** Return the position of the first caracter of a substring into a string | 92 | ** Interface to strtok |
| 76 | ** LUA interface: | ||
| 77 | ** n = strfind (string, substring, init, end) | ||
| 78 | */ | 93 | */ |
| 79 | static void str_find (void) | 94 | static void str_tok (void) |
| 80 | { | 95 | { |
| 81 | char *s1 = lua_check_string(1, "strfind"); | 96 | char *s1 = lua_check_string(1, "strtok"); |
| 82 | char *s2 = lua_check_string(2, "strfind"); | 97 | char *del = lua_check_string(2, "strtok"); |
| 83 | long init = lua_opt_number(3, 1, "strfind") - 1; | 98 | lua_Object t = lua_createtable(); |
| 84 | char *f = (init>=0 && init<=strlen(s1)) ? strstr(s1+init,s2) : NULL; | 99 | int i = 1; |
| 85 | if (f != NULL) | 100 | /* As strtok changes s1, and s1 is "constant", make a copy of it */ |
| 86 | { | 101 | s1 = strcpy(lua_strbuffer(strlen(s1+1)), s1); |
| 87 | size_t pos = f-s1+1; | 102 | while ((s1 = strtok(s1, del)) != NULL) { |
| 88 | if (lua_opt_number(4, LONG_MAX, "strfind") >= pos+strlen(s2)-1) | 103 | lua_pushobject(t); |
| 89 | lua_pushnumber (pos); | 104 | lua_pushnumber(i++); |
| 90 | else | 105 | lua_pushstring(s1); |
| 91 | lua_pushnil(); | 106 | lua_storesubscript(); |
| 92 | } | 107 | s1 = NULL; /* prepare for next strtok */ |
| 93 | else | 108 | } |
| 94 | lua_pushnil(); | 109 | lua_pushobject(t); |
| 110 | lua_pushnumber(i-1); /* total number of tokens */ | ||
| 95 | } | 111 | } |
| 96 | 112 | ||
| 113 | |||
| 97 | /* | 114 | /* |
| 98 | ** Return the string length | 115 | ** Return the string length |
| 99 | ** LUA interface: | 116 | ** LUA interface: |
| @@ -101,11 +118,9 @@ static void str_find (void) | |||
| 101 | */ | 118 | */ |
| 102 | static void str_len (void) | 119 | static void str_len (void) |
| 103 | { | 120 | { |
| 104 | char *s = lua_check_string(1, "strlen"); | 121 | lua_pushnumber(strlen(lua_check_string(1, "strlen"))); |
| 105 | lua_pushnumber(strlen(s)); | ||
| 106 | } | 122 | } |
| 107 | 123 | ||
| 108 | |||
| 109 | /* | 124 | /* |
| 110 | ** Return the substring of a string, from start to end | 125 | ** Return the substring of a string, from start to end |
| 111 | ** LUA interface: | 126 | ** LUA interface: |
| @@ -113,136 +128,342 @@ static void str_len (void) | |||
| 113 | */ | 128 | */ |
| 114 | static void str_sub (void) | 129 | static void str_sub (void) |
| 115 | { | 130 | { |
| 116 | char *s = lua_check_string(1, "strsub"); | 131 | char *s = lua_check_string(1, "strsub"); |
| 117 | long start = (long)lua_check_number(2, "strsub"); | 132 | long start = (long)lua_check_number(2, "strsub"); |
| 118 | long end = lua_opt_number(3, strlen(s), "strsub"); | 133 | long end = lua_opt_number(3, strlen(s), "strsub"); |
| 119 | if (end < start || start < 1 || end > strlen(s)) | 134 | if (1 <= start && start <= end && end <= strlen(s)) { |
| 120 | lua_pushliteral(""); | 135 | luaI_addchar(0); |
| 121 | else | 136 | addnchar(s+start-1, end-start+1); |
| 122 | { | 137 | lua_pushstring(luaI_addchar(0)); |
| 123 | luaI_addchar(0); | 138 | } |
| 124 | while (start <= end) | 139 | else lua_pushliteral(""); |
| 125 | luaI_addchar(s[start++ - 1]); | ||
| 126 | lua_pushstring (luaI_addchar(0)); | ||
| 127 | } | ||
| 128 | } | 140 | } |
| 129 | 141 | ||
| 130 | /* | 142 | /* |
| 131 | ** Convert a string to lower case. | 143 | ** Transliterate a string |
| 132 | ** LUA interface: | ||
| 133 | ** lowercase = strlower (string) | ||
| 134 | */ | 144 | */ |
| 135 | static void str_lower (void) | 145 | static void str_map (void) |
| 136 | { | 146 | { |
| 137 | char *s = lua_check_string(1, "strlower"); | 147 | char *s = lua_check_string(1, "strmap"); |
| 138 | luaI_addchar(0); | 148 | char *from = lua_check_string(2, "strmap"); |
| 139 | while (*s) | 149 | char *to = lua_opt_string(3, "", "strmap"); |
| 140 | luaI_addchar(tolower(*s++)); | 150 | long len = strlen(to); |
| 151 | for (luaI_addchar(0); *s; s++) { | ||
| 152 | char *f = strrchr(from, *s); | ||
| 153 | if (f == NULL) | ||
| 154 | luaI_addchar(*s); | ||
| 155 | else { | ||
| 156 | long pos = f-from; | ||
| 157 | if (pos < len) | ||
| 158 | luaI_addchar(to[pos]); | ||
| 159 | } | ||
| 160 | } | ||
| 141 | lua_pushstring(luaI_addchar(0)); | 161 | lua_pushstring(luaI_addchar(0)); |
| 142 | } | 162 | } |
| 143 | 163 | ||
| 144 | |||
| 145 | /* | 164 | /* |
| 146 | ** Convert a string to upper case. | 165 | ** get ascii value of a character in a string |
| 147 | ** LUA interface: | ||
| 148 | ** uppercase = strupper (string) | ||
| 149 | */ | 166 | */ |
| 150 | static void str_upper (void) | 167 | static void str_ascii (void) |
| 168 | { | ||
| 169 | char *s = lua_check_string(1, "ascii"); | ||
| 170 | long pos = lua_opt_number(2, 1, "ascii") - 1; | ||
| 171 | lua_arg_check(0<=pos && pos<strlen(s), "ascii"); | ||
| 172 | lua_pushnumber((unsigned char)s[pos]); | ||
| 173 | } | ||
| 174 | |||
| 175 | |||
| 176 | /* pattern matching */ | ||
| 177 | |||
| 178 | #define ESC '%' | ||
| 179 | #define SPECIALS "^$*?.([%" | ||
| 180 | |||
| 181 | static char *item_end (char *p) | ||
| 182 | { | ||
| 183 | switch (*p) { | ||
| 184 | case '\0': return p; | ||
| 185 | case ESC: | ||
| 186 | if (*(p+1) == 0) lua_error("incorrect pattern"); | ||
| 187 | return p+2; | ||
| 188 | case '[': { | ||
| 189 | char *end = (*(p+1) == 0) ? NULL : strchr(p+2, ']'); | ||
| 190 | if (end == NULL) lua_error("incorrect pattern"); | ||
| 191 | return end+1; | ||
| 192 | } | ||
| 193 | default: | ||
| 194 | return p+1; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | static int matchclass (int c, int cl) | ||
| 199 | { | ||
| 200 | int res; | ||
| 201 | switch (tolower(cl)) { | ||
| 202 | case 'a' : res = isalpha(c); break; | ||
| 203 | case 'c' : res = iscntrl(c); break; | ||
| 204 | case 'd' : res = isdigit(c); break; | ||
| 205 | case 'l' : res = islower(c); break; | ||
| 206 | case 'p' : res = ispunct(c); break; | ||
| 207 | case 's' : res = isspace(c); break; | ||
| 208 | case 'u' : res = isupper(c); break; | ||
| 209 | case 'w' : res = isalnum(c); break; | ||
| 210 | default: return (cl == c); | ||
| 211 | } | ||
| 212 | return (islower(cl) ? res : !res); | ||
| 213 | } | ||
| 214 | |||
| 215 | static int singlematch (int c, char *p) | ||
| 216 | { | ||
| 217 | if (c == 0) return 0; | ||
| 218 | switch (*p) { | ||
| 219 | case '.': return 1; | ||
| 220 | case ESC: return matchclass(c, *(p+1)); | ||
| 221 | case '[': { | ||
| 222 | char *end = strchr(p+2, ']'); | ||
| 223 | int sig = *(p+1) == '^' ? (p++, 0) : 1; | ||
| 224 | while (++p < end) { | ||
| 225 | if (*p == ESC) { | ||
| 226 | if (((p+1) < end) && matchclass(c, *++p)) return sig; | ||
| 227 | } | ||
| 228 | else if ((*(p+1) == '-') && (p+2 < end)) { | ||
| 229 | p+=2; | ||
| 230 | if (*(p-2) <= c && c <= *p) return sig; | ||
| 231 | } | ||
| 232 | else if (*p == c) return sig; | ||
| 233 | } | ||
| 234 | return !sig; | ||
| 235 | } | ||
| 236 | default: return (*p == c); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | #define MAX_CAPT 9 | ||
| 241 | |||
| 242 | static struct { | ||
| 243 | char *init; | ||
| 244 | int len; /* -1 signals unfinished capture */ | ||
| 245 | } capture[MAX_CAPT]; | ||
| 246 | |||
| 247 | static int num_captures; /* only valid after a sucessful call to match */ | ||
| 248 | |||
| 249 | |||
| 250 | static void push_captures (void) | ||
| 151 | { | 251 | { |
| 152 | char *s = lua_check_string(1, "strupper"); | 252 | int i; |
| 153 | luaI_addchar(0); | 253 | luaI_addchar(0); |
| 154 | while (*s) | 254 | for (i=0; i<num_captures; i++) { |
| 155 | luaI_addchar(toupper(*s++)); | 255 | if (capture[i].len == -1) lua_error("unfinished capture"); |
| 256 | addnchar(capture[i].init, capture[i].len); | ||
| 257 | lua_pushstring(luaI_addchar(0)); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | static int check_cap (int l, int level) | ||
| 262 | { | ||
| 263 | l -= '1'; | ||
| 264 | if (!(0 <= l && l < level && capture[l].len != -1)) | ||
| 265 | lua_error("invalid capture index"); | ||
| 266 | return l; | ||
| 267 | } | ||
| 268 | |||
| 269 | static void add_s (char *newp) | ||
| 270 | { | ||
| 271 | while (*newp) { | ||
| 272 | if (*newp != ESC || !isdigit(*++newp)) | ||
| 273 | luaI_addchar(*newp++); | ||
| 274 | else { | ||
| 275 | int l = check_cap(*newp++, num_captures); | ||
| 276 | addnchar(capture[l].init, capture[l].len); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | static int capture_to_close (int level) | ||
| 282 | { | ||
| 283 | for (level--; level>=0; level--) | ||
| 284 | if (capture[level].len == -1) return level; | ||
| 285 | lua_error("invalid pattern capture"); | ||
| 286 | return 0; /* to avoid warnings */ | ||
| 287 | } | ||
| 288 | |||
| 289 | static char *match (char *s, char *p, int level) | ||
| 290 | { | ||
| 291 | init: /* using goto's to optimize tail recursion */ | ||
| 292 | switch (*p) { | ||
| 293 | case '(': /* start capture */ | ||
| 294 | if (level >= MAX_CAPT) lua_error("too many captures"); | ||
| 295 | capture[level].init = s; | ||
| 296 | capture[level].len = -1; | ||
| 297 | level++; p++; goto init; /* return match(s, p+1, level); */ | ||
| 298 | case ')': { /* end capture */ | ||
| 299 | int l = capture_to_close(level); | ||
| 300 | char *res; | ||
| 301 | capture[l].len = s - capture[l].init; /* close capture */ | ||
| 302 | if ((res = match(s, p+1, level)) == NULL) /* match failed? */ | ||
| 303 | capture[l].len = -1; /* undo capture */ | ||
| 304 | return res; | ||
| 305 | } | ||
| 306 | case ESC: /* possibly a capture (if followed by a digit) */ | ||
| 307 | if (!isdigit(*(p+1))) goto dflt; | ||
| 308 | else { | ||
| 309 | int l = check_cap(*(p+1), level); | ||
| 310 | if (strncmp(capture[l].init, s, capture[l].len) == 0) { | ||
| 311 | /* return match(p+2, s+capture[l].len, level); */ | ||
| 312 | p+=2; s+=capture[l].len; goto init; | ||
| 313 | } | ||
| 314 | else return NULL; | ||
| 315 | } | ||
| 316 | case '\0': case '$': /* (possibly) end of pattern */ | ||
| 317 | if (*p == 0 || (*(p+1) == 0 && *s == 0)) { | ||
| 318 | num_captures = level; | ||
| 319 | return s; | ||
| 320 | } | ||
| 321 | else goto dflt; | ||
| 322 | default: dflt: { /* it is a pattern item */ | ||
| 323 | int m = singlematch(*s, p); | ||
| 324 | char *ep = item_end(p); /* get what is next */ | ||
| 325 | switch (*ep) { | ||
| 326 | case '*': { /* repetition? */ | ||
| 327 | char *res; | ||
| 328 | if (m && (res = match(s+1, p, level))) | ||
| 329 | return res; | ||
| 330 | p=ep+1; goto init; /* else return match(s, ep+1, level); */ | ||
| 331 | } | ||
| 332 | case '?': { /* optional? */ | ||
| 333 | char *res; | ||
| 334 | if (m && (res = match(s+1, ep+1, level))) | ||
| 335 | return res; | ||
| 336 | p=ep+1; goto init; /* else return match(s, ep+1, level); */ | ||
| 337 | } | ||
| 338 | default: | ||
| 339 | if (m) { s++; p=ep; goto init; } /* return match(s+1, ep, level); */ | ||
| 340 | else return NULL; | ||
| 341 | } | ||
| 342 | } | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | static void str_find (void) | ||
| 347 | { | ||
| 348 | char *s = lua_check_string(1, "find"); | ||
| 349 | char *p = lua_check_string(2, "find"); | ||
| 350 | long init = lua_opt_number(3, 1, "strfind") - 1; | ||
| 351 | lua_arg_check(0 <= init && init <= strlen(s), "find"); | ||
| 352 | if (strpbrk(p, SPECIALS) == NULL) { /* no special caracters? */ | ||
| 353 | char *s2 = strstr(s+init, p); | ||
| 354 | if (s2) { | ||
| 355 | lua_pushnumber(s2-s+1); | ||
| 356 | lua_pushnumber(s2-s+strlen(p)); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | else { | ||
| 360 | int anchor = (*p == '^') ? (p++, 1) : 0; | ||
| 361 | char *s1=s+init; | ||
| 362 | do { | ||
| 363 | char *res; | ||
| 364 | if ((res=match(s1, p, 0)) != NULL) { | ||
| 365 | lua_pushnumber(s1-s+1); /* start */ | ||
| 366 | lua_pushnumber(res-s); /* end */ | ||
| 367 | push_captures(); | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | } while (*s1++ && !anchor); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | static void str_s (void) | ||
| 375 | { | ||
| 376 | char *src = lua_check_string(1, "s"); | ||
| 377 | char *p = lua_check_string(2, "s"); | ||
| 378 | char *newp = lua_check_string(3, "s"); | ||
| 379 | int max_s = lua_opt_number(4, strlen(src), "s"); | ||
| 380 | int anchor = (*p == '^') ? (p++, 1) : 0; | ||
| 381 | int n = 0; | ||
| 382 | luaI_addchar(0); | ||
| 383 | while (*src && n < max_s) { | ||
| 384 | char *e; | ||
| 385 | if ((e=match(src, p, 0)) == NULL) | ||
| 386 | luaI_addchar(*src++); | ||
| 387 | else { | ||
| 388 | if (e == src) lua_error("empty pattern in substitution"); /* ??? */ | ||
| 389 | add_s(newp); | ||
| 390 | src = e; | ||
| 391 | n++; | ||
| 392 | } | ||
| 393 | if (anchor) break; | ||
| 394 | } | ||
| 395 | addnchar(src, strlen(src)); | ||
| 156 | lua_pushstring(luaI_addchar(0)); | 396 | lua_pushstring(luaI_addchar(0)); |
| 397 | lua_pushnumber(n); /* number of substitutions */ | ||
| 157 | } | 398 | } |
| 158 | 399 | ||
| 159 | /* | 400 | static void str_set (void) |
| 160 | ** get ascii value of a character in a string | ||
| 161 | */ | ||
| 162 | static void str_ascii (void) | ||
| 163 | { | 401 | { |
| 164 | char *s = lua_check_string(1, "ascii"); | 402 | char *item = lua_check_string(1, "strset"); |
| 165 | long pos = lua_opt_number(2, 1, "ascii") - 1; | 403 | int i; |
| 166 | if (pos<0 || pos>=strlen(s)) | 404 | lua_arg_check(*item_end(item) == 0, "strset"); |
| 167 | lua_arg_error("ascii"); | 405 | luaI_addchar(0); |
| 168 | lua_pushnumber(s[pos]); | 406 | for (i=1; i<256; i++) /* 0 cannot be part of a set */ |
| 407 | if (singlematch(i, item)) | ||
| 408 | luaI_addchar(i); | ||
| 409 | lua_pushstring(luaI_addchar(0)); | ||
| 169 | } | 410 | } |
| 170 | 411 | ||
| 412 | |||
| 171 | void luaI_addquoted (char *s) | 413 | void luaI_addquoted (char *s) |
| 172 | { | 414 | { |
| 173 | luaI_addchar('"'); | 415 | luaI_addchar('"'); |
| 174 | for (; *s; s++) | 416 | for (; *s; s++) { |
| 175 | { | 417 | if (strchr("\"\\\n", *s)) |
| 176 | if (*s == '"' || *s == '\\' || *s == '\n') | ||
| 177 | luaI_addchar('\\'); | 418 | luaI_addchar('\\'); |
| 178 | luaI_addchar(*s); | 419 | luaI_addchar(*s); |
| 179 | } | 420 | } |
| 180 | luaI_addchar('"'); | 421 | luaI_addchar('"'); |
| 181 | } | 422 | } |
| 182 | 423 | ||
| 183 | #define MAX_CONVERTION 2000 | 424 | #define MAX_FORMAT 200 |
| 184 | #define MAX_FORMAT 50 | ||
| 185 | 425 | ||
| 186 | static void str_format (void) | 426 | static void str_format (void) |
| 187 | { | 427 | { |
| 188 | int arg = 1; | 428 | int arg = 1; |
| 189 | char *strfrmt = lua_check_string(arg++, "format"); | 429 | char *strfrmt = lua_check_string(arg++, "format"); |
| 190 | luaI_addchar(0); /* initialize */ | 430 | luaI_addchar(0); /* initialize */ |
| 191 | while (*strfrmt) | 431 | while (*strfrmt) { |
| 192 | { | ||
| 193 | if (*strfrmt != '%') | 432 | if (*strfrmt != '%') |
| 194 | luaI_addchar(*strfrmt++); | 433 | luaI_addchar(*strfrmt++); |
| 195 | else if (*++strfrmt == '%') | 434 | else if (*++strfrmt == '%') |
| 196 | luaI_addchar(*strfrmt++); /* %% */ | 435 | luaI_addchar(*strfrmt++); /* %% */ |
| 197 | else | 436 | else { /* format item */ |
| 198 | { /* format item */ | ||
| 199 | char form[MAX_FORMAT]; /* store the format ('%...') */ | 437 | char form[MAX_FORMAT]; /* store the format ('%...') */ |
| 200 | char buff[MAX_CONVERTION]; /* store the formated value */ | 438 | char *buff; |
| 201 | int size = 0; | 439 | char *initf = strfrmt-1; /* -1 to include % */ |
| 202 | int i = 0; | 440 | strfrmt = match(strfrmt, "[-+ #]*(%d*)%.?(%d*)", 0); |
| 203 | form[i++] = '%'; | 441 | if (capture[0].len > 3 || capture[1].len > 3) /* < 1000? */ |
| 204 | form[i] = *strfrmt++; | 442 | lua_error("invalid format (width/precision too long)"); |
| 205 | while (!isalpha(form[i])) | 443 | strncpy(form, initf, strfrmt-initf+1); /* +1 to include convertion */ |
| 206 | { | 444 | form[strfrmt-initf+1] = 0; |
| 207 | if (isdigit(form[i])) | 445 | buff = openspace(1000); /* to store the formated value */ |
| 208 | { | 446 | switch (*strfrmt++) { |
| 209 | size = size*10 + form[i]-'0'; | ||
| 210 | if (size >= MAX_CONVERTION) | ||
| 211 | lua_error("format size/precision too long in function `format'"); | ||
| 212 | } | ||
| 213 | else if (form[i] == '.') | ||
| 214 | size = 0; /* re-start */ | ||
| 215 | if (++i >= MAX_FORMAT) | ||
| 216 | lua_error("bad format in function `format'"); | ||
| 217 | form[i] = *strfrmt++; | ||
| 218 | } | ||
| 219 | form[i+1] = 0; /* ends string */ | ||
| 220 | switch (form[i]) | ||
| 221 | { | ||
| 222 | case 'q': | 447 | case 'q': |
| 223 | luaI_addquoted(lua_check_string(arg++, "format")); | 448 | luaI_addquoted(lua_check_string(arg++, "format")); |
| 224 | buff[0] = '\0'; /* addchar already done */ | ||
| 225 | break; | 449 | break; |
| 226 | case 's': | 450 | case 's': { |
| 227 | { | ||
| 228 | char *s = lua_check_string(arg++, "format"); | 451 | char *s = lua_check_string(arg++, "format"); |
| 229 | if (strlen(s) >= MAX_CONVERTION) | 452 | buff = openspace(strlen(s)); |
| 230 | lua_error("string argument too long in function `format'"); | 453 | buff_size += sprintf(buff, form, s); |
| 231 | sprintf(buff, form, s); | ||
| 232 | break; | 454 | break; |
| 233 | } | 455 | } |
| 234 | case 'c': case 'd': case 'i': case 'o': | 456 | case 'c': case 'd': case 'i': case 'o': |
| 235 | case 'u': case 'x': case 'X': | 457 | case 'u': case 'x': case 'X': |
| 236 | sprintf(buff, form, (int)lua_check_number(arg++, "format")); | 458 | buff_size += sprintf(buff, form, |
| 459 | (int)lua_check_number(arg++, "format")); | ||
| 237 | break; | 460 | break; |
| 238 | case 'e': case 'E': case 'f': case 'g': | 461 | case 'e': case 'E': case 'f': case 'g': |
| 239 | sprintf(buff, form, lua_check_number(arg++, "format")); | 462 | buff_size += sprintf(buff, form, lua_check_number(arg++, "format")); |
| 240 | break; | 463 | break; |
| 241 | default: /* also treat cases 'pnLlh' */ | 464 | default: /* also treat cases 'pnLlh' */ |
| 242 | lua_error("invalid format option in function `format'"); | 465 | lua_error("invalid format option in function `format'"); |
| 243 | } | 466 | } |
| 244 | for (i=0; buff[i]; i++) /* move formated value to result */ | ||
| 245 | luaI_addchar(buff[i]); | ||
| 246 | } | 467 | } |
| 247 | } | 468 | } |
| 248 | lua_pushstring(luaI_addchar(0)); /* push the result */ | 469 | lua_pushstring(luaI_addchar(0)); /* push the result */ |
| @@ -256,14 +477,17 @@ void luaI_openlib (struct lua_reg *l, int n) | |||
| 256 | lua_register(l[i].name, l[i].func); | 477 | lua_register(l[i].name, l[i].func); |
| 257 | } | 478 | } |
| 258 | 479 | ||
| 480 | |||
| 259 | static struct lua_reg strlib[] = { | 481 | static struct lua_reg strlib[] = { |
| 260 | {"strfind", str_find}, | 482 | {"strtok", str_tok}, |
| 261 | {"strlen", str_len}, | 483 | {"strlen", str_len}, |
| 262 | {"strsub", str_sub}, | 484 | {"strsub", str_sub}, |
| 263 | {"strlower", str_lower}, | 485 | {"strset", str_set}, |
| 264 | {"strupper", str_upper}, | 486 | {"strmap", str_map}, |
| 265 | {"ascii", str_ascii}, | 487 | {"ascii", str_ascii}, |
| 266 | {"format", str_format} | 488 | {"format", str_format}, |
| 489 | {"strfind", str_find}, | ||
| 490 | {"s", str_s} | ||
| 267 | }; | 491 | }; |
| 268 | 492 | ||
| 269 | 493 | ||
