r8372: - split out provisioning logic into a separate ejs library
[jra/samba/.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/ejs/ejs.h"
26 #include "system/passwd.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      list = split(".", "a.foo.bar");
79
80   NOTE: does not take a regular expression, unlink perl split()
81 */
82 static int ejs_split(MprVarHandle eid, int argc, char **argv)
83 {
84         const char *separator;
85         char *s, *p;
86         struct MprVar ret;
87         int count = 0;
88         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
89         if (argc != 2) {
90                 ejsSetErrorMsg(eid, "split invalid arguments");
91                 return -1;
92         }
93         separator = argv[0];
94         s = argv[1];
95
96         ret = mprObject("list");
97
98         while ((p = strstr(s, separator))) {
99                 char *s2 = talloc_strndup(tmp_ctx, s, (int)(p-s));
100                 mprAddArray(&ret, count++, mprString(s2));
101                 talloc_free(s2);
102                 s = p + strlen(separator);
103         }
104         if (*s) {
105                 mprAddArray(&ret, count++, mprString(s));
106         }
107         talloc_free(tmp_ctx);
108         mpr_Return(eid, ret);
109         return 0;
110 }
111
112
113 /*
114   usage:
115      str = join("DC=", list);
116 */
117 static int ejs_join(MprVarHandle eid, int argc, struct MprVar **argv)
118 {
119         int i;
120         const char *separator;
121         char *ret = NULL;
122         const char **list;
123         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
124         if (argc != 2 ||
125             argv[0]->type != MPR_TYPE_STRING ||
126             argv[1]->type != MPR_TYPE_OBJECT) {
127                 ejsSetErrorMsg(eid, "join invalid arguments");
128                 return -1;
129         }
130
131         separator = mprToString(argv[0]);
132         list      = mprToArray(tmp_ctx, argv[1]);
133
134         if (list == NULL || list[0] == NULL) {
135                 talloc_free(tmp_ctx);
136                 mpr_Return(eid, mprString(NULL));
137                 return 0;
138         }
139         
140         ret = talloc_strdup(tmp_ctx, list[0]);
141         if (ret == NULL) {
142                 goto failed;
143         }
144         for (i=1;list[i];i++) {
145                 ret = talloc_asprintf_append(ret, "%s%s", separator, list[i]);
146                 if (ret == NULL) {
147                         goto failed;
148                 }
149         }
150         mpr_Return(eid, mprString(ret));
151         talloc_free(tmp_ctx);
152         return 0;
153 failed:
154         ejsSetErrorMsg(eid, "out of memory");
155         return -1;
156 }
157
158
159 /*
160   blergh, C certainly makes this hard!
161   usage:
162      str = sprintf("i=%d s=%7s", 7, "foo");
163 */
164 static int ejs_sprintf(MprVarHandle eid, int argc, struct MprVar **argv)
165 {
166         const char *format;
167         const char *p;
168         char *ret;
169         int a = 1;
170         char *(*_asprintf_append)(char *, const char *, ...);
171         TALLOC_CTX *tmp_ctx;
172         if (argc < 1 || argv[0]->type != MPR_TYPE_STRING) {
173                 ejsSetErrorMsg(eid, "sprintf invalid arguments");
174                 return -1;
175         }
176         format = mprToString(argv[0]);
177         tmp_ctx = talloc_new(mprMemCtx());
178         ret = talloc_strdup(tmp_ctx, "");
179
180         /* avoid all the format string warnings */
181         _asprintf_append = talloc_asprintf_append;
182
183         /*
184           hackity hack ...
185         */
186         while ((p = strchr(format, '%'))) {
187                 char *fmt2;
188                 int len, len_count=0;
189                 char *tstr;
190                 ret = talloc_asprintf_append(ret, "%*.*s", 
191                                              (int)(p-format), (int)(p-format), 
192                                              format);
193                 if (ret == NULL) goto failed;
194                 format += (int)(p-format);
195                 len = strcspn(p+1, "dxuiofgGpXeEFcs%") + 1;
196                 fmt2 = talloc_strndup(tmp_ctx, p, len+1);
197                 if (fmt2 == NULL) goto failed;
198                 len_count = count_chars(fmt2, '*');
199                 /* find the type string */
200                 tstr = &fmt2[len];
201                 while (tstr > fmt2 && isalpha(tstr[-1])) {
202                         tstr--;
203                 }
204                 if (strcmp(tstr, "%") == 0) {
205                         ret = talloc_asprintf_append(ret, "%%");
206                         if (ret == NULL) {
207                                 goto failed;
208                         }
209                         format += len+1;
210                         continue;
211                 }
212                 if (len_count > 2 || 
213                     argc < a + len_count + 1) {
214                         ejsSetErrorMsg(eid, "sprintf: not enough arguments for format");
215                         goto failed;
216                 }
217 #define FMT_ARG(fn, type) do { \
218                         switch (len_count) { \
219                         case 0: \
220                                 ret = _asprintf_append(ret, fmt2, \
221                                                              (type)fn(argv[a])); \
222                                 break; \
223                         case 1: \
224                                 ret = _asprintf_append(ret, fmt2, \
225                                                              (int)mprVarToNumber(argv[a]), \
226                                                              (type)fn(argv[a+1])); \
227                                 break; \
228                         case 2: \
229                                 ret = _asprintf_append(ret, fmt2, \
230                                                              (int)mprVarToNumber(argv[a]), \
231                                                              (int)mprVarToNumber(argv[a+1]), \
232                                                              (type)fn(argv[a+2])); \
233                                 break; \
234                         } \
235                         a += len_count + 1; \
236                         if (ret == NULL) { \
237                                 goto failed; \
238                         } \
239 } while (0)
240
241                 if (strcmp(tstr, "s")==0)        FMT_ARG(mprToString,    const char *);
242                 else if (strcmp(tstr, "c")==0)   FMT_ARG(*mprToString,   char);
243                 else if (strcmp(tstr, "d")==0)   FMT_ARG(mprVarToNumber, int);
244                 else if (strcmp(tstr, "ld")==0)  FMT_ARG(mprVarToNumber, long);
245                 else if (strcmp(tstr, "lld")==0) FMT_ARG(mprVarToNumber, long long);
246                 else if (strcmp(tstr, "x")==0)   FMT_ARG(mprVarToNumber, int);
247                 else if (strcmp(tstr, "lx")==0)  FMT_ARG(mprVarToNumber, long);
248                 else if (strcmp(tstr, "llx")==0) FMT_ARG(mprVarToNumber, long long);
249                 else if (strcmp(tstr, "X")==0)   FMT_ARG(mprVarToNumber, int);
250                 else if (strcmp(tstr, "lX")==0)  FMT_ARG(mprVarToNumber, long);
251                 else if (strcmp(tstr, "llX")==0) FMT_ARG(mprVarToNumber, long long);
252                 else if (strcmp(tstr, "u")==0)   FMT_ARG(mprVarToNumber, int);
253                 else if (strcmp(tstr, "lu")==0)  FMT_ARG(mprVarToNumber, long);
254                 else if (strcmp(tstr, "llu")==0) FMT_ARG(mprVarToNumber, long long);
255                 else if (strcmp(tstr, "i")==0)   FMT_ARG(mprVarToNumber, int);
256                 else if (strcmp(tstr, "li")==0)  FMT_ARG(mprVarToNumber, long);
257                 else if (strcmp(tstr, "lli")==0) FMT_ARG(mprVarToNumber, long long);
258                 else if (strcmp(tstr, "o")==0)   FMT_ARG(mprVarToNumber, int);
259                 else if (strcmp(tstr, "lo")==0)  FMT_ARG(mprVarToNumber, long);
260                 else if (strcmp(tstr, "llo")==0) FMT_ARG(mprVarToNumber, long long);
261                 else if (strcmp(tstr, "f")==0)   FMT_ARG(mprVarToFloat,  double);
262                 else if (strcmp(tstr, "lf")==0)  FMT_ARG(mprVarToFloat,  double);
263                 else if (strcmp(tstr, "g")==0)   FMT_ARG(mprVarToFloat,  double);
264                 else if (strcmp(tstr, "lg")==0)  FMT_ARG(mprVarToFloat,  double);
265                 else if (strcmp(tstr, "e")==0)   FMT_ARG(mprVarToFloat,  double);
266                 else if (strcmp(tstr, "le")==0)  FMT_ARG(mprVarToFloat,  double);
267                 else if (strcmp(tstr, "E")==0)   FMT_ARG(mprVarToFloat,  double);
268                 else if (strcmp(tstr, "lE")==0)  FMT_ARG(mprVarToFloat,  double);
269                 else if (strcmp(tstr, "F")==0)   FMT_ARG(mprVarToFloat,  double);
270                 else if (strcmp(tstr, "lF")==0)  FMT_ARG(mprVarToFloat,  double);
271                 else {
272                         ejsSetErrorMsg(eid, "sprintf: unknown format string '%s'", fmt2);
273                         goto failed;
274                 }
275                 format += len+1;
276         }
277
278         ret = talloc_asprintf_append(ret, "%s", format);
279         mpr_Return(eid, mprString(ret));
280         talloc_free(tmp_ctx);
281         return 0;          
282         
283 failed:
284         talloc_free(tmp_ctx);
285         return -1;
286 }
287
288 /*
289   used to build your own print function
290      str = vsprintf(args);
291 */
292 static int ejs_vsprintf(MprVarHandle eid, int argc, struct MprVar **argv)
293 {
294         struct MprVar **args, *len, *v;
295         int i, ret, length;
296         if (argc != 1 || argv[0]->type != MPR_TYPE_OBJECT) {
297                 ejsSetErrorMsg(eid, "vsprintf invalid arguments");
298                 return -1;
299         }
300         v = argv[0];
301         len = mprGetProperty(v, "length", NULL);
302         if (len == NULL) {
303                 ejsSetErrorMsg(eid, "vsprintf takes an array");
304                 return -1;
305         }
306         length = mprToInt(len);
307         args = talloc_array(mprMemCtx(), struct MprVar *, length);
308         if (args == NULL) {
309                 return -1;
310         }
311
312         for (i=0;i<length;i++) {
313                 char idx[16];
314                 mprItoa(i, idx, sizeof(idx));
315                 args[i] = mprGetProperty(v, idx, NULL);
316         }
317         
318         ret = ejs_sprintf(eid, length, args);
319         talloc_free(args);
320         return ret;
321 }
322
323 /*
324   setup C functions that be called from ejs
325 */
326 void smb_setup_ejs_string(void)
327 {
328         ejsDefineStringCFunction(-1, "strlen", ejs_strlen, NULL, MPR_VAR_SCRIPT_HANDLE);
329         ejsDefineStringCFunction(-1, "strlower", ejs_strlower, NULL, MPR_VAR_SCRIPT_HANDLE);
330         ejsDefineStringCFunction(-1, "strupper", ejs_strupper, NULL, MPR_VAR_SCRIPT_HANDLE);
331         ejsDefineStringCFunction(-1, "split", ejs_split, NULL, MPR_VAR_SCRIPT_HANDLE);
332         ejsDefineCFunction(-1, "join", ejs_join, NULL, MPR_VAR_SCRIPT_HANDLE);
333         ejsDefineCFunction(-1, "sprintf", ejs_sprintf, NULL, MPR_VAR_SCRIPT_HANDLE);
334         ejsDefineCFunction(-1, "vsprintf", ejs_vsprintf, NULL, MPR_VAR_SCRIPT_HANDLE);
335 }