Merge Samba3 and Samba4 together
[bbaumbach/samba-autobuild/.git] / source4 / lib / appweb / ejs-2.0 / ejs / classes / ejsString.c
1 /*
2  *      @file   ejsString.c
3  *      @brief  EJScript string class
4  */
5 /********************************* Copyright **********************************/
6 /*
7  *      @copy   default
8  *      
9  *      Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
10  *      Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
11  *      
12  *      This software is distributed under commercial and open source licenses.
13  *      You may use the GPL open source license described below or you may acquire 
14  *      a commercial license from Mbedthis Software. You agree to be fully bound 
15  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
16  *      this software for full details.
17  *      
18  *      This software is open source; you can redistribute it and/or modify it 
19  *      under the terms of the GNU General Public License as published by the 
20  *      Free Software Foundation; either version 2 of the License, or (at your 
21  *      option) any later version. See the GNU General Public License for more 
22  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
23  *      
24  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
25  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
26  *      
27  *      This GPL license does NOT permit incorporating this software into 
28  *      proprietary programs. If you are unable to comply with the GPL, you must
29  *      acquire a commercial license to use this software. Commercial licenses 
30  *      for this software and support services are available from Mbedthis 
31  *      Software at http://www.mbedthis.com 
32  *      
33  *      @end
34  */
35 /********************************** Includes **********************************/
36
37 #include        "ejs.h"
38
39 #if BLD_FEATURE_EJS
40 /******************************************************************************/
41 /*********************************** Constructors *****************************/
42 /******************************************************************************/
43 /*
44  *      String constructor. 
45  */
46
47 int ejsStringConstructor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
48 {
49         char    *str;
50
51         if (argc == 0) {
52                 ejsSetReturnValueToString(ejs, "");
53
54         } else if (argc == 1) {
55                 /* MOB -- rc */
56                 str = ejsVarToString(ejs, argv[0]);
57                 ejsSetReturnValueToString(ejs, str);
58
59         } else {
60                 ejsArgError(ejs, "usage: String([var])");
61                 return -1;
62         }
63
64         return 0;
65 }
66
67 /******************************************************************************/
68 /******************************** Visible Methods *****************************/
69 /******************************************************************************/
70 /*
71  *      Return a string containing the character at a given index
72  *
73  *      String string.charAt(Number)
74  */
75
76 static int charAt(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
77 {
78         EjsNum          num;
79         char            buf[2];
80
81         if (argc != 1) {
82                 ejsArgError(ejs, "usage: charAt(integer)");
83                 return -1;
84         }
85
86         num = ejsVarToNumber(argv[0]);
87         if (num < 0 || num >= thisObj->length) {
88                 ejsError(ejs, EJS_RANGE_ERROR, "Bad index");
89                 return -1;
90         }
91
92         mprAssert(ejsVarIsString(thisObj));
93
94         buf[0] = argv[0]->string[num];
95         buf[1] = '\0';
96         ejsSetReturnValueToString(ejs, buf);
97
98         return 0;
99 }
100
101 /******************************************************************************/
102 /*
103  *      Return an integer containing the character at a given index
104  *
105  *      Number string.charCodeAt(Number)
106  */
107
108 static EjsNum charCodeAt(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
109 {
110         EjsNum                  num;
111
112         if (argc != 1) {
113                 ejsArgError(ejs, "usage: charCodeAt(integer)");
114                 return -1;
115         }
116
117         num = ejsVarToNumber(argv[0]);
118         if (num < 0 || num >= thisObj->length) {
119                 ejsError(ejs, EJS_RANGE_ERROR, "Bad index");
120                 return -1;
121         }
122         ejsSetReturnValueToNumber(ejs, (EjsNum) argv[0]->string[num]);
123
124         return 0;
125 }
126
127 /******************************************************************************/
128 /*
129  *      Catenate
130  *
131  *      String string.catenate(var, ...)
132  */
133
134 static int concat(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
135 {
136         int                             i;
137
138         if (argc == 0) {
139                 ejsArgError(ejs, "usage: concat(String, ...)");
140                 return -1;
141         }
142
143         mprAssert(ejsVarIsString(thisObj));
144
145         for (i = 0; i < argc; i++) {
146                 if (ejsStrcat(ejs, thisObj, argv[i]) < 0) {
147                         ejsMemoryError(ejs);
148                         return -1;
149                 }
150         }
151         ejsSetReturnValue(ejs, thisObj);
152         return 0;
153 }
154
155 /******************************************************************************/
156 /*
157  *      Return the position of the first occurance of a substring
158  *
159  *      Number string.indexOf(String subString [, Number start])
160  */
161
162 static int indexOf(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
163 {
164         char    *pat, *s1, *s2, *origin;
165         int             start, i;
166
167         if (argc == 0 || argc > 2) {
168                 ejsArgError(ejs, "usage: indexOf(String [, Number])");
169                 return -1;
170         }
171
172         pat = ejsVarToString(ejs, argv[0]);
173
174         if (argc == 2) {
175                 start = ejsVarToNumber(argv[1]);
176                 if (start > thisObj->length) {
177                         start = thisObj->length;
178                 }
179         } else {
180                 start = 0;
181         }
182
183         i = start;
184         for (origin = &thisObj->string[i]; i < thisObj->length; i++, origin++) {
185                 s1 = origin;
186                 for (s2 = pat; *s1 && *s2; s1++, s2++) {
187                         if (*s1 != *s2) {
188                                 break;
189                         }
190                 }
191                 if (*s2 == '\0') {
192                         ejsSetReturnValueToNumber(ejs, (EjsNum) (origin - thisObj->string));
193                 }
194         }
195
196         ejsSetReturnValueToNumber(ejs, (EjsNum) -1);
197         return 0;
198 }
199
200 /******************************************************************************/
201 /*
202  *      Return the position of the last occurance of a substring
203  *
204  *      Number string.lastIndexOf(String subString [, Number start])
205  */
206
207 static int lastIndexOf(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
208 {
209         char    *pat, *s1, *s2, *origin;
210         int             start;
211
212         if (argc == 0 || argc > 2) {
213                 ejsArgError(ejs, "usage: indexOf(String [, Number])");
214                 return -1;
215         }
216
217         pat = ejsVarToString(ejs, argv[0]);
218
219         if (argc == 2) {
220                 start = ejsVarToNumber(argv[1]);
221                 if (start > thisObj->length) {
222                         start = thisObj->length;
223                 }
224         } else {
225                 start = 0;
226         }
227
228         origin = &thisObj->string[thisObj->length - 1];
229         for (; origin >= &thisObj->string[start]; origin--) {
230
231                 s1 = origin;
232                 for (s2 = pat; *s1 && *s2; s1++, s2++) {
233                         if (*s1 != *s2) {
234                                 break;
235                         }
236                 }
237                 if (*s2 == '\0') {
238                         ejsSetReturnValueToNumber(ejs, (EjsNum) (origin - thisObj->string));
239                 }
240         }
241
242         ejsSetReturnValueToNumber(ejs, (EjsNum) -1);
243         return 0;
244 }
245
246 /******************************************************************************/
247 /*
248  *      Return a substring
249  *
250  *      Number string.slice(Number start, Number end)
251  */
252
253 static int slice(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
254 {
255         EjsNum          start, end;
256
257         if (argc != 2) {
258                 ejsArgError(ejs, "usage: slice(Number, Number)");
259                 return -1;
260         }
261
262         start = ejsVarToNumber(argv[0]);
263         end = ejsVarToNumber(argv[1]);
264         if (start < 0 || start >= thisObj->length) {
265                 ejsError(ejs, EJS_RANGE_ERROR, "Bad start index");
266                 return-1;
267         }
268         if (end < 0 || end >= thisObj->length) {
269                 ejsError(ejs, EJS_RANGE_ERROR, "Bad end index");
270                 return -1;
271         }
272
273         mprAssert(ejsVarIsString(thisObj));
274
275         ejsSetReturnValueToBinaryString(ejs, (uchar*) &thisObj->string[start],
276                 end - start);
277
278         return 0;
279 }
280
281 /******************************************************************************/
282 /*
283  *      Split a string
284  *
285  *      Number string.split(String delimiter [, Number limit])
286  */
287
288 static int split(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
289 {
290         EjsVar          *array, *vp;
291         char            *delim, *last, *cp;
292         int                     len, limit, alloc;
293
294         if (argc == 0 || argc > 2) {
295                 ejsArgError(ejs, "usage: split(String [, Number])");
296                 return -1;
297         }
298
299         delim = ejsVarToStringEx(ejs, argv[0], &alloc);
300
301         limit = ejsVarToNumber(argv[1]);
302
303         array = ejsCreateArray(ejs, 0);
304
305         len = strlen(delim);
306
307         last = thisObj->string;
308         for (cp = last; *cp; cp++) {
309                 if (*cp == *delim && strncmp(cp, delim, len) == 0) {
310                         if (cp > last) {
311                                 vp = ejsCreateBinaryStringVar(ejs, (uchar*) last, (cp - last));
312                                 ejsAddArrayElt(ejs, array, vp, EJS_SHALLOW_COPY);
313                                 ejsFreeVar(ejs, vp);
314                         }
315                 }
316         }
317
318         ejsSetReturnValue(ejs, array);
319         ejsFreeVar(ejs, array);
320
321         if (alloc) {
322                 mprFree(delim);
323         }
324
325         return 0;
326 }
327
328 /******************************************************************************/
329 /*
330  *      Create the object class
331  */
332
333 int ejsDefineStringClass(Ejs *ejs)
334 {
335         EjsVar          *sc;
336
337         sc = ejsDefineClass(ejs, "String", "Object", ejsStringConstructor);
338         if (sc == 0) {
339                 return MPR_ERR_CANT_INITIALIZE;
340         }
341
342         ejsDefineCMethod(ejs, sc, "charAt", charAt, EJS_NO_LOCAL);
343         ejsDefineCMethod(ejs, sc, "charCodeAt", charCodeAt, EJS_NO_LOCAL);
344         ejsDefineCMethod(ejs, sc, "concat", concat, EJS_NO_LOCAL);
345         ejsDefineCMethod(ejs, sc, "indexOf", indexOf, EJS_NO_LOCAL);
346         ejsDefineCMethod(ejs, sc, "lastIndexOf", lastIndexOf, EJS_NO_LOCAL);
347         ejsDefineCMethod(ejs, sc, "slice", slice, EJS_NO_LOCAL);
348         ejsDefineCMethod(ejs, sc, "split", split, EJS_NO_LOCAL);
349 #if UNUSED
350         ejsDefineCMethod(ejs, sc, "match", match, EJS_NO_LOCAL);
351         ejsDefineCMethod(ejs, sc, "replace", replace, EJS_NO_LOCAL);
352         ejsDefineCMethod(ejs, sc, "search", search, EJS_NO_LOCAL);
353         ejsDefineCMethod(ejs, sc, "substring", substring, EJS_NO_LOCAL);
354         //      MOB bad name
355         ejsDefineCMethod(ejs, sc, "substr", substr, EJS_NO_LOCAL);
356         ejsDefineCMethod(ejs, sc, "toLowerCase", toLowerCase, EJS_NO_LOCAL);
357         ejsDefineCMethod(ejs, sc, "toUpperCase", toUpperCase, EJS_NO_LOCAL);
358
359         //      Static method
360         ejsDefineCMethod(ejs, sc, "fromCharCode", fromCharCode, 0, EJS_NO_LOCAL);
361 #endif
362
363         if (ejsObjHasErrors(sc)) {
364                 ejsFreeVar(ejs, sc);
365                 return MPR_ERR_CANT_CREATE;
366         }
367         return 0;
368 }
369
370 /******************************************************************************/
371 #endif /* BLD_FEATURE_EJS */
372
373 /*
374  * Local variables:
375  * tab-width: 4
376  * c-basic-offset: 4
377  * End:
378  * vim:tw=78
379  * vim600: sw=4 ts=4 fdm=marker
380  * vim<600: sw=4 ts=4
381  */