r,a=brendan@mozilla.org. Adding missing ECMA3 compliance toLocaleXXX

functions to built-in Array, Date and Object object prototypes.
This commit is contained in:
rogerl%netscape.com 2000-08-09 21:46:03 +00:00
parent 9b6fafc3d8
commit 9d79d55a1b
10 changed files with 283 additions and 107 deletions

View File

@ -3169,6 +3169,20 @@ JS_ClearRegExpRoots(JSContext *cx)
/************************************************************************/
JS_PUBLIC_API(void)
JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
{
cx->localeCallbacks = callbacks;
}
JS_PUBLIC_API(JSLocaleCallbacks *)
JS_GetLocaleCallbacks(JSContext *cx)
{
return cx->localeCallbacks;
}
/************************************************************************/
JS_PUBLIC_API(JSBool)
JS_IsExceptionPending(JSContext *cx)
{

View File

@ -1141,6 +1141,31 @@ JS_CompareStrings(JSString *str1, JSString *str2);
/************************************************************************/
/*
* Locale specific string conversion callback.
*/
struct JSLocaleCallbacks {
JSLocaleToUpperCase localeToUpperCase;
JSLocaleToLowerCase localeToLowerCase;
JSLocaleCompare localeCompare;
};
/*
* Establish locale callbacks. The pointer must persist as long as the JSContext.
* Setting to NULL resorts to default behaviour.
*/
extern JS_PUBLIC_API(void)
JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks);
/* Return the address of the current locale callbacks struct. May be NULL. */
extern JS_PUBLIC_API(JSLocaleCallbacks *)
JS_GetLocaleCallbacks(JSContext *cx);
/************************************************************************/
/*
* Error reporting.
*/

View File

@ -311,7 +311,7 @@ JSClass js_ArrayClass = {
static JSBool
array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
jsval *rval)
jsval *rval, JSBool localeString)
{
JSBool ok;
jsval v;
@ -321,6 +321,7 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
const jschar *sepstr;
JSString *str;
JSHashEntry *he;
JSObject *obj2;
ok = js_GetLengthProperty(cx, obj, &length);
if (!ok)
@ -383,9 +384,18 @@ array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
if (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v)) {
str = cx->runtime->emptyString;
} else {
str = (literalize ? js_ValueToSource : js_ValueToString)(cx, v);
} else {
if (localeString) {
if (!js_ValueToObject(cx, v, &obj2))
goto doneBad;
if (!js_TryMethod(cx, obj2, cx->runtime->atomState.toLocaleStringAtom, 0, NULL, &v))
goto doneBad;
str = JSVAL_TO_STRING(v);
}
else
str = (literalize ? js_ValueToSource : js_ValueToString)(cx, v);
if (!str) {
doneBad:
ok = JS_FALSE;
goto done;
}
@ -459,7 +469,7 @@ static JSBool
array_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
return array_join_sub(cx, obj, &comma_space, JS_TRUE, rval);
return array_join_sub(cx, obj, &comma_space, JS_TRUE, rval, JS_FALSE);
}
#endif
@ -475,7 +485,18 @@ array_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
*/
literalize = (cx->version == JSVERSION_1_2);
return array_join_sub(cx, obj, literalize ? &comma_space : &comma,
literalize, rval);
literalize, rval, JS_FALSE);
}
static JSBool
array_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
/*
* Passing comma_space here as the separator. Need a way to get a
* locale specific version.
*/
return array_join_sub(cx, obj, &comma_space, JS_FALSE, rval, JS_TRUE);
}
static JSBool
@ -484,12 +505,12 @@ array_join(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSString *str;
if (argc == 0)
return array_join_sub(cx, obj, &comma, JS_FALSE, rval);
return array_join_sub(cx, obj, &comma, JS_FALSE, rval, JS_FALSE);
str = js_ValueToString(cx, argv[0]);
if (!str)
return JS_FALSE;
argv[0] = STRING_TO_JSVAL(str);
return array_join_sub(cx, obj, str, JS_FALSE, rval);
return array_join_sub(cx, obj, str, JS_FALSE, rval, JS_FALSE);
}
#if !JS_HAS_MORE_PERL_FUN
@ -1282,27 +1303,28 @@ array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
static JSFunctionSpec array_methods[] = {
#if JS_HAS_TOSOURCE
{js_toSource_str, array_toSource, 0,0,0},
{js_toSource_str, array_toSource, 0,0,0},
#endif
{js_toString_str, array_toString, 0,0,0},
{js_toString_str, array_toString, 0,0,0},
{js_toLocaleString_str, array_toLocaleString, 0,0,0},
/* Perl-ish methods. */
{"join", array_join, 1,0,0},
{"reverse", array_reverse, 0,0,0},
{"sort", array_sort, 1,0,0},
{"join", array_join, 1,0,0},
{"reverse", array_reverse, 0,0,0},
{"sort", array_sort, 1,0,0},
#ifdef NOTYET
{"pack", array_pack, 1,0,0},
{"pack", array_pack, 1,0,0},
#endif
{"push", array_push, 1,0,0},
{"pop", array_pop, 0,0,0},
{"shift", array_shift, 0,0,0},
{"unshift", array_unshift, 1,0,0},
{"splice", array_splice, 1,0,0},
{"push", array_push, 1,0,0},
{"pop", array_pop, 0,0,0},
{"shift", array_shift, 0,0,0},
{"unshift", array_unshift, 1,0,0},
{"splice", array_splice, 1,0,0},
/* Python-esque sequence methods. */
#if JS_HAS_SEQUENCE_OPS
{"concat", array_concat, 0,0,0},
{"slice", array_slice, 0,0,0},
{"concat", array_concat, 0,0,0},
{"slice", array_slice, 0,0,0},
#endif
{0,0,0,0,0}

View File

@ -261,6 +261,7 @@ js_InitAtomState(JSContext *cx, JSAtomState *state)
FROB(setAtom, js_set_str);
FROB(toSourceAtom, js_toSource_str);
FROB(toStringAtom, js_toString_str);
FROB(toLocaleStringAtom, js_toLocaleString_str);
FROB(valueOfAtom, js_valueOf_str);
FROB(evalAtom, js_eval_str);

View File

@ -165,6 +165,7 @@ struct JSAtomState {
JSAtom *setAtom;
JSAtom *toSourceAtom;
JSAtom *toStringAtom;
JSAtom *toLocaleStringAtom;
JSAtom *valueOfAtom;
JSAtom *evalAtom;

View File

@ -243,6 +243,10 @@ struct JSContext {
/* Delay JS_SetVersion scanner effects until they're needed. */
JSVersion scannerVersion;
/* Locale specific callbacks for string conversion. */
JSLocaleCallbacks *localeCallbacks;
};
/* Slightly more readable macros, also to hide bitset implementation detail. */

View File

@ -1554,8 +1554,8 @@ date_format(JSContext *cx, jsdouble date, jsval *rval)
}
static JSBool
date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval, char *format)
{
char buf[100];
JSString *str;
@ -1571,17 +1571,8 @@ date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
jsdouble local = LocalTime(*date);
new_explode(local, &split, JS_FALSE);
/* let PRMJTime format it. Use '%#c' for windows, because '%c' is
* backward-compatible and non-y2k with msvc; '%#c' requests that a
* full year be used in the result string.
*/
result_len = PRMJ_FormatTime(buf, sizeof buf,
#if defined(_WIN32) && !defined(__MWERKS__)
"%#c",
#else
"%c",
#endif
&split);
/* let PRMJTime format it. */
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
/* If it failed, default to toString. */
if (result_len == 0)
@ -1595,6 +1586,47 @@ date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
return JS_TRUE;
}
static JSBool
date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
{
/* Use '%#c' for windows, because '%c' is
* backward-compatible and non-y2k with msvc; '%#c' requests that a
* full year be used in the result string.
*/
return date_toLocaleHelper(cx, obj, argc, argv, rval,
#if defined(_WIN32) && !defined(__MWERKS__)
"%#c"
#else
"%c"
#endif
);
}
static JSBool
date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
{
/* Use '%#x' for windows, because '%x' is
* backward-compatible and non-y2k with msvc; '%#x' requests that a
* full year be used in the result string.
*/
return date_toLocaleHelper(cx, obj, argc, argv, rval,
#if defined(_WIN32) && !defined(__MWERKS__)
"%#x"
#else
"%x"
#endif
);
}
static JSBool
date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
{
return date_toLocaleHelper(cx, obj, argc, argv, rval, "%X");
}
#if JS_HAS_TOSOURCE
#include <string.h>
#include "jsdtoa.h"
@ -1686,49 +1718,51 @@ static JSFunctionSpec date_static_methods[] = {
};
static JSFunctionSpec date_methods[] = {
{"getTime", date_getTime, 0,0,0 },
{"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 },
{"getYear", date_getYear, 0,0,0 },
{"getFullYear", date_getFullYear, 0,0,0 },
{"getUTCFullYear", date_getUTCFullYear, 0,0,0 },
{"getMonth", date_getMonth, 0,0,0 },
{"getUTCMonth", date_getUTCMonth, 0,0,0 },
{"getDate", date_getDate, 0,0,0 },
{"getUTCDate", date_getUTCDate, 0,0,0 },
{"getDay", date_getDay, 0,0,0 },
{"getUTCDay", date_getUTCDay, 0,0,0 },
{"getHours", date_getHours, 0,0,0 },
{"getUTCHours", date_getUTCHours, 0,0,0 },
{"getMinutes", date_getMinutes, 0,0,0 },
{"getUTCMinutes", date_getUTCMinutes, 0,0,0 },
{"getSeconds", date_getUTCSeconds, 0,0,0 },
{"getUTCSeconds", date_getUTCSeconds, 0,0,0 },
{"getMilliseconds", date_getUTCMilliseconds,0,0,0 },
{"getUTCMilliseconds",date_getUTCMilliseconds,0,0,0 },
{"setTime", date_setTime, 1,0,0 },
{"setYear", date_setYear, 1,0,0 },
{"setFullYear", date_setFullYear, 3,0,0 },
{"setUTCFullYear", date_setUTCFullYear, 3,0,0 },
{"setMonth", date_setMonth, 2,0,0 },
{"setUTCMonth", date_setUTCMonth, 2,0,0 },
{"setDate", date_setDate, 1,0,0 },
{"setUTCDate", date_setUTCDate, 1,0,0 },
{"setHours", date_setHours, 4,0,0 },
{"setUTCHours", date_setUTCHours, 4,0,0 },
{"setMinutes", date_setMinutes, 3,0,0 },
{"setUTCMinutes", date_setUTCMinutes, 3,0,0 },
{"setSeconds", date_setSeconds, 2,0,0 },
{"setUTCSeconds", date_setUTCSeconds, 2,0,0 },
{"setMilliseconds", date_setMilliseconds, 1,0,0 },
{"setUTCMilliseconds",date_setUTCMilliseconds,1,0,0 },
{"toGMTString", date_toGMTString, 0,0,0 },
{"toUTCString", date_toGMTString, 0,0,0 },
{"toLocaleString", date_toLocaleString, 0,0,0 },
{"getTime", date_getTime, 0,0,0 },
{"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 },
{"getYear", date_getYear, 0,0,0 },
{"getFullYear", date_getFullYear, 0,0,0 },
{"getUTCFullYear", date_getUTCFullYear, 0,0,0 },
{"getMonth", date_getMonth, 0,0,0 },
{"getUTCMonth", date_getUTCMonth, 0,0,0 },
{"getDate", date_getDate, 0,0,0 },
{"getUTCDate", date_getUTCDate, 0,0,0 },
{"getDay", date_getDay, 0,0,0 },
{"getUTCDay", date_getUTCDay, 0,0,0 },
{"getHours", date_getHours, 0,0,0 },
{"getUTCHours", date_getUTCHours, 0,0,0 },
{"getMinutes", date_getMinutes, 0,0,0 },
{"getUTCMinutes", date_getUTCMinutes, 0,0,0 },
{"getSeconds", date_getUTCSeconds, 0,0,0 },
{"getUTCSeconds", date_getUTCSeconds, 0,0,0 },
{"getMilliseconds", date_getUTCMilliseconds,0,0,0 },
{"getUTCMilliseconds", date_getUTCMilliseconds,0,0,0 },
{"setTime", date_setTime, 1,0,0 },
{"setYear", date_setYear, 1,0,0 },
{"setFullYear", date_setFullYear, 3,0,0 },
{"setUTCFullYear", date_setUTCFullYear, 3,0,0 },
{"setMonth", date_setMonth, 2,0,0 },
{"setUTCMonth", date_setUTCMonth, 2,0,0 },
{"setDate", date_setDate, 1,0,0 },
{"setUTCDate", date_setUTCDate, 1,0,0 },
{"setHours", date_setHours, 4,0,0 },
{"setUTCHours", date_setUTCHours, 4,0,0 },
{"setMinutes", date_setMinutes, 3,0,0 },
{"setUTCMinutes", date_setUTCMinutes, 3,0,0 },
{"setSeconds", date_setSeconds, 2,0,0 },
{"setUTCSeconds", date_setUTCSeconds, 2,0,0 },
{"setMilliseconds", date_setMilliseconds, 1,0,0 },
{"setUTCMilliseconds", date_setUTCMilliseconds,1,0,0 },
{"toGMTString", date_toGMTString, 0,0,0 },
{"toUTCString", date_toGMTString, 0,0,0 },
{js_toLocaleString_str, date_toLocaleString, 0,0,0 },
{"toLocaleDateString", date_toLocaleDateString,0,0,0 },
{"toLocaleTimeString", date_toLocaleTimeString,0,0,0 },
#if JS_HAS_TOSOURCE
{js_toSource_str, date_toSource, 0,0,0 },
{js_toSource_str, date_toSource, 0,0,0 },
#endif
{js_toString_str, date_toString, 0,0,0 },
{js_valueOf_str, date_valueOf, 0,0,0 },
{js_toString_str, date_toString, 0,0,0 },
{js_valueOf_str, date_valueOf, 0,0,0 },
{0,0,0,0,0}
};

View File

@ -1100,6 +1100,7 @@ static JSFunctionSpec object_methods[] = {
{js_toSource_str, js_obj_toSource, 0, 0, OBJ_TOSTRING_EXTRA},
#endif
{js_toString_str, js_obj_toString, 0, 0, OBJ_TOSTRING_EXTRA},
{js_toLocaleString_str, js_obj_toString, 0, 0, OBJ_TOSTRING_EXTRA},
{js_valueOf_str, obj_valueOf, 0,0,0},
{js_eval_str, obj_eval, 1,0,0},
#if JS_HAS_OBJ_WATCHPOINT

View File

@ -114,6 +114,7 @@ typedef struct JSScript JSScript;
typedef struct JSString JSString;
typedef struct JSXDRState JSXDRState;
typedef struct JSExceptionState JSExceptionState;
typedef struct JSLocaleCallbacks JSLocaleCallbacks;
#ifndef CRT_CALL
#ifdef XP_OS2_VACPP
@ -267,6 +268,17 @@ typedef JSBool
JSBool fromJS, jsval **vpp, va_list *app);
#endif
typedef JSBool
(* CRT_CALL JSLocaleToUpperCase)(JSContext *cx, JSString *src, jsval *rval);
typedef JSBool
(* CRT_CALL JSLocaleToLowerCase)(JSContext *cx, JSString *src, jsval *rval);
typedef JSBool
(* CRT_CALL JSLocaleCompare)(JSContext *cx, JSString *src1, JSString *src2, jsval *rval);
JS_END_EXTERN_C
#endif /* jspubtd_h___ */

View File

@ -551,6 +551,24 @@ str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_TRUE;
}
static JSBool
str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSString *str;
/*
* Forcibly ignore the first (or any) argument and return toLowerCase(),
* ECMA has reserved that argument, presumbaly for defining the locale.
*/
if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
if (!str)
return JS_FALSE;
return cx->localeCallbacks->localeToLowerCase(cx, str, rval);
}
return str_toLowerCase(cx, obj, 0, argv, rval);
}
static JSBool
str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
@ -579,6 +597,47 @@ str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_TRUE;
}
static JSBool
str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSString *str;
/*
* Forcibly ignore the first (or any) argument and return toLowerCase(),
* ECMA has reserved that argument, presumbaly for defining the locale.
*/
if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
if (!str)
return JS_FALSE;
return cx->localeCallbacks->localeToUpperCase(cx, str, rval);
}
return str_toUpperCase(cx, obj, 0, argv, rval);
}
static JSBool
str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSString *str, *thatStr;
str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
if (!str)
return JS_FALSE;
argv[-1] = STRING_TO_JSVAL(str);
if (argc == 0)
*rval = JSVAL_ZERO;
else {
thatStr = js_ValueToString(cx, argv[0]);
if (!thatStr)
return JS_FALSE;
if (cx->localeCallbacks && cx->localeCallbacks->localeCompare)
return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval);
*rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
}
return JS_TRUE;
}
static JSBool
str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
@ -2014,51 +2073,54 @@ str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
static JSFunctionSpec string_methods[] = {
#if JS_HAS_TOSOURCE
{"quote", str_quote, 0,0,0},
{js_toSource_str, str_toSource, 0,0,0},
{"quote", str_quote, 0,0,0},
{js_toSource_str, str_toSource, 0,0,0},
#endif
/* Java-like methods. */
{js_toString_str, str_toString, 0,0,0},
{js_valueOf_str, str_valueOf, 0,0,0},
{"substring", str_substring, 2,0,0},
{"toLowerCase", str_toLowerCase, 0,0,0},
{"toUpperCase", str_toUpperCase, 0,0,0},
{"charAt", str_charAt, 1,0,0},
{"charCodeAt", str_charCodeAt, 1,0,0},
{"indexOf", str_indexOf, 2,0,0},
{"lastIndexOf", str_lastIndexOf, 2,0,0},
{js_toString_str, str_toString, 0,0,0},
{js_valueOf_str, str_valueOf, 0,0,0},
{"substring", str_substring, 2,0,0},
{"toLowerCase", str_toLowerCase, 0,0,0},
{"toUpperCase", str_toUpperCase, 0,0,0},
{"charAt", str_charAt, 1,0,0},
{"charCodeAt", str_charCodeAt, 1,0,0},
{"indexOf", str_indexOf, 2,0,0},
{"lastIndexOf", str_lastIndexOf, 2,0,0},
{"toLocaleLowerCase", str_toLocaleLowerCase, 0,0,0},
{"toLocaleUpperCase", str_toLocaleUpperCase, 0,0,0},
{"localeCompare", str_localeCompare, 1,0,0},
/* Perl-ish methods (search is actually Python-esque). */
{"match", str_match, 1,0,0},
{"search", str_search, 1,0,0},
{"replace", str_replace, 2,0,0},
{"split", str_split, 1,0,0},
{"substr", str_substr, 2,0,0},
{"match", str_match, 1,0,0},
{"search", str_search, 1,0,0},
{"replace", str_replace, 2,0,0},
{"split", str_split, 1,0,0},
{"substr", str_substr, 2,0,0},
#ifdef NOTYET
{"unpack", str_unpack, 1,0,0},
{"unpack", str_unpack, 1,0,0},
#endif
/* Python-esque sequence methods. */
#if JS_HAS_SEQUENCE_OPS
{"concat", str_concat, 0,0,0},
{"slice", str_slice, 0,0,0},
{"concat", str_concat, 0,0,0},
{"slice", str_slice, 0,0,0},
#endif
/* HTML string methods. */
{"bold", str_bold, 0,0,0},
{"italics", str_italics, 0,0,0},
{"fixed", str_fixed, 0,0,0},
{"fontsize", str_fontsize, 1,0,0},
{"fontcolor", str_fontcolor, 1,0,0},
{"link", str_link, 1,0,0},
{"anchor", str_anchor, 1,0,0},
{"strike", str_strike, 0,0,0},
{"small", str_small, 0,0,0},
{"big", str_big, 0,0,0},
{"blink", str_blink, 0,0,0},
{"sup", str_sup, 0,0,0},
{"sub", str_sub, 0,0,0},
{"bold", str_bold, 0,0,0},
{"italics", str_italics, 0,0,0},
{"fixed", str_fixed, 0,0,0},
{"fontsize", str_fontsize, 1,0,0},
{"fontcolor", str_fontcolor, 1,0,0},
{"link", str_link, 1,0,0},
{"anchor", str_anchor, 1,0,0},
{"strike", str_strike, 0,0,0},
{"small", str_small, 0,0,0},
{"big", str_big, 0,0,0},
{"blink", str_blink, 0,0,0},
{"sup", str_sup, 0,0,0},
{"sub", str_sub, 0,0,0},
{0,0,0,0,0}
};