r9756: One-way upgrade from Samba3->Samba4 basically works now
[ira/wip.git] / source4 / scripting / ejs / smbcalls_string.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    provide access to string functions
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Jelmer Vernooij 2005 (substr)
8    
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.
13    
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.
18    
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.
22 */
23
24 #include "includes.h"
25 #include "scripting/ejs/smbcalls.h"
26 #include "lib/appweb/ejs/ejs.h"
27
28 /*
29   usage:
30       var len = strlen(str);
31 */
32 static int ejs_strlen(MprVarHandle eid, int argc, char **argv)
33 {
34         if (argc != 1) {
35                 ejsSetErrorMsg(eid, "strlen invalid arguments");
36                 return -1;
37         }
38         mpr_Return(eid, mprCreateIntegerVar(strlen_m(argv[0])));
39         return 0;
40 }
41
42 /*
43   usage:
44       var s = strlower("UPPER");
45 */
46 static int ejs_strlower(MprVarHandle eid, int argc, char **argv)
47 {
48         char *s;
49         if (argc != 1) {
50                 ejsSetErrorMsg(eid, "strlower invalid arguments");
51                 return -1;
52         }
53         s = strlower_talloc(mprMemCtx(), argv[0]);
54         mpr_Return(eid, mprString(s));
55         talloc_free(s);
56         return 0;
57 }
58
59 /*
60   usage:
61       var s = strupper("lower");
62 */
63 static int ejs_strupper(MprVarHandle eid, int argc, char **argv)
64 {
65         char *s;
66         if (argc != 1) {
67                 ejsSetErrorMsg(eid, "strupper invalid arguments");
68                 return -1;
69         }
70         s = strupper_talloc(mprMemCtx(), argv[0]);
71         mpr_Return(eid, mprString(s));
72         talloc_free(s);
73         return 0;
74 }
75
76 /*
77   usage:
78       var s = strstr(string, substring);
79 */
80 static int ejs_strstr(MprVarHandle eid, int argc, char **argv)
81 {
82         char *s;
83         if (argc != 2) {
84                 ejsSetErrorMsg(eid, "strstr invalid arguments");
85                 return -1;
86         }
87         s = strstr(argv[0], argv[1]);
88         mpr_Return(eid, mprString(s));
89         return 0;
90 }
91
92 /*
93   usage:
94      list = split(".", "a.foo.bar");
95
96   NOTE: does not take a regular expression, unlink perl split()
97 */
98 static int ejs_split(MprVarHandle eid, int argc, char **argv)
99 {
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;
108         }
109         separator = argv[0];
110         s = argv[1];
111
112         ret = mprObject("list");
113
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);
119         }
120         if (*s) {
121                 mprAddArray(&ret, count++, mprString(s));
122         }
123         talloc_free(tmp_ctx);
124         mpr_Return(eid, ret);
125         return 0;
126 }
127
128 /*
129   usage:
130     str = substr(orig[, start_offset[, length]]);
131
132         special cases:
133                 if start_offset < 0 then start_offset+=strlen(orig)
134                 if length < 0 then length+=strlen(orig)-start_offset
135
136         (as found in many other languages)
137 */
138 static int ejs_substr(MprVarHandle eid, int argc, struct MprVar **argv)
139 {
140         int start_offset = 0;
141         int length = 0;
142         const char *orig;
143         char *target;
144         
145         if (argc < 1 || argc > 3 ||
146             argv[0]->type != MPR_TYPE_STRING) {
147                 ejsSetErrorMsg(eid, "substr invalid arguments");
148                 return -1;
149         }
150
151         if (argc == 1) {
152                 mpr_Return(eid, *argv[0]);
153                 return 0;
154         }
155
156         orig = mprToString(argv[0]);
157         start_offset = mprToInt(argv[1]);
158         if (start_offset < 0) start_offset += strlen(orig);
159         if (start_offset < 0 || start_offset > strlen(orig)) {
160                 ejsSetErrorMsg(eid, "substr arg 2 out of bounds");
161                 return -1;
162         }
163
164         if (argc == 3) {
165                 length = mprToInt(argv[1]);
166                 if (length < 0) length += strlen(orig) - start_offset;
167                 if (length < 0 || length+start_offset > strlen(orig)) {
168                         ejsSetErrorMsg(eid, "substr arg 3 out of bounds");
169                         return -1;
170                 }
171         } else {
172                 length = strlen(orig);
173         }
174
175         target = talloc_strndup(mprMemCtx(), orig+start_offset, length);
176         
177         mpr_Return(eid, mprString(target));
178
179         talloc_free(target);
180
181         return 0;
182 }
183
184 /*
185   usage:
186      str = join("DC=", list);
187 */
188 static int ejs_join(MprVarHandle eid, int argc, struct MprVar **argv)
189 {
190         int i;
191         const char *separator;
192         char *ret = NULL;
193         const char **list;
194         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
195         if (argc != 2 ||
196             argv[0]->type != MPR_TYPE_STRING ||
197             argv[1]->type != MPR_TYPE_OBJECT) {
198                 ejsSetErrorMsg(eid, "join invalid arguments");
199                 return -1;
200         }
201
202         separator = mprToString(argv[0]);
203         list      = mprToArray(tmp_ctx, argv[1]);
204
205         if (list == NULL || list[0] == NULL) {
206                 talloc_free(tmp_ctx);
207                 mpr_Return(eid, mprString(NULL));
208                 return 0;
209         }
210         
211         ret = talloc_strdup(tmp_ctx, list[0]);
212         if (ret == NULL) {
213                 goto failed;
214         }
215         for (i=1;list[i];i++) {
216                 ret = talloc_asprintf_append(ret, "%s%s", separator, list[i]);
217                 if (ret == NULL) {
218                         goto failed;
219                 }
220         }
221         mpr_Return(eid, mprString(ret));
222         talloc_free(tmp_ctx);
223         return 0;
224 failed:
225         ejsSetErrorMsg(eid, "out of memory");
226         return -1;
227 }
228
229
230 /*
231   blergh, C certainly makes this hard!
232   usage:
233      str = sprintf("i=%d s=%7s", 7, "foo");
234 */
235 static int ejs_sprintf(MprVarHandle eid, int argc, struct MprVar **argv)
236 {
237         const char *format;
238         const char *p;
239         char *ret;
240         int a = 1;
241         char *(*_asprintf_append)(char *, const char *, ...);
242         TALLOC_CTX *tmp_ctx;
243         if (argc < 1 || argv[0]->type != MPR_TYPE_STRING) {
244                 ejsSetErrorMsg(eid, "sprintf invalid arguments");
245                 return -1;
246         }
247         format = mprToString(argv[0]);
248         tmp_ctx = talloc_new(mprMemCtx());
249         ret = talloc_strdup(tmp_ctx, "");
250
251         /* avoid all the format string warnings */
252         _asprintf_append = talloc_asprintf_append;
253
254         /*
255           hackity hack ...
256         */
257         while ((p = strchr(format, '%'))) {
258                 char *fmt2;
259                 int len, len_count=0;
260                 char *tstr;
261                 ret = talloc_asprintf_append(ret, "%*.*s", 
262                                              (int)(p-format), (int)(p-format), 
263                                              format);
264                 if (ret == NULL) goto failed;
265                 format += (int)(p-format);
266                 len = strcspn(p+1, "dxuiofgGpXeEFcs%") + 1;
267                 fmt2 = talloc_strndup(tmp_ctx, p, len+1);
268                 if (fmt2 == NULL) goto failed;
269                 len_count = count_chars(fmt2, '*');
270                 /* find the type string */
271                 tstr = &fmt2[len];
272                 while (tstr > fmt2 && isalpha((unsigned char)tstr[-1])) {
273                         tstr--;
274                 }
275                 if (strcmp(tstr, "%") == 0) {
276                         ret = talloc_asprintf_append(ret, "%%");
277                         if (ret == NULL) {
278                                 goto failed;
279                         }
280                         format += len+1;
281                         continue;
282                 }
283                 if (len_count > 2 || 
284                     argc < a + len_count + 1) {
285                         ejsSetErrorMsg(eid, "sprintf: not enough arguments for format");
286                         goto failed;
287                 }
288 #define FMT_ARG(fn, type) do { \
289                         switch (len_count) { \
290                         case 0: \
291                                 ret = _asprintf_append(ret, fmt2, \
292                                                              (type)fn(argv[a])); \
293                                 break; \
294                         case 1: \
295                                 ret = _asprintf_append(ret, fmt2, \
296                                                              (int)mprVarToNumber(argv[a]), \
297                                                              (type)fn(argv[a+1])); \
298                                 break; \
299                         case 2: \
300                                 ret = _asprintf_append(ret, fmt2, \
301                                                              (int)mprVarToNumber(argv[a]), \
302                                                              (int)mprVarToNumber(argv[a+1]), \
303                                                              (type)fn(argv[a+2])); \
304                                 break; \
305                         } \
306                         a += len_count + 1; \
307                         if (ret == NULL) { \
308                                 goto failed; \
309                         } \
310 } while (0)
311
312                 if (strcmp(tstr, "s")==0)        FMT_ARG(mprToString,    const char *);
313                 else if (strcmp(tstr, "c")==0)   FMT_ARG(*mprToString,   char);
314                 else if (strcmp(tstr, "d")==0)   FMT_ARG(mprVarToNumber, int);
315                 else if (strcmp(tstr, "ld")==0)  FMT_ARG(mprVarToNumber, long);
316                 else if (strcmp(tstr, "lld")==0) FMT_ARG(mprVarToNumber, long long);
317                 else if (strcmp(tstr, "x")==0)   FMT_ARG(mprVarToNumber, int);
318                 else if (strcmp(tstr, "lx")==0)  FMT_ARG(mprVarToNumber, long);
319                 else if (strcmp(tstr, "llx")==0) FMT_ARG(mprVarToNumber, long long);
320                 else if (strcmp(tstr, "X")==0)   FMT_ARG(mprVarToNumber, int);
321                 else if (strcmp(tstr, "lX")==0)  FMT_ARG(mprVarToNumber, long);
322                 else if (strcmp(tstr, "llX")==0) FMT_ARG(mprVarToNumber, long long);
323                 else if (strcmp(tstr, "u")==0)   FMT_ARG(mprVarToNumber, int);
324                 else if (strcmp(tstr, "lu")==0)  FMT_ARG(mprVarToNumber, long);
325                 else if (strcmp(tstr, "llu")==0) FMT_ARG(mprVarToNumber, long long);
326                 else if (strcmp(tstr, "i")==0)   FMT_ARG(mprVarToNumber, int);
327                 else if (strcmp(tstr, "li")==0)  FMT_ARG(mprVarToNumber, long);
328                 else if (strcmp(tstr, "lli")==0) FMT_ARG(mprVarToNumber, long long);
329                 else if (strcmp(tstr, "o")==0)   FMT_ARG(mprVarToNumber, int);
330                 else if (strcmp(tstr, "lo")==0)  FMT_ARG(mprVarToNumber, long);
331                 else if (strcmp(tstr, "llo")==0) FMT_ARG(mprVarToNumber, long long);
332                 else if (strcmp(tstr, "f")==0)   FMT_ARG(mprVarToFloat,  double);
333                 else if (strcmp(tstr, "lf")==0)  FMT_ARG(mprVarToFloat,  double);
334                 else if (strcmp(tstr, "g")==0)   FMT_ARG(mprVarToFloat,  double);
335                 else if (strcmp(tstr, "lg")==0)  FMT_ARG(mprVarToFloat,  double);
336                 else if (strcmp(tstr, "e")==0)   FMT_ARG(mprVarToFloat,  double);
337                 else if (strcmp(tstr, "le")==0)  FMT_ARG(mprVarToFloat,  double);
338                 else if (strcmp(tstr, "E")==0)   FMT_ARG(mprVarToFloat,  double);
339                 else if (strcmp(tstr, "lE")==0)  FMT_ARG(mprVarToFloat,  double);
340                 else if (strcmp(tstr, "F")==0)   FMT_ARG(mprVarToFloat,  double);
341                 else if (strcmp(tstr, "lF")==0)  FMT_ARG(mprVarToFloat,  double);
342                 else {
343                         ejsSetErrorMsg(eid, "sprintf: unknown format string '%s'", fmt2);
344                         goto failed;
345                 }
346                 format += len+1;
347         }
348
349         ret = talloc_asprintf_append(ret, "%s", format);
350         mpr_Return(eid, mprString(ret));
351         talloc_free(tmp_ctx);
352         return 0;          
353         
354 failed:
355         talloc_free(tmp_ctx);
356         return -1;
357 }
358
359 /*
360   used to build your own print function
361      str = vsprintf(args);
362 */
363 static int ejs_vsprintf(MprVarHandle eid, int argc, struct MprVar **argv)
364 {
365         struct MprVar **args, *len, *v;
366         int i, ret, length;
367         if (argc != 1 || argv[0]->type != MPR_TYPE_OBJECT) {
368                 ejsSetErrorMsg(eid, "vsprintf invalid arguments");
369                 return -1;
370         }
371         v = argv[0];
372         len = mprGetProperty(v, "length", NULL);
373         if (len == NULL) {
374                 ejsSetErrorMsg(eid, "vsprintf takes an array");
375                 return -1;
376         }
377         length = mprToInt(len);
378         args = talloc_array(mprMemCtx(), struct MprVar *, length);
379         if (args == NULL) {
380                 return -1;
381         }
382
383         for (i=0;i<length;i++) {
384                 char idx[16];
385                 mprItoa(i, idx, sizeof(idx));
386                 args[i] = mprGetProperty(v, idx, NULL);
387         }
388         
389         ret = ejs_sprintf(eid, length, args);
390         talloc_free(args);
391         return ret;
392 }
393
394
395 /*
396   encode a string, replacing all non-alpha with %02x form
397 */
398 static int ejs_encodeURIComponent(MprVarHandle eid, int argc, char **argv)
399 {
400         int i, j, count=0;
401         const char *s;
402         char *ret;
403         if (argc != 1) {
404                 ejsSetErrorMsg(eid, "encodeURIComponent invalid arguments");
405                 return -1;
406         }
407         
408         s = argv[0];
409
410         for (i=0;s[i];i++) {
411                 if (!isalnum(s[i])) count++;
412         }
413         
414         ret = talloc_size(mprMemCtx(), i + count*2 + 1);
415         if (ret == NULL) {
416                 return -1;
417         }
418         for (i=j=0;s[i];i++,j++) {
419                 if (!isalnum(s[i])) {
420                         snprintf(ret+j, 4, "%%%02X", (unsigned)s[i]);
421                         j += 2;
422                 } else {
423                         ret[j] = s[i];
424                 }
425         }
426         ret[j] = 0;
427         mpr_Return(eid, mprString(ret));
428         talloc_free(ret);
429         return 0;
430 }
431
432 /*
433   encode a string, replacing all non-alpha of %02x form
434 */
435 static int ejs_decodeURIComponent(MprVarHandle eid, int argc, char **argv)
436 {
437         int i, j, count=0;
438         const char *s;
439         char *ret;
440         if (argc != 1) {
441                 ejsSetErrorMsg(eid, "decodeURIComponent invalid arguments");
442                 return -1;
443         }
444         
445         s = argv[0];
446
447         ret = talloc_size(mprMemCtx(), strlen(s) + 1);
448         if (ret == NULL) {
449                 return -1;
450         }
451
452         for (i=j=0;s[i];i++,j++) {
453                 if (s[i] == '%') {
454                         unsigned c;
455                         if (sscanf(s+i+1, "%02X", &c) != 1) {
456                                 ejsSetErrorMsg(eid, "decodeURIComponent bad format");
457                                 return -1;
458                         }
459                         ret[j] = c;
460                         i += 2;
461                 } else {
462                         ret[j] = s[i];
463                 }
464                 if (!isalnum(s[i])) count++;
465         }
466         
467         ret[j] = 0;
468         mpr_Return(eid, mprString(ret));
469         talloc_free(ret);
470         return 0;
471 }
472
473 /*
474   initialise string ejs subsystem
475 */
476 static int ejs_string_init(MprVarHandle eid, int argc, struct MprVar **argv)
477 {
478         struct MprVar *obj = mprInitObject(eid, "string", argc, argv);
479
480         mprSetCFunction(obj, "substr", ejs_substr);
481         mprSetStringCFunction(obj, "strlen", ejs_strlen);
482         mprSetStringCFunction(obj, "strlower", ejs_strlower);
483         mprSetStringCFunction(obj, "strupper", ejs_strupper);
484         mprSetStringCFunction(obj, "strstr", ejs_strstr);
485         mprSetStringCFunction(obj, "split", ejs_split);
486         mprSetCFunction(obj, "join", ejs_join);
487         mprSetCFunction(obj, "sprintf", ejs_sprintf);
488         mprSetCFunction(obj, "vsprintf", ejs_vsprintf);
489         mprSetStringCFunction(obj, "encodeURIComponent", ejs_encodeURIComponent);
490         mprSetStringCFunction(obj, "decodeURIComponent", ejs_decodeURIComponent);
491
492         return 0;
493 }
494
495 /*
496   setup C functions that be called from ejs
497 */
498 void smb_setup_ejs_string(void)
499 {
500         ejsDefineCFunction(-1, "string_init", ejs_string_init, NULL, MPR_VAR_SCRIPT_HANDLE);
501 }