2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / NativeString.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\r
3  * The contents of this file are subject to the Netscape Public\r
4  * License Version 1.1 (the "License"); you may not use this file\r
5  * except in compliance with the License. You may obtain a copy of\r
6  * the License at http://www.mozilla.org/NPL/\r
7  *\r
8  * Software distributed under the License is distributed on an "AS\r
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
10  * implied. See the License for the specific language governing\r
11  * rights and limitations under the License.\r
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\r
16  * The Initial Developer of the Original Code is Netscape\r
17  * Communications Corporation.  Portions created by Netscape are\r
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s):\r
22  * Tom Beauvais\r
23  * Norris Boyd\r
24  * Mike McCabe\r
25  *\r
26  * Alternatively, the contents of this file may be used under the\r
27  * terms of the GNU Public License (the "GPL"), in which case the\r
28  * provisions of the GPL are applicable instead of those above.\r
29  * If you wish to allow use of your version of this file only\r
30  * under the terms of the GPL and not to allow others to use your\r
31  * version of this file under the NPL, indicate your decision by\r
32  * deleting the provisions above and replace them with the notice\r
33  * and other provisions required by the GPL.  If you do not delete\r
34  * the provisions above, a recipient may use your version of this\r
35  * file under either the NPL or the GPL.\r
36  */\r
37 \r
38 package org.mozilla.javascript;\r
39 \r
40 import java.lang.reflect.Method;\r
41 import java.util.Vector;\r
42 \r
43 /**\r
44  * This class implements the String native object.\r
45  *\r
46  * See ECMA 15.5.\r
47  *\r
48  * String methods for dealing with regular expressions are\r
49  * ported directly from C. Latest port is from version 1.40.12.19\r
50  * in the JSFUN13_BRANCH.\r
51  *\r
52  * @author Mike McCabe\r
53  * @author Norris Boyd\r
54  */\r
55 public class NativeString extends IdScriptable {\r
56 \r
57     public static void init(Context cx, Scriptable scope, boolean sealed) {\r
58         NativeString obj = new NativeString();\r
59         obj.prototypeFlag = true;\r
60         obj.addAsPrototype(MAX_PROTOTYPE_ID, cx, scope, sealed);\r
61     }\r
62 \r
63     /**\r
64      * Zero-parameter constructor: just used to create String.prototype\r
65      */\r
66     public NativeString() {\r
67         string = defaultValue;\r
68     }\r
69 \r
70     public NativeString(String s) {\r
71         string = s;\r
72     }\r
73 \r
74     public String getClassName() {\r
75         return "String";\r
76     }\r
77 \r
78     protected void fillConstructorProperties\r
79         (Context cx, IdFunction ctor, boolean sealed)\r
80     {\r
81         addIdFunctionProperty(ctor, ConstructorId_fromCharCode, sealed);\r
82         super.fillConstructorProperties(cx, ctor, sealed);\r
83     }\r
84 \r
85     protected int getIdDefaultAttributes(int id) {\r
86         if (id == Id_length) {\r
87             return DONTENUM | READONLY | PERMANENT;\r
88         }\r
89         return super.getIdDefaultAttributes(id);\r
90     }\r
91 \r
92     protected Object getIdValue(int id) {\r
93         if (id == Id_length) {\r
94             return wrap_int(string.length());\r
95         }\r
96         return super.getIdValue(id);\r
97     }\r
98 \r
99     public int methodArity(int methodId) {\r
100         if (prototypeFlag) {\r
101             switch (methodId) {\r
102                 case ConstructorId_fromCharCode:   return 1;\r
103 \r
104                 case Id_constructor:               return 1;\r
105                 case Id_toString:                  return 0;\r
106                 case Id_valueOf:                   return 0;\r
107                 case Id_charAt:                    return 1;\r
108                 case Id_charCodeAt:                return 1;\r
109                 case Id_indexOf:                   return 2;\r
110                 case Id_lastIndexOf:               return 2;\r
111                 case Id_split:                     return 1;\r
112                 case Id_substring:                 return 2;\r
113                 case Id_toLowerCase:               return 0;\r
114                 case Id_toUpperCase:               return 0;\r
115                 case Id_substr:                    return 2;\r
116                 case Id_concat:                    return 1;\r
117                 case Id_slice:                     return 2;\r
118                 case Id_bold:                      return 0;\r
119                 case Id_italics:                   return 0;\r
120                 case Id_fixed:                     return 0;\r
121                 case Id_strike:                    return 0;\r
122                 case Id_small:                     return 0;\r
123                 case Id_big:                       return 0;\r
124                 case Id_blink:                     return 0;\r
125                 case Id_sup:                       return 0;\r
126                 case Id_sub:                       return 0;\r
127                 case Id_fontsize:                  return 0;\r
128                 case Id_fontcolor:                 return 0;\r
129                 case Id_link:                      return 0;\r
130                 case Id_anchor:                    return 0;\r
131                 case Id_equals:                    return 1;\r
132                 case Id_equalsIgnoreCase:          return 1;\r
133                 case Id_match:                     return 1;\r
134                 case Id_search:                    return 1;\r
135                 case Id_replace:                   return 1;\r
136             }\r
137         }\r
138         return super.methodArity(methodId);\r
139     }\r
140 \r
141     public Object execMethod\r
142         (int methodId, IdFunction f,\r
143          Context cx, Scriptable scope, Scriptable thisObj, Object[] args)\r
144         throws JavaScriptException\r
145     {\r
146         if (prototypeFlag) {\r
147             switch (methodId) {\r
148                 case ConstructorId_fromCharCode: \r
149                     return jsStaticFunction_fromCharCode(args);\r
150 \r
151                 case Id_constructor:\r
152                     return jsConstructor(args, thisObj == null);\r
153 \r
154                 case Id_toString:\r
155                     return realThis(thisObj, f).jsFunction_toString();\r
156 \r
157                 case Id_valueOf:\r
158                     return realThis(thisObj, f).jsFunction_valueOf();\r
159 \r
160                 case Id_charAt: \r
161                     return jsFunction_charAt\r
162                         (ScriptRuntime.toString(thisObj), args);\r
163 \r
164                 case Id_charCodeAt: \r
165                     return wrap_double(jsFunction_charCodeAt\r
166                         (ScriptRuntime.toString(thisObj), args));\r
167 \r
168                 case Id_indexOf:\r
169                     return wrap_int(jsFunction_indexOf\r
170                         (ScriptRuntime.toString(thisObj), args));\r
171 \r
172                 case Id_lastIndexOf: \r
173                     return wrap_int(jsFunction_lastIndexOf\r
174                         (ScriptRuntime.toString(thisObj), args));\r
175 \r
176                 case Id_split: \r
177                     return jsFunction_split\r
178                         (cx, scope, ScriptRuntime.toString(thisObj), args);\r
179 \r
180                 case Id_substring:\r
181                     return jsFunction_substring\r
182                         (cx, ScriptRuntime.toString(thisObj), args);\r
183 \r
184                 case Id_toLowerCase:\r
185                     return jsFunction_toLowerCase\r
186                         (ScriptRuntime.toString(thisObj));\r
187 \r
188                 case Id_toUpperCase:\r
189                     return jsFunction_toUpperCase\r
190                         (ScriptRuntime.toString(thisObj));\r
191 \r
192                 case Id_substr: \r
193                     return jsFunction_substr\r
194                         (ScriptRuntime.toString(thisObj), args);\r
195 \r
196                 case Id_concat:\r
197                     return jsFunction_concat\r
198                         (ScriptRuntime.toString(thisObj), args);\r
199 \r
200                 case Id_slice:\r
201                     return jsFunction_slice\r
202                      (ScriptRuntime.toString(thisObj), args);\r
203 \r
204                 case Id_bold:\r
205                     return realThis(thisObj, f).tagify("b", null, null);\r
206 \r
207                 case Id_italics:\r
208                     return realThis(thisObj, f).tagify("i", null, null);\r
209 \r
210                 case Id_fixed:\r
211                     return realThis(thisObj, f).tagify("tt", null, null);\r
212 \r
213                 case Id_strike:\r
214                     return realThis(thisObj, f).tagify("strike", null, null);\r
215 \r
216                 case Id_small:\r
217                     return realThis(thisObj, f).tagify("small", null, null);\r
218 \r
219                 case Id_big:\r
220                     return realThis(thisObj, f).tagify("big", null, null);\r
221 \r
222                 case Id_blink:\r
223                     return realThis(thisObj, f).tagify("blink", null, null);\r
224 \r
225                 case Id_sup:\r
226                     return realThis(thisObj, f).tagify("sup", null, null);\r
227 \r
228                 case Id_sub:\r
229                     return realThis(thisObj, f).tagify("sub", null, null);\r
230 \r
231                 case Id_fontsize:\r
232                     return realThis(thisObj, f).\r
233                         tagify("font size", "font", \r
234                                ScriptRuntime.toString(args, 0));\r
235 \r
236                 case Id_fontcolor:\r
237                     return realThis(thisObj, f).\r
238                         tagify("font color", "font",\r
239                                ScriptRuntime.toString(args, 0));\r
240 \r
241                 case Id_link:\r
242                     return realThis(thisObj, f).\r
243                         tagify("a href", "a", ScriptRuntime.toString(args, 0));\r
244 \r
245                 case Id_anchor:\r
246                     return realThis(thisObj, f).\r
247                         tagify("a name", "a", ScriptRuntime.toString(args, 0));\r
248 \r
249                 case Id_equals:\r
250                     return wrap_boolean(jsFunction_equals\r
251                         (ScriptRuntime.toString(thisObj),\r
252                          ScriptRuntime.toString(args, 0)));\r
253 \r
254                 case Id_equalsIgnoreCase:\r
255                     return wrap_boolean(jsFunction_equalsIgnoreCase\r
256                         (ScriptRuntime.toString(thisObj),\r
257                          ScriptRuntime.toString(args, 0)));\r
258 \r
259                 case Id_match:\r
260                     return checkReProxy(cx).match(cx, scope, thisObj, args);\r
261 \r
262                 case Id_search:\r
263                     return checkReProxy(cx).search(cx, scope, thisObj, args);\r
264 \r
265                 case Id_replace:\r
266                     return checkReProxy(cx).replace(cx, scope, thisObj, args);\r
267             }\r
268         }\r
269         return super.execMethod(methodId, f, cx, scope, thisObj, args);\r
270     }\r
271 \r
272     private NativeString realThis(Scriptable thisObj, IdFunction f) {\r
273         while (!(thisObj instanceof NativeString)) {\r
274             thisObj = nextInstanceCheck(thisObj, f, true);\r
275         }\r
276         return (NativeString)thisObj;\r
277     }\r
278 \r
279     private static RegExpProxy checkReProxy(Context cx) {\r
280         RegExpProxy result = cx.getRegExpProxy();\r
281         if (result == null) {\r
282             throw cx.reportRuntimeError0("msg.no.regexp");\r
283         }\r
284         return result;\r
285     }\r
286 \r
287     /*\r
288      * HTML composition aids.\r
289      */\r
290     private String tagify(String begin, String end, String value) {\r
291         StringBuffer result = new StringBuffer();\r
292         result.append('<');\r
293         result.append(begin);\r
294         if (value != null) {\r
295             result.append("=\"");\r
296             result.append(value);\r
297             result.append('"');\r
298         }\r
299         result.append('>');\r
300         result.append(this.string);\r
301         result.append("</");\r
302         result.append((end == null) ? begin : end);\r
303         result.append('>');\r
304         return result.toString();\r
305     }\r
306 \r
307     private static String jsStaticFunction_fromCharCode(Object[] args) {\r
308         int N = args.length;\r
309         if (N < 1)\r
310             return "";\r
311         StringBuffer s = new java.lang.StringBuffer(N);\r
312         for (int i=0; i < N; i++) {\r
313             s.append(ScriptRuntime.toUint16(args[i]));\r
314         }\r
315         return s.toString();\r
316     }\r
317 \r
318     private static Object jsConstructor(Object[] args, boolean inNewExpr) {\r
319         String s = args.length >= 1\r
320             ? ScriptRuntime.toString(args[0])\r
321             : defaultValue;\r
322         if (inNewExpr) {\r
323             // new String(val) creates a new String object.\r
324             return new NativeString(s);\r
325         }\r
326         // String(val) converts val to a string value.\r
327         return s;\r
328     }\r
329 \r
330     public String toString() {\r
331         return string;\r
332     }\r
333 \r
334     /* ECMA 15.5.4.2: 'the toString function is not generic.' */\r
335     private String jsFunction_toString() {\r
336         return string;\r
337     }\r
338 \r
339     private String jsFunction_valueOf() {\r
340         return string;\r
341     }\r
342 \r
343     /* Make array-style property lookup work for strings.\r
344      * XXX is this ECMA?  A version check is probably needed. In js too.\r
345      */\r
346     public Object get(int index, Scriptable start) {\r
347         if (index >= 0 && index < string.length())\r
348             return string.substring(index, index + 1);\r
349         return super.get(index, start);\r
350     }\r
351 \r
352     public void put(int index, Scriptable start, Object value) {\r
353         if (index >= 0 && index < string.length())\r
354             return;\r
355         super.put(index, start, value);\r
356     }\r
357 \r
358     /*\r
359      *\r
360      * See ECMA 15.5.4.[4,5]\r
361      */\r
362     private static String jsFunction_charAt(String target, Object[] args)\r
363     {\r
364         // this'll return 0 if undefined... seems\r
365         // to be ECMA.\r
366         double pos = ScriptRuntime.toInteger(args, 0);\r
367 \r
368         if (pos < 0 || pos >= target.length())\r
369             return "";\r
370 \r
371         return target.substring((int)pos, (int)pos + 1);\r
372     }\r
373 \r
374     private static double jsFunction_charCodeAt(String target, Object[] args)\r
375     {\r
376         double pos = ScriptRuntime.toInteger(args, 0);\r
377 \r
378         if (pos < 0 || pos >= target.length()) {\r
379             return ScriptRuntime.NaN;\r
380         }\r
381 \r
382         return target.charAt((int)pos);\r
383     }\r
384 \r
385     /*\r
386      *\r
387      * See ECMA 15.5.4.6.  Uses Java String.indexOf()\r
388      * OPT to add - BMH searching from jsstr.c.\r
389      */\r
390     private static int jsFunction_indexOf(String target, Object[] args) {\r
391         String search = ScriptRuntime.toString(args, 0);\r
392         double begin = ScriptRuntime.toInteger(args, 1);\r
393 \r
394         if (begin > target.length()) {\r
395             return -1;\r
396         } else {\r
397             if (begin < 0)\r
398                 begin = 0;\r
399             return target.indexOf(search, (int)begin);\r
400         }\r
401     }\r
402 \r
403     /*\r
404      *\r
405      * See ECMA 15.5.4.7\r
406      *\r
407      */\r
408     private static int jsFunction_lastIndexOf(String target, Object[] args) {\r
409         String search = ScriptRuntime.toString(args, 0);\r
410         double end = ScriptRuntime.toNumber(args, 1);\r
411 \r
412         if (end != end || end > target.length())\r
413             end = target.length();\r
414         else if (end < 0)\r
415             end = 0;\r
416 \r
417         return target.lastIndexOf(search, (int)end);\r
418     }\r
419 \r
420     /*\r
421      * Used by js_split to find the next split point in target,\r
422      * starting at offset ip and looking either for the given\r
423      * separator substring, or for the next re match.  ip and\r
424      * matchlen must be reference variables (assumed to be arrays of\r
425      * length 1) so they can be updated in the leading whitespace or\r
426      * re case.\r
427      *\r
428      * Return -1 on end of string, >= 0 for a valid index of the next\r
429      * separator occurrence if found, or the string length if no\r
430      * separator is found.\r
431      */\r
432     private static int find_split(Scriptable scope, String target,\r
433                                   String separator, Object re,\r
434                                   int[] ip, int[] matchlen, boolean[] matched,\r
435                                   String[][] parensp)\r
436     {\r
437         int i = ip[0];\r
438         int length = target.length();\r
439         Context cx = Context.getContext();\r
440         int version = cx.getLanguageVersion();\r
441 \r
442         /*\r
443          * Perl4 special case for str.split(' '), only if the user has selected\r
444          * JavaScript1.2 explicitly.  Split on whitespace, and skip leading w/s.\r
445          * Strange but true, apparently modeled after awk.\r
446          */\r
447         if (version == Context.VERSION_1_2 &&\r
448             re == null && separator.length() == 1 && separator.charAt(0) == ' ')\r
449         {\r
450             /* Skip leading whitespace if at front of str. */\r
451             if (i == 0) {\r
452                 while (i < length && Character.isWhitespace(target.charAt(i)))\r
453                     i++;\r
454                 ip[0] = i;\r
455             }\r
456 \r
457             /* Don't delimit whitespace at end of string. */\r
458             if (i == length)\r
459                 return -1;\r
460 \r
461             /* Skip over the non-whitespace chars. */\r
462             while (i < length\r
463                    && !Character.isWhitespace(target.charAt(i)))\r
464                 i++;\r
465 \r
466             /* Now skip the next run of whitespace. */\r
467             int j = i;\r
468             while (j < length && Character.isWhitespace(target.charAt(j)))\r
469                 j++;\r
470 \r
471             /* Update matchlen to count delimiter chars. */\r
472             matchlen[0] = j - i;\r
473             return i;\r
474         }\r
475 \r
476         /*\r
477          * Stop if past end of string.  If at end of string, we will\r
478          * return target length, so that\r
479          *\r
480          *  "ab,".split(',') => new Array("ab", "")\r
481          *\r
482          * and the resulting array converts back to the string "ab,"\r
483          * for symmetry.  NB: This differs from perl, which drops the\r
484          * trailing empty substring if the LIMIT argument is omitted.\r
485          */\r
486         if (i > length)\r
487             return -1;\r
488 \r
489         /*\r
490          * Match a regular expression against the separator at or\r
491          * above index i.  Return -1 at end of string instead of\r
492          * trying for a match, so we don't get stuck in a loop.\r
493          */\r
494         if (re != null) {\r
495             return cx.getRegExpProxy().find_split(scope, target,\r
496                                                   separator, re,\r
497                                                   ip, matchlen, matched,\r
498                                                   parensp);\r
499         }\r
500 \r
501         /*\r
502          * Deviate from ECMA by never splitting an empty string by any separator\r
503          * string into a non-empty array (an array of length 1 that contains the\r
504          * empty string).\r
505          */\r
506         if (version != Context.VERSION_DEFAULT && version < Context.VERSION_1_3\r
507             && length == 0)\r
508             return -1;\r
509 \r
510         /*\r
511          * Special case: if sep is the empty string, split str into\r
512          * one character substrings.  Let our caller worry about\r
513          * whether to split once at end of string into an empty\r
514          * substring.\r
515          *\r
516          * For 1.2 compatibility, at the end of the string, we return the length as\r
517          * the result, and set the separator length to 1 -- this allows the caller\r
518          * to include an additional null string at the end of the substring list.\r
519          */\r
520         if (separator.length() == 0) {\r
521             if (version == Context.VERSION_1_2) {\r
522                 if (i == length) {\r
523                     matchlen[0] = 1;\r
524                     return i;\r
525                 }\r
526                 return i + 1;\r
527             }\r
528             return (i == length) ? -1 : i + 1;\r
529         }\r
530 \r
531         /* Punt to j.l.s.indexOf; return target length if seperator is\r
532          * not found.\r
533          */\r
534         if (ip[0] >= length)\r
535             return length;\r
536 \r
537         i = target.indexOf(separator, ip[0]);\r
538 \r
539         return (i != -1) ? i : length;\r
540     }\r
541 \r
542     /*\r
543      * See ECMA 15.5.4.8.  Modified to match JS 1.2 - optionally takes\r
544      * a limit argument and accepts a regular expression as the split\r
545      * argument.\r
546      */\r
547     private static Object jsFunction_split(Context cx, Scriptable scope,\r
548                                            String target, Object[] args)\r
549     {\r
550         // create an empty Array to return;\r
551         Scriptable top = getTopLevelScope(scope);\r
552         Scriptable result = ScriptRuntime.newObject(cx, top, "Array", null);\r
553 \r
554         // return an array consisting of the target if no separator given\r
555         // don't check against undefined, because we want\r
556         // 'fooundefinedbar'.split(void 0) to split to ['foo', 'bar']\r
557         if (args.length < 1) {\r
558             result.put(0, result, target);\r
559             return result;\r
560         }\r
561 \r
562         // Use the second argument as the split limit, if given.\r
563         boolean limited = (args.length > 1) && (args[1] != Undefined.instance);\r
564         long limit = 0;  // Initialize to avoid warning.\r
565         if (limited) {\r
566             /* Clamp limit between 0 and 1 + string length. */\r
567             limit = ScriptRuntime.toUint32(args[1]);\r
568             if (limit > target.length())\r
569                 limit = 1 + target.length();\r
570         }\r
571 \r
572         String separator = null;\r
573         int[] matchlen = { 0 };\r
574         Object re = null;\r
575         RegExpProxy reProxy = cx.getRegExpProxy();\r
576         if (reProxy != null && reProxy.isRegExp(args[0])) {\r
577             re = args[0];\r
578         } else {\r
579             separator = ScriptRuntime.toString(args[0]);\r
580             matchlen[0] = separator.length();\r
581         }\r
582 \r
583         // split target with separator or re\r
584         int[] ip = { 0 };\r
585         int match;\r
586         int len = 0;\r
587         boolean[] matched = { false };\r
588         String[][] parens = { null };\r
589         while ((match = find_split(scope, target, separator, re, ip,\r
590                                    matchlen, matched, parens)) >= 0)\r
591         {\r
592             if ((limited && len >= limit) || (match > target.length()))\r
593                 break;\r
594 \r
595             String substr;\r
596             if (target.length() == 0)\r
597                 substr = target;\r
598             else\r
599                 substr = target.substring(ip[0], match);\r
600 \r
601             result.put(len, result, substr);\r
602             len++;\r
603         /*\r
604          * Imitate perl's feature of including parenthesized substrings\r
605          * that matched part of the delimiter in the new array, after the\r
606          * split substring that was delimited.\r
607          */\r
608             if (re != null && matched[0] == true) {\r
609                 int size = parens[0].length;\r
610                 for (int num = 0; num < size; num++) {\r
611                     if (limited && len >= limit)\r
612                         break;\r
613                     result.put(len, result, parens[0][num]);\r
614                     len++;\r
615                 }\r
616                 matched[0] = false;\r
617             }\r
618             ip[0] = match + matchlen[0];\r
619 \r
620             if (cx.getLanguageVersion() < Context.VERSION_1_3\r
621                 && cx.getLanguageVersion() != Context.VERSION_DEFAULT)\r
622             {\r
623         /*\r
624          * Deviate from ECMA to imitate Perl, which omits a final\r
625          * split unless a limit argument is given and big enough.\r
626          */\r
627                 if (!limited && ip[0] == target.length())\r
628                     break;\r
629             }\r
630         }\r
631         return result;\r
632     }\r
633 \r
634     /*\r
635      * See ECMA 15.5.4.15\r
636      */\r
637     private static String jsFunction_substring(Context cx, String target,\r
638                                                Object[] args)\r
639     {\r
640         int length = target.length();\r
641         double start = ScriptRuntime.toInteger(args, 0);\r
642         double end;\r
643 \r
644         if (start < 0)\r
645             start = 0;\r
646         else if (start > length)\r
647             start = length;\r
648 \r
649         if (args.length <= 1 || args[1] == Undefined.instance) {\r
650             end = length;\r
651         } else {\r
652             end = ScriptRuntime.toInteger(args[1]);\r
653             if (end < 0)\r
654                 end = 0;\r
655             else if (end > length)\r
656                 end = length;\r
657 \r
658             // swap if end < start\r
659             if (end < start) {\r
660                 if (cx.getLanguageVersion() != Context.VERSION_1_2) {\r
661                     double temp = start;\r
662                     start = end;\r
663                     end = temp;\r
664                 } else {\r
665                     // Emulate old JDK1.0 java.lang.String.substring()\r
666                     end = start;\r
667                 }\r
668             }\r
669         }\r
670         return target.substring((int)start, (int)end);\r
671     }\r
672 \r
673     /*\r
674      *\r
675      * See ECMA 15.5.4.[11,12]\r
676      */\r
677     private static String jsFunction_toLowerCase(String target) {\r
678         return target.toLowerCase();\r
679     }\r
680 \r
681     private static String jsFunction_toUpperCase(String target) {\r
682         return target.toUpperCase();\r
683     }\r
684 \r
685     public double jsGet_length() {\r
686         return (double) string.length();\r
687     }\r
688 \r
689     /*\r
690      * Non-ECMA methods.\r
691      */\r
692     private static String jsFunction_substr(String target, Object[] args) {\r
693         if (args.length < 1)\r
694             return target;\r
695 \r
696         double begin = ScriptRuntime.toInteger(args[0]);\r
697         double end;\r
698         int length = target.length();\r
699 \r
700         if (begin < 0) {\r
701             begin += length;\r
702             if (begin < 0)\r
703                 begin = 0;\r
704         } else if (begin > length) {\r
705             begin = length;\r
706         }\r
707 \r
708         if (args.length == 1) {\r
709             end = length;\r
710         } else {\r
711             end = ScriptRuntime.toInteger(args[1]);\r
712             if (end < 0)\r
713                 end = 0;\r
714             end += begin;\r
715             if (end > length)\r
716                 end = length;\r
717         }\r
718 \r
719         return target.substring((int)begin, (int)end);\r
720     }\r
721 \r
722     /*\r
723      * Python-esque sequence operations.\r
724      */\r
725     private static String jsFunction_concat(String target, Object[] args) {\r
726         int N = args.length;\r
727         if (N == 0) { return target; }\r
728 \r
729         StringBuffer result = new StringBuffer();\r
730         result.append(target);\r
731 \r
732         for (int i = 0; i < N; i++)\r
733             result.append(ScriptRuntime.toString(args[i]));\r
734 \r
735         return result.toString();\r
736     }\r
737 \r
738     private static String jsFunction_slice(String target, Object[] args) {\r
739         if (args.length != 0) {\r
740             double begin = ScriptRuntime.toInteger(args[0]);\r
741             double end;\r
742             int length = target.length();\r
743             if (begin < 0) {\r
744                 begin += length;\r
745                 if (begin < 0)\r
746                     begin = 0;\r
747             } else if (begin > length) {\r
748                 begin = length;\r
749             }\r
750 \r
751             if (args.length == 1) {\r
752                 end = length;\r
753             } else {\r
754                 end = ScriptRuntime.toInteger(args[1]);\r
755                 if (end < 0) {\r
756                     end += length;\r
757                     if (end < 0)\r
758                         end = 0;\r
759                 } else if (end > length) {\r
760                     end = length;\r
761                 }\r
762                 if (end < begin)\r
763                     end = begin;\r
764             }\r
765             return target.substring((int)begin, (int)end);\r
766         }\r
767         return target;\r
768     }\r
769 \r
770     private static boolean jsFunction_equals(String target, String strOther) {\r
771         return target.equals(strOther);\r
772     }\r
773 \r
774 \r
775     private static boolean jsFunction_equalsIgnoreCase(String target,\r
776                                                        String strOther)\r
777     {\r
778         return target.equalsIgnoreCase(strOther);\r
779     }\r
780 \r
781     protected int maxInstanceId() { return MAX_INSTANCE_ID; }\r
782 \r
783     protected String getIdName(int id) {\r
784         if (id == Id_length) { return "length"; }\r
785         \r
786         if (prototypeFlag) {\r
787             switch (id) {\r
788                 case ConstructorId_fromCharCode: return "fromCharCode";\r
789 \r
790                 case Id_constructor:             return "constructor";\r
791                 case Id_toString:                return "toString";\r
792                 case Id_valueOf:                 return "valueOf";\r
793                 case Id_charAt:                  return "charAt";\r
794                 case Id_charCodeAt:              return "charCodeAt";\r
795                 case Id_indexOf:                 return "indexOf";\r
796                 case Id_lastIndexOf:             return "lastIndexOf";\r
797                 case Id_split:                   return "split";\r
798                 case Id_substring:               return "substring";\r
799                 case Id_toLowerCase:             return "toLowerCase";\r
800                 case Id_toUpperCase:             return "toUpperCase";\r
801                 case Id_substr:                  return "substr";\r
802                 case Id_concat:                  return "concat";\r
803                 case Id_slice:                   return "slice";\r
804                 case Id_bold:                    return "bold";\r
805                 case Id_italics:                 return "italics";\r
806                 case Id_fixed:                   return "fixed";\r
807                 case Id_strike:                  return "strike";\r
808                 case Id_small:                   return "small";\r
809                 case Id_big:                     return "big";\r
810                 case Id_blink:                   return "blink";\r
811                 case Id_sup:                     return "sup";\r
812                 case Id_sub:                     return "sub";\r
813                 case Id_fontsize:                return "fontsize";\r
814                 case Id_fontcolor:               return "fontcolor";\r
815                 case Id_link:                    return "link";\r
816                 case Id_anchor:                  return "anchor";\r
817                 case Id_equals:                  return "equals";\r
818                 case Id_equalsIgnoreCase:        return "equalsIgnoreCase";\r
819                 case Id_match:                   return "match";\r
820                 case Id_search:                  return "search";\r
821                 case Id_replace:                 return "replace";\r
822             }\r
823         }\r
824         return null;\r
825     }\r
826 \r
827     private static final int\r
828         ConstructorId_fromCharCode   = -1,\r
829         Id_length                    =  1,\r
830         MAX_INSTANCE_ID              =  1;\r
831         \r
832 \r
833     protected int mapNameToId(String s) {\r
834         if (s.equals("length")) { return Id_length; }\r
835         else if (prototypeFlag) { \r
836             return toPrototypeId(s); \r
837         }\r
838         return 0;\r
839     }\r
840 \r
841 // #string_id_map#\r
842 \r
843     private static int toPrototypeId(String s) {\r
844         int id;\r
845 // #generated# Last update: 2001-04-23 12:50:07 GMT+02:00\r
846         L0: { id = 0; String X = null; int c;\r
847             L: switch (s.length()) {\r
848             case 3: c=s.charAt(2);\r
849                 if (c=='b') { if (s.charAt(0)=='s' && s.charAt(1)=='u') {id=Id_sub; break L0;} }\r
850                 else if (c=='g') { if (s.charAt(0)=='b' && s.charAt(1)=='i') {id=Id_big; break L0;} }\r
851                 else if (c=='p') { if (s.charAt(0)=='s' && s.charAt(1)=='u') {id=Id_sup; break L0;} }\r
852                 break L;\r
853             case 4: c=s.charAt(0);\r
854                 if (c=='b') { X="bold";id=Id_bold; }\r
855                 else if (c=='l') { X="link";id=Id_link; }\r
856                 break L;\r
857             case 5: switch (s.charAt(4)) {\r
858                 case 'd': X="fixed";id=Id_fixed; break L;\r
859                 case 'e': X="slice";id=Id_slice; break L;\r
860                 case 'h': X="match";id=Id_match; break L;\r
861                 case 'k': X="blink";id=Id_blink; break L;\r
862                 case 'l': X="small";id=Id_small; break L;\r
863                 case 't': X="split";id=Id_split; break L;\r
864                 } break L;\r
865             case 6: switch (s.charAt(1)) {\r
866                 case 'e': c=s.charAt(0);\r
867                     if (c=='l') { X="length";id=Id_length; }\r
868                     else if (c=='s') { X="search";id=Id_search; }\r
869                     break L;\r
870                 case 'h': X="charAt";id=Id_charAt; break L;\r
871                 case 'n': X="anchor";id=Id_anchor; break L;\r
872                 case 'o': X="concat";id=Id_concat; break L;\r
873                 case 'q': X="equals";id=Id_equals; break L;\r
874                 case 't': X="strike";id=Id_strike; break L;\r
875                 case 'u': X="substr";id=Id_substr; break L;\r
876                 } break L;\r
877             case 7: switch (s.charAt(1)) {\r
878                 case 'a': X="valueOf";id=Id_valueOf; break L;\r
879                 case 'e': X="replace";id=Id_replace; break L;\r
880                 case 'n': X="indexOf";id=Id_indexOf; break L;\r
881                 case 't': X="italics";id=Id_italics; break L;\r
882                 } break L;\r
883             case 8: c=s.charAt(0);\r
884                 if (c=='f') { X="fontsize";id=Id_fontsize; }\r
885                 else if (c=='t') { X="toString";id=Id_toString; }\r
886                 break L;\r
887             case 9: c=s.charAt(0);\r
888                 if (c=='f') { X="fontcolor";id=Id_fontcolor; }\r
889                 else if (c=='s') { X="substring";id=Id_substring; }\r
890                 break L;\r
891             case 10: X="charCodeAt";id=Id_charCodeAt; break L;\r
892             case 11: switch (s.charAt(2)) {\r
893                 case 'L': X="toLowerCase";id=Id_toLowerCase; break L;\r
894                 case 'U': X="toUpperCase";id=Id_toUpperCase; break L;\r
895                 case 'n': X="constructor";id=Id_constructor; break L;\r
896                 case 's': X="lastIndexOf";id=Id_lastIndexOf; break L;\r
897                 } break L;\r
898             case 16: X="equalsIgnoreCase";id=Id_equalsIgnoreCase; break L;\r
899             }\r
900             if (X!=null && X!=s && !X.equals(s)) id = 0;\r
901         }\r
902 // #/generated#\r
903         return id;\r
904     }\r
905 \r
906     private static final int\r
907         Id_constructor               = MAX_INSTANCE_ID + 1,\r
908         Id_toString                  = MAX_INSTANCE_ID + 2,\r
909         Id_valueOf                   = MAX_INSTANCE_ID + 3,\r
910         Id_charAt                    = MAX_INSTANCE_ID + 4,\r
911         Id_charCodeAt                = MAX_INSTANCE_ID + 5,\r
912         Id_indexOf                   = MAX_INSTANCE_ID + 6,\r
913         Id_lastIndexOf               = MAX_INSTANCE_ID + 7,\r
914         Id_split                     = MAX_INSTANCE_ID + 8,\r
915         Id_substring                 = MAX_INSTANCE_ID + 9,\r
916         Id_toLowerCase               = MAX_INSTANCE_ID + 10,\r
917         Id_toUpperCase               = MAX_INSTANCE_ID + 11,\r
918         Id_substr                    = MAX_INSTANCE_ID + 12,\r
919         Id_concat                    = MAX_INSTANCE_ID + 13,\r
920         Id_slice                     = MAX_INSTANCE_ID + 14,\r
921         Id_bold                      = MAX_INSTANCE_ID + 15,\r
922         Id_italics                   = MAX_INSTANCE_ID + 16,\r
923         Id_fixed                     = MAX_INSTANCE_ID + 17,\r
924         Id_strike                    = MAX_INSTANCE_ID + 18,\r
925         Id_small                     = MAX_INSTANCE_ID + 19,\r
926         Id_big                       = MAX_INSTANCE_ID + 20,\r
927         Id_blink                     = MAX_INSTANCE_ID + 21,\r
928         Id_sup                       = MAX_INSTANCE_ID + 22,\r
929         Id_sub                       = MAX_INSTANCE_ID + 23,\r
930         Id_fontsize                  = MAX_INSTANCE_ID + 24,\r
931         Id_fontcolor                 = MAX_INSTANCE_ID + 25,\r
932         Id_link                      = MAX_INSTANCE_ID + 26,\r
933         Id_anchor                    = MAX_INSTANCE_ID + 27,\r
934         Id_equals                    = MAX_INSTANCE_ID + 28,\r
935         Id_equalsIgnoreCase          = MAX_INSTANCE_ID + 29,\r
936         Id_match                     = MAX_INSTANCE_ID + 30,\r
937         Id_search                    = MAX_INSTANCE_ID + 31,\r
938         Id_replace                   = MAX_INSTANCE_ID + 32,\r
939 \r
940         MAX_PROTOTYPE_ID             = MAX_INSTANCE_ID + 32;\r
941 \r
942 // #/string_id_map#\r
943 \r
944     private static final String defaultValue = "";\r
945 \r
946     private String string;\r
947     \r
948     private boolean prototypeFlag;\r
949 }\r
950 \r