r9825: Correctly handle length argument to substr()
[Samba/aatanasov.git] / source / scripting / ejs / smbcalls_string.c
blob66e2210ea86e5563d59d100357ed5dfcbca024f1
1 /*
2 Unix SMB/CIFS implementation.
4 provide access to string functions
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Jelmer Vernooij 2005 (substr)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
25 #include "scripting/ejs/smbcalls.h"
26 #include "lib/appweb/ejs/ejs.h"
29 usage:
30 var len = strlen(str);
32 static int ejs_strlen(MprVarHandle eid, int argc, char **argv)
34 if (argc != 1) {
35 ejsSetErrorMsg(eid, "strlen invalid arguments");
36 return -1;
38 mpr_Return(eid, mprCreateIntegerVar(strlen_m(argv[0])));
39 return 0;
43 usage:
44 var s = strlower("UPPER");
46 static int ejs_strlower(MprVarHandle eid, int argc, char **argv)
48 char *s;
49 if (argc != 1) {
50 ejsSetErrorMsg(eid, "strlower invalid arguments");
51 return -1;
53 s = strlower_talloc(mprMemCtx(), argv[0]);
54 mpr_Return(eid, mprString(s));
55 talloc_free(s);
56 return 0;
60 usage:
61 var s = strupper("lower");
63 static int ejs_strupper(MprVarHandle eid, int argc, char **argv)
65 char *s;
66 if (argc != 1) {
67 ejsSetErrorMsg(eid, "strupper invalid arguments");
68 return -1;
70 s = strupper_talloc(mprMemCtx(), argv[0]);
71 mpr_Return(eid, mprString(s));
72 talloc_free(s);
73 return 0;
77 usage:
78 var s = strstr(string, substring);
80 static int ejs_strstr(MprVarHandle eid, int argc, char **argv)
82 char *s;
83 if (argc != 2) {
84 ejsSetErrorMsg(eid, "strstr invalid arguments");
85 return -1;
87 s = strstr(argv[0], argv[1]);
88 mpr_Return(eid, mprString(s));
89 return 0;
93 usage:
94 list = split(".", "a.foo.bar");
96 NOTE: does not take a regular expression, unlink perl split()
98 static int ejs_split(MprVarHandle eid, int argc, char **argv)
100 const char *separator;
101 char *s, *p;
102 struct MprVar ret;
103 int count = 0;
104 TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
105 if (argc != 2) {
106 ejsSetErrorMsg(eid, "split invalid arguments");
107 return -1;
109 separator = argv[0];
110 s = argv[1];
112 ret = mprObject("list");
114 while ((p = strstr(s, separator))) {
115 char *s2 = talloc_strndup(tmp_ctx, s, (int)(p-s));
116 mprAddArray(&ret, count++, mprString(s2));
117 talloc_free(s2);
118 s = p + strlen(separator);
120 if (*s) {
121 mprAddArray(&ret, count++, mprString(s));
123 talloc_free(tmp_ctx);
124 mpr_Return(eid, ret);
125 return 0;
129 usage:
130 str = substr(orig[, start_offset[, length]]);
132 special cases:
133 if start_offset < 0 then start_offset+=strlen(orig)
134 if length < 0 then length+=strlen(orig)-start_offset
136 (as found in many other languages)
138 static int ejs_substr(MprVarHandle eid, int argc, struct MprVar **argv)
140 int start_offset = 0;
141 int length = 0;
142 const char *orig;
143 char *target;
145 if (argc < 1 || argc > 3 ||
146 argv[0]->type != MPR_TYPE_STRING) {
147 ejsSetErrorMsg(eid, "substr invalid arguments");
148 return -1;
151 if (argc == 1) {
152 mpr_Return(eid, *argv[0]);
153 return 0;
156 orig = mprToString(argv[0]);
157 start_offset = mprToInt(argv[1]);
158 length = strlen(orig);
159 if (start_offset < 0) start_offset += strlen(orig);
160 if (start_offset < 0 || start_offset > strlen(orig)) {
161 ejsSetErrorMsg(eid, "substr arg 2 out of bounds");
162 return -1;
165 if (argc == 3) {
166 length = mprToInt(argv[2]);
167 if (length < 0) length += strlen(orig) - start_offset;
168 if (length < 0 || length+start_offset > strlen(orig)) {
169 ejsSetErrorMsg(eid, "substr arg 3 out of bounds");
170 return -1;
174 target = talloc_strndup(mprMemCtx(), orig+start_offset, length);
176 mpr_Return(eid, mprString(target));
178 talloc_free(target);
180 return 0;
184 usage:
185 str = join("DC=", list);
187 static int ejs_join(MprVarHandle eid, int argc, struct MprVar **argv)
189 int i;
190 const char *separator;
191 char *ret = NULL;
192 const char **list;
193 TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
194 if (argc != 2 ||
195 argv[0]->type != MPR_TYPE_STRING ||
196 argv[1]->type != MPR_TYPE_OBJECT) {
197 ejsSetErrorMsg(eid, "join invalid arguments");
198 return -1;
201 separator = mprToString(argv[0]);
202 list = mprToArray(tmp_ctx, argv[1]);
204 if (list == NULL || list[0] == NULL) {
205 talloc_free(tmp_ctx);
206 mpr_Return(eid, mprString(NULL));
207 return 0;
210 ret = talloc_strdup(tmp_ctx, list[0]);
211 if (ret == NULL) {
212 goto failed;
214 for (i=1;list[i];i++) {
215 ret = talloc_asprintf_append(ret, "%s%s", separator, list[i]);
216 if (ret == NULL) {
217 goto failed;
220 mpr_Return(eid, mprString(ret));
221 talloc_free(tmp_ctx);
222 return 0;
223 failed:
224 ejsSetErrorMsg(eid, "out of memory");
225 return -1;
230 blergh, C certainly makes this hard!
231 usage:
232 str = sprintf("i=%d s=%7s", 7, "foo");
234 static int ejs_sprintf(MprVarHandle eid, int argc, struct MprVar **argv)
236 const char *format;
237 const char *p;
238 char *ret;
239 int a = 1;
240 char *(*_asprintf_append)(char *, const char *, ...);
241 TALLOC_CTX *tmp_ctx;
242 if (argc < 1 || argv[0]->type != MPR_TYPE_STRING) {
243 ejsSetErrorMsg(eid, "sprintf invalid arguments");
244 return -1;
246 format = mprToString(argv[0]);
247 tmp_ctx = talloc_new(mprMemCtx());
248 ret = talloc_strdup(tmp_ctx, "");
250 /* avoid all the format string warnings */
251 _asprintf_append = talloc_asprintf_append;
254 hackity hack ...
256 while ((p = strchr(format, '%'))) {
257 char *fmt2;
258 int len, len_count=0;
259 char *tstr;
260 ret = talloc_asprintf_append(ret, "%*.*s",
261 (int)(p-format), (int)(p-format),
262 format);
263 if (ret == NULL) goto failed;
264 format += (int)(p-format);
265 len = strcspn(p+1, "dxuiofgGpXeEFcs%") + 1;
266 fmt2 = talloc_strndup(tmp_ctx, p, len+1);
267 if (fmt2 == NULL) goto failed;
268 len_count = count_chars(fmt2, '*');
269 /* find the type string */
270 tstr = &fmt2[len];
271 while (tstr > fmt2 && isalpha((unsigned char)tstr[-1])) {
272 tstr--;
274 if (strcmp(tstr, "%") == 0) {
275 ret = talloc_asprintf_append(ret, "%%");
276 if (ret == NULL) {
277 goto failed;
279 format += len+1;
280 continue;
282 if (len_count > 2 ||
283 argc < a + len_count + 1) {
284 ejsSetErrorMsg(eid, "sprintf: not enough arguments for format");
285 goto failed;
287 #define FMT_ARG(fn, type) do { \
288 switch (len_count) { \
289 case 0: \
290 ret = _asprintf_append(ret, fmt2, \
291 (type)fn(argv[a])); \
292 break; \
293 case 1: \
294 ret = _asprintf_append(ret, fmt2, \
295 (int)mprVarToNumber(argv[a]), \
296 (type)fn(argv[a+1])); \
297 break; \
298 case 2: \
299 ret = _asprintf_append(ret, fmt2, \
300 (int)mprVarToNumber(argv[a]), \
301 (int)mprVarToNumber(argv[a+1]), \
302 (type)fn(argv[a+2])); \
303 break; \
305 a += len_count + 1; \
306 if (ret == NULL) { \
307 goto failed; \
309 } while (0)
311 if (strcmp(tstr, "s")==0) FMT_ARG(mprToString, const char *);
312 else if (strcmp(tstr, "c")==0) FMT_ARG(*mprToString, char);
313 else if (strcmp(tstr, "d")==0) FMT_ARG(mprVarToNumber, int);
314 else if (strcmp(tstr, "ld")==0) FMT_ARG(mprVarToNumber, long);
315 else if (strcmp(tstr, "lld")==0) FMT_ARG(mprVarToNumber, long long);
316 else if (strcmp(tstr, "x")==0) FMT_ARG(mprVarToNumber, int);
317 else if (strcmp(tstr, "lx")==0) FMT_ARG(mprVarToNumber, long);
318 else if (strcmp(tstr, "llx")==0) FMT_ARG(mprVarToNumber, long long);
319 else if (strcmp(tstr, "X")==0) FMT_ARG(mprVarToNumber, int);
320 else if (strcmp(tstr, "lX")==0) FMT_ARG(mprVarToNumber, long);
321 else if (strcmp(tstr, "llX")==0) FMT_ARG(mprVarToNumber, long long);
322 else if (strcmp(tstr, "u")==0) FMT_ARG(mprVarToNumber, int);
323 else if (strcmp(tstr, "lu")==0) FMT_ARG(mprVarToNumber, long);
324 else if (strcmp(tstr, "llu")==0) FMT_ARG(mprVarToNumber, long long);
325 else if (strcmp(tstr, "i")==0) FMT_ARG(mprVarToNumber, int);
326 else if (strcmp(tstr, "li")==0) FMT_ARG(mprVarToNumber, long);
327 else if (strcmp(tstr, "lli")==0) FMT_ARG(mprVarToNumber, long long);
328 else if (strcmp(tstr, "o")==0) FMT_ARG(mprVarToNumber, int);
329 else if (strcmp(tstr, "lo")==0) FMT_ARG(mprVarToNumber, long);
330 else if (strcmp(tstr, "llo")==0) FMT_ARG(mprVarToNumber, long long);
331 else if (strcmp(tstr, "f")==0) FMT_ARG(mprVarToFloat, double);
332 else if (strcmp(tstr, "lf")==0) FMT_ARG(mprVarToFloat, double);
333 else if (strcmp(tstr, "g")==0) FMT_ARG(mprVarToFloat, double);
334 else if (strcmp(tstr, "lg")==0) FMT_ARG(mprVarToFloat, double);
335 else if (strcmp(tstr, "e")==0) FMT_ARG(mprVarToFloat, double);
336 else if (strcmp(tstr, "le")==0) FMT_ARG(mprVarToFloat, double);
337 else if (strcmp(tstr, "E")==0) FMT_ARG(mprVarToFloat, double);
338 else if (strcmp(tstr, "lE")==0) FMT_ARG(mprVarToFloat, double);
339 else if (strcmp(tstr, "F")==0) FMT_ARG(mprVarToFloat, double);
340 else if (strcmp(tstr, "lF")==0) FMT_ARG(mprVarToFloat, double);
341 else {
342 ejsSetErrorMsg(eid, "sprintf: unknown format string '%s'", fmt2);
343 goto failed;
345 format += len+1;
348 ret = talloc_asprintf_append(ret, "%s", format);
349 mpr_Return(eid, mprString(ret));
350 talloc_free(tmp_ctx);
351 return 0;
353 failed:
354 talloc_free(tmp_ctx);
355 return -1;
359 used to build your own print function
360 str = vsprintf(args);
362 static int ejs_vsprintf(MprVarHandle eid, int argc, struct MprVar **argv)
364 struct MprVar **args, *len, *v;
365 int i, ret, length;
366 if (argc != 1 || argv[0]->type != MPR_TYPE_OBJECT) {
367 ejsSetErrorMsg(eid, "vsprintf invalid arguments");
368 return -1;
370 v = argv[0];
371 len = mprGetProperty(v, "length", NULL);
372 if (len == NULL) {
373 ejsSetErrorMsg(eid, "vsprintf takes an array");
374 return -1;
376 length = mprToInt(len);
377 args = talloc_array(mprMemCtx(), struct MprVar *, length);
378 if (args == NULL) {
379 return -1;
382 for (i=0;i<length;i++) {
383 char idx[16];
384 mprItoa(i, idx, sizeof(idx));
385 args[i] = mprGetProperty(v, idx, NULL);
388 ret = ejs_sprintf(eid, length, args);
389 talloc_free(args);
390 return ret;
395 encode a string, replacing all non-alpha with %02x form
397 static int ejs_encodeURIComponent(MprVarHandle eid, int argc, char **argv)
399 int i, j, count=0;
400 const char *s;
401 char *ret;
402 if (argc != 1) {
403 ejsSetErrorMsg(eid, "encodeURIComponent invalid arguments");
404 return -1;
407 s = argv[0];
409 for (i=0;s[i];i++) {
410 if (!isalnum(s[i])) count++;
413 ret = talloc_size(mprMemCtx(), i + count*2 + 1);
414 if (ret == NULL) {
415 return -1;
417 for (i=j=0;s[i];i++,j++) {
418 if (!isalnum(s[i])) {
419 snprintf(ret+j, 4, "%%%02X", (unsigned)s[i]);
420 j += 2;
421 } else {
422 ret[j] = s[i];
425 ret[j] = 0;
426 mpr_Return(eid, mprString(ret));
427 talloc_free(ret);
428 return 0;
432 encode a string, replacing all non-alpha of %02x form
434 static int ejs_decodeURIComponent(MprVarHandle eid, int argc, char **argv)
436 int i, j, count=0;
437 const char *s;
438 char *ret;
439 if (argc != 1) {
440 ejsSetErrorMsg(eid, "decodeURIComponent invalid arguments");
441 return -1;
444 s = argv[0];
446 ret = talloc_size(mprMemCtx(), strlen(s) + 1);
447 if (ret == NULL) {
448 return -1;
451 for (i=j=0;s[i];i++,j++) {
452 if (s[i] == '%') {
453 unsigned c;
454 if (sscanf(s+i+1, "%02X", &c) != 1) {
455 ejsSetErrorMsg(eid, "decodeURIComponent bad format");
456 return -1;
458 ret[j] = c;
459 i += 2;
460 } else {
461 ret[j] = s[i];
463 if (!isalnum(s[i])) count++;
466 ret[j] = 0;
467 mpr_Return(eid, mprString(ret));
468 talloc_free(ret);
469 return 0;
473 initialise string ejs subsystem
475 static int ejs_string_init(MprVarHandle eid, int argc, struct MprVar **argv)
477 struct MprVar *obj = mprInitObject(eid, "string", argc, argv);
479 mprSetCFunction(obj, "substr", ejs_substr);
480 mprSetStringCFunction(obj, "strlen", ejs_strlen);
481 mprSetStringCFunction(obj, "strlower", ejs_strlower);
482 mprSetStringCFunction(obj, "strupper", ejs_strupper);
483 mprSetStringCFunction(obj, "strstr", ejs_strstr);
484 mprSetStringCFunction(obj, "split", ejs_split);
485 mprSetCFunction(obj, "join", ejs_join);
486 mprSetCFunction(obj, "sprintf", ejs_sprintf);
487 mprSetCFunction(obj, "vsprintf", ejs_vsprintf);
488 mprSetStringCFunction(obj, "encodeURIComponent", ejs_encodeURIComponent);
489 mprSetStringCFunction(obj, "decodeURIComponent", ejs_decodeURIComponent);
491 return 0;
495 setup C functions that be called from ejs
497 void smb_setup_ejs_string(void)
499 ejsDefineCFunction(-1, "string_init", ejs_string_init, NULL, MPR_VAR_SCRIPT_HANDLE);