1b6b7d09dd236866618aa2122291a8ed98994b19
[sfrench/samba-autobuild/.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    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "scripting/ejs/smbcalls.h"
25 #include "lib/appweb/ejs/ejs.h"
26
27 /*
28   usage:
29       var len = strlen(str);
30 */
31 static int ejs_strlen(MprVarHandle eid, int argc, char **argv)
32 {
33         if (argc != 1) {
34                 ejsSetErrorMsg(eid, "strlen invalid arguments");
35                 return -1;
36         }
37         mpr_Return(eid, mprCreateIntegerVar(strlen_m(argv[0])));
38         return 0;
39 }
40
41 /*
42   usage:
43       var s = strlower("UPPER");
44 */
45 static int ejs_strlower(MprVarHandle eid, int argc, char **argv)
46 {
47         char *s;
48         if (argc != 1) {
49                 ejsSetErrorMsg(eid, "strlower invalid arguments");
50                 return -1;
51         }
52         s = strlower_talloc(mprMemCtx(), argv[0]);
53         mpr_Return(eid, mprString(s));
54         talloc_free(s);
55         return 0;
56 }
57
58 /*
59   usage:
60       var s = strupper("lower");
61 */
62 static int ejs_strupper(MprVarHandle eid, int argc, char **argv)
63 {
64         char *s;
65         if (argc != 1) {
66                 ejsSetErrorMsg(eid, "strupper invalid arguments");
67                 return -1;
68         }
69         s = strupper_talloc(mprMemCtx(), argv[0]);
70         mpr_Return(eid, mprString(s));
71         talloc_free(s);
72         return 0;
73 }
74
75 /*
76   usage:
77       var s = strstr(string, substring);
78 */
79 static int ejs_strstr(MprVarHandle eid, int argc, char **argv)
80 {
81         char *s;
82         if (argc != 2) {
83                 ejsSetErrorMsg(eid, "strstr invalid arguments");
84                 return -1;
85         }
86         s = strstr(argv[0], argv[1]);
87         mpr_Return(eid, mprString(s));
88         return 0;
89 }
90
91 /*
92   usage:
93      list = split(".", "a.foo.bar");
94
95   NOTE: does not take a regular expression, unlink perl split()
96 */
97 static int ejs_split(MprVarHandle eid, int argc, char **argv)
98 {
99         const char *separator;
100         char *s, *p;
101         struct MprVar ret;
102         int count = 0;
103         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
104         if (argc != 2) {
105                 ejsSetErrorMsg(eid, "split invalid arguments");
106                 return -1;
107         }
108         separator = argv[0];
109         s = argv[1];
110
111         ret = mprObject("list");
112
113         while ((p = strstr(s, separator))) {
114                 char *s2 = talloc_strndup(tmp_ctx, s, (int)(p-s));
115                 mprAddArray(&ret, count++, mprString(s2));
116                 talloc_free(s2);
117                 s = p + strlen(separator);
118         }
119         if (*s) {
120                 mprAddArray(&ret, count++, mprString(s));
121         }
122         talloc_free(tmp_ctx);
123         mpr_Return(eid, ret);
124         return 0;
125 }
126
127
128 /*
129   usage:
130      str = join("DC=", list);
131 */
132 static int ejs_join(MprVarHandle eid, int argc, struct MprVar **argv)
133 {
134         int i;
135         const char *separator;
136         char *ret = NULL;
137         const char **list;
138         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
139         if (argc != 2 ||
140             argv[0]->type != MPR_TYPE_STRING ||
141             argv[1]->type != MPR_TYPE_OBJECT) {
142                 ejsSetErrorMsg(eid, "join invalid arguments");
143                 return -1;
144         }
145
146         separator = mprToString(argv[0]);
147         list      = mprToArray(tmp_ctx, argv[1]);
148
149         if (list == NULL || list[0] == NULL) {
150                 talloc_free(tmp_ctx);
151                 mpr_Return(eid, mprString(NULL));
152                 return 0;
153         }
154         
155         ret = talloc_strdup(tmp_ctx, list[0]);
156         if (ret == NULL) {
157                 goto failed;
158         }
159         for (i=1;list[i];i++) {
160                 ret = talloc_asprintf_append(ret, "%s%s", separator, list[i]);
161                 if (ret == NULL) {
162                         goto failed;
163                 }
164         }
165         mpr_Return(eid, mprString(ret));
166         talloc_free(tmp_ctx);
167         return 0;
168 failed:
169         ejsSetErrorMsg(eid, "out of memory");
170         return -1;
171 }
172
173
174 /*
175   blergh, C certainly makes this hard!
176   usage:
177      str = sprintf("i=%d s=%7s", 7, "foo");
178 */
179 static int ejs_sprintf(MprVarHandle eid, int argc, struct MprVar **argv)
180 {
181         const char *format;
182         const char *p;
183         char *ret;
184         int a = 1;
185         char *(*_asprintf_append)(char *, const char *, ...);
186         TALLOC_CTX *tmp_ctx;
187         if (argc < 1 || argv[0]->type != MPR_TYPE_STRING) {
188                 ejsSetErrorMsg(eid, "sprintf invalid arguments");
189                 return -1;
190         }
191         format = mprToString(argv[0]);
192         tmp_ctx = talloc_new(mprMemCtx());
193         ret = talloc_strdup(tmp_ctx, "");
194
195         /* avoid all the format string warnings */
196         _asprintf_append = talloc_asprintf_append;
197
198         /*
199           hackity hack ...
200         */
201         while ((p = strchr(format, '%'))) {
202                 char *fmt2;
203                 int len, len_count=0;
204                 char *tstr;
205                 ret = talloc_asprintf_append(ret, "%*.*s", 
206                                              (int)(p-format), (int)(p-format), 
207                                              format);
208                 if (ret == NULL) goto failed;
209                 format += (int)(p-format);
210                 len = strcspn(p+1, "dxuiofgGpXeEFcs%") + 1;
211                 fmt2 = talloc_strndup(tmp_ctx, p, len+1);
212                 if (fmt2 == NULL) goto failed;
213                 len_count = count_chars(fmt2, '*');
214                 /* find the type string */
215                 tstr = &fmt2[len];
216                 while (tstr > fmt2 && isalpha((unsigned char)tstr[-1])) {
217                         tstr--;
218                 }
219                 if (strcmp(tstr, "%") == 0) {
220                         ret = talloc_asprintf_append(ret, "%%");
221                         if (ret == NULL) {
222                                 goto failed;
223                         }
224                         format += len+1;
225                         continue;
226                 }
227                 if (len_count > 2 || 
228                     argc < a + len_count + 1) {
229                         ejsSetErrorMsg(eid, "sprintf: not enough arguments for format");
230                         goto failed;
231                 }
232 #define FMT_ARG(fn, type) do { \
233                         switch (len_count) { \
234                         case 0: \
235                                 ret = _asprintf_append(ret, fmt2, \
236                                                              (type)fn(argv[a])); \
237                                 break; \
238                         case 1: \
239                                 ret = _asprintf_append(ret, fmt2, \
240                                                              (int)mprVarToNumber(argv[a]), \
241                                                              (type)fn(argv[a+1])); \
242                                 break; \
243                         case 2: \
244                                 ret = _asprintf_append(ret, fmt2, \
245                                                              (int)mprVarToNumber(argv[a]), \
246                                                              (int)mprVarToNumber(argv[a+1]), \
247                                                              (type)fn(argv[a+2])); \
248                                 break; \
249                         } \
250                         a += len_count + 1; \
251                         if (ret == NULL) { \
252                                 goto failed; \
253                         } \
254 } while (0)
255
256                 if (strcmp(tstr, "s")==0)        FMT_ARG(mprToString,    const char *);
257                 else if (strcmp(tstr, "c")==0)   FMT_ARG(*mprToString,   char);
258                 else if (strcmp(tstr, "d")==0)   FMT_ARG(mprVarToNumber, int);
259                 else if (strcmp(tstr, "ld")==0)  FMT_ARG(mprVarToNumber, long);
260                 else if (strcmp(tstr, "lld")==0) FMT_ARG(mprVarToNumber, long long);
261                 else if (strcmp(tstr, "x")==0)   FMT_ARG(mprVarToNumber, int);
262                 else if (strcmp(tstr, "lx")==0)  FMT_ARG(mprVarToNumber, long);
263                 else if (strcmp(tstr, "llx")==0) FMT_ARG(mprVarToNumber, long long);
264                 else if (strcmp(tstr, "X")==0)   FMT_ARG(mprVarToNumber, int);
265                 else if (strcmp(tstr, "lX")==0)  FMT_ARG(mprVarToNumber, long);
266                 else if (strcmp(tstr, "llX")==0) FMT_ARG(mprVarToNumber, long long);
267                 else if (strcmp(tstr, "u")==0)   FMT_ARG(mprVarToNumber, int);
268                 else if (strcmp(tstr, "lu")==0)  FMT_ARG(mprVarToNumber, long);
269                 else if (strcmp(tstr, "llu")==0) FMT_ARG(mprVarToNumber, long long);
270                 else if (strcmp(tstr, "i")==0)   FMT_ARG(mprVarToNumber, int);
271                 else if (strcmp(tstr, "li")==0)  FMT_ARG(mprVarToNumber, long);
272                 else if (strcmp(tstr, "lli")==0) FMT_ARG(mprVarToNumber, long long);
273                 else if (strcmp(tstr, "o")==0)   FMT_ARG(mprVarToNumber, int);
274                 else if (strcmp(tstr, "lo")==0)  FMT_ARG(mprVarToNumber, long);
275                 else if (strcmp(tstr, "llo")==0) FMT_ARG(mprVarToNumber, long long);
276                 else if (strcmp(tstr, "f")==0)   FMT_ARG(mprVarToFloat,  double);
277                 else if (strcmp(tstr, "lf")==0)  FMT_ARG(mprVarToFloat,  double);
278                 else if (strcmp(tstr, "g")==0)   FMT_ARG(mprVarToFloat,  double);
279                 else if (strcmp(tstr, "lg")==0)  FMT_ARG(mprVarToFloat,  double);
280                 else if (strcmp(tstr, "e")==0)   FMT_ARG(mprVarToFloat,  double);
281                 else if (strcmp(tstr, "le")==0)  FMT_ARG(mprVarToFloat,  double);
282                 else if (strcmp(tstr, "E")==0)   FMT_ARG(mprVarToFloat,  double);
283                 else if (strcmp(tstr, "lE")==0)  FMT_ARG(mprVarToFloat,  double);
284                 else if (strcmp(tstr, "F")==0)   FMT_ARG(mprVarToFloat,  double);
285                 else if (strcmp(tstr, "lF")==0)  FMT_ARG(mprVarToFloat,  double);
286                 else {
287                         ejsSetErrorMsg(eid, "sprintf: unknown format string '%s'", fmt2);
288                         goto failed;
289                 }
290                 format += len+1;
291         }
292
293         ret = talloc_asprintf_append(ret, "%s", format);
294         mpr_Return(eid, mprString(ret));
295         talloc_free(tmp_ctx);
296         return 0;          
297         
298 failed:
299         talloc_free(tmp_ctx);
300         return -1;
301 }
302
303 /*
304   used to build your own print function
305      str = vsprintf(args);
306 */
307 static int ejs_vsprintf(MprVarHandle eid, int argc, struct MprVar **argv)
308 {
309         struct MprVar **args, *len, *v;
310         int i, ret, length;
311         if (argc != 1 || argv[0]->type != MPR_TYPE_OBJECT) {
312                 ejsSetErrorMsg(eid, "vsprintf invalid arguments");
313                 return -1;
314         }
315         v = argv[0];
316         len = mprGetProperty(v, "length", NULL);
317         if (len == NULL) {
318                 ejsSetErrorMsg(eid, "vsprintf takes an array");
319                 return -1;
320         }
321         length = mprToInt(len);
322         args = talloc_array(mprMemCtx(), struct MprVar *, length);
323         if (args == NULL) {
324                 return -1;
325         }
326
327         for (i=0;i<length;i++) {
328                 char idx[16];
329                 mprItoa(i, idx, sizeof(idx));
330                 args[i] = mprGetProperty(v, idx, NULL);
331         }
332         
333         ret = ejs_sprintf(eid, length, args);
334         talloc_free(args);
335         return ret;
336 }
337
338
339 /*
340   encode a string, replacing all non-alpha with %02x form
341 */
342 static int ejs_encodeURIComponent(MprVarHandle eid, int argc, char **argv)
343 {
344         int i, j, count=0;
345         const char *s;
346         char *ret;
347         if (argc != 1) {
348                 ejsSetErrorMsg(eid, "encodeURIComponent invalid arguments");
349                 return -1;
350         }
351         
352         s = argv[0];
353
354         for (i=0;s[i];i++) {
355                 if (!isalnum(s[i])) count++;
356         }
357         
358         ret = talloc_size(mprMemCtx(), i + count*2 + 1);
359         if (ret == NULL) {
360                 return -1;
361         }
362         for (i=j=0;s[i];i++,j++) {
363                 if (!isalnum(s[i])) {
364                         snprintf(ret+j, 4, "%%%02X", (unsigned)s[i]);
365                         j += 2;
366                 } else {
367                         ret[j] = s[i];
368                 }
369         }
370         ret[j] = 0;
371         mpr_Return(eid, mprString(ret));
372         talloc_free(ret);
373         return 0;
374 }
375
376 /*
377   encode a string, replacing all non-alpha of %02x form
378 */
379 static int ejs_decodeURIComponent(MprVarHandle eid, int argc, char **argv)
380 {
381         int i, j, count=0;
382         const char *s;
383         char *ret;
384         if (argc != 1) {
385                 ejsSetErrorMsg(eid, "decodeURIComponent invalid arguments");
386                 return -1;
387         }
388         
389         s = argv[0];
390
391         ret = talloc_size(mprMemCtx(), strlen(s) + 1);
392         if (ret == NULL) {
393                 return -1;
394         }
395
396         for (i=j=0;s[i];i++,j++) {
397                 if (s[i] == '%') {
398                         unsigned c;
399                         if (sscanf(s+i+1, "%02X", &c) != 1) {
400                                 ejsSetErrorMsg(eid, "decodeURIComponent bad format");
401                                 return -1;
402                         }
403                         ret[j] = c;
404                         i += 2;
405                 } else {
406                         ret[j] = s[i];
407                 }
408                 if (!isalnum(s[i])) count++;
409         }
410         
411         ret[j] = 0;
412         mpr_Return(eid, mprString(ret));
413         talloc_free(ret);
414         return 0;
415 }
416
417 /*
418   initialise string ejs subsystem
419 */
420 static int ejs_string_init(MprVarHandle eid, int argc, struct MprVar **argv)
421 {
422         struct MprVar *obj = mprInitObject(eid, "string", argc, argv);
423
424         mprSetStringCFunction(obj, "strlen", ejs_strlen);
425         mprSetStringCFunction(obj, "strlower", ejs_strlower);
426         mprSetStringCFunction(obj, "strupper", ejs_strupper);
427         mprSetStringCFunction(obj, "strstr", ejs_strstr);
428         mprSetStringCFunction(obj, "split", ejs_split);
429         mprSetCFunction(obj, "join", ejs_join);
430         mprSetCFunction(obj, "sprintf", ejs_sprintf);
431         mprSetCFunction(obj, "vsprintf", ejs_vsprintf);
432         mprSetStringCFunction(obj, "encodeURIComponent", ejs_encodeURIComponent);
433         mprSetStringCFunction(obj, "decodeURIComponent", ejs_decodeURIComponent);
434
435         return 0;
436 }
437
438 /*
439   setup C functions that be called from ejs
440 */
441 void smb_setup_ejs_string(void)
442 {
443         ejsDefineCFunction(-1, "string_init", ejs_string_init, NULL, MPR_VAR_SCRIPT_HANDLE);
444 }