michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jsstr_h michael@0: #define jsstr_h michael@0: michael@0: #include "mozilla/HashFunctions.h" michael@0: #include "mozilla/PodOperations.h" michael@0: michael@0: #include "jsutil.h" michael@0: #include "NamespaceImports.h" michael@0: michael@0: #include "gc/Rooting.h" michael@0: #include "js/RootingAPI.h" michael@0: #include "vm/Unicode.h" michael@0: michael@0: class JSAutoByteString; michael@0: class JSFlatString; michael@0: class JSLinearString; michael@0: michael@0: namespace js { michael@0: michael@0: class StringBuffer; michael@0: michael@0: class MutatingRopeSegmentRange; michael@0: michael@0: template michael@0: extern JSString * michael@0: ConcatStrings(ThreadSafeContext *cx, michael@0: typename MaybeRooted::HandleType left, michael@0: typename MaybeRooted::HandleType right); michael@0: michael@0: // Return s advanced past any Unicode white space characters. michael@0: static inline const jschar * michael@0: SkipSpace(const jschar *s, const jschar *end) michael@0: { michael@0: JS_ASSERT(s <= end); michael@0: michael@0: while (s < end && unicode::IsSpace(*s)) michael@0: s++; michael@0: michael@0: return s; michael@0: } michael@0: michael@0: // Return less than, equal to, or greater than zero depending on whether michael@0: // s1 is less than, equal to, or greater than s2. michael@0: inline int32_t michael@0: CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2) michael@0: { michael@0: size_t n = Min(l1, l2); michael@0: for (size_t i = 0; i < n; i++) { michael@0: if (int32_t cmp = s1[i] - s2[i]) michael@0: return cmp; michael@0: } michael@0: michael@0: return (int32_t)(l1 - l2); michael@0: } michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern JSString * JS_FASTCALL michael@0: js_toLowerCase(JSContext *cx, JSString *str); michael@0: michael@0: extern JSString * JS_FASTCALL michael@0: js_toUpperCase(JSContext *cx, JSString *str); michael@0: michael@0: struct JSSubString { michael@0: size_t length; michael@0: const jschar *chars; michael@0: }; michael@0: michael@0: extern const jschar js_empty_ucstr[]; michael@0: extern const JSSubString js_EmptySubString; michael@0: michael@0: /* michael@0: * Shorthands for ASCII (7-bit) decimal and hex conversion. michael@0: * Manually inline isdigit for performance; MSVC doesn't do this for us. michael@0: */ michael@0: #define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9) michael@0: #define JS7_UNDEC(c) ((c) - '0') michael@0: #define JS7_ISHEX(c) ((c) < 128 && isxdigit(c)) michael@0: #define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a') michael@0: #define JS7_ISLET(c) ((c) < 128 && isalpha(c)) michael@0: michael@0: /* Initialize the String class, returning its prototype object. */ michael@0: extern JSObject * michael@0: js_InitStringClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: extern const char js_escape_str[]; michael@0: extern const char js_unescape_str[]; michael@0: extern const char js_uneval_str[]; michael@0: extern const char js_decodeURI_str[]; michael@0: extern const char js_encodeURI_str[]; michael@0: extern const char js_decodeURIComponent_str[]; michael@0: extern const char js_encodeURIComponent_str[]; michael@0: michael@0: /* GC-allocate a string descriptor for the given malloc-allocated chars. */ michael@0: template michael@0: extern JSFlatString * michael@0: js_NewString(js::ThreadSafeContext *cx, jschar *chars, size_t length); michael@0: michael@0: extern JSLinearString * michael@0: js_NewDependentString(JSContext *cx, JSString *base, size_t start, size_t length); michael@0: michael@0: /* Copy a counted string and GC-allocate a descriptor for it. */ michael@0: template michael@0: extern JSFlatString * michael@0: js_NewStringCopyN(js::ExclusiveContext *cx, const jschar *s, size_t n); michael@0: michael@0: template michael@0: extern JSFlatString * michael@0: js_NewStringCopyN(js::ThreadSafeContext *cx, const char *s, size_t n); michael@0: michael@0: /* Copy a C string and GC-allocate a descriptor for it. */ michael@0: template michael@0: extern JSFlatString * michael@0: js_NewStringCopyZ(js::ExclusiveContext *cx, const jschar *s); michael@0: michael@0: template michael@0: extern JSFlatString * michael@0: js_NewStringCopyZ(js::ThreadSafeContext *cx, const char *s); michael@0: michael@0: /* michael@0: * Convert a value to a printable C string. michael@0: */ michael@0: extern const char * michael@0: js_ValueToPrintable(JSContext *cx, const js::Value &, michael@0: JSAutoByteString *bytes, bool asSource = false); michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Convert a non-string value to a string, returning null after reporting an michael@0: * error, otherwise returning a new string reference. michael@0: */ michael@0: template michael@0: extern JSString * michael@0: ToStringSlow(ExclusiveContext *cx, typename MaybeRooted::HandleType arg); michael@0: michael@0: /* michael@0: * Convert the given value to a string. This method includes an inline michael@0: * fast-path for the case where the value is already a string; if the value is michael@0: * known not to be a string, use ToStringSlow instead. michael@0: */ michael@0: template michael@0: static MOZ_ALWAYS_INLINE JSString * michael@0: ToString(JSContext *cx, JS::HandleValue v) michael@0: { michael@0: if (v.isString()) michael@0: return v.toString(); michael@0: return ToStringSlow(cx, v); michael@0: } michael@0: michael@0: /* michael@0: * This function implements E-262-3 section 9.8, toString. Convert the given michael@0: * value to a string of jschars appended to the given buffer. On error, the michael@0: * passed buffer may have partial results appended. michael@0: */ michael@0: inline bool michael@0: ValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); michael@0: michael@0: /* michael@0: * Convert a value to its source expression, returning null after reporting michael@0: * an error, otherwise returning a new string reference. michael@0: */ michael@0: extern JSString * michael@0: ValueToSource(JSContext *cx, HandleValue v); michael@0: michael@0: /* michael@0: * Convert a JSString to its source expression; returns null after reporting an michael@0: * error, otherwise returns a new string reference. No Handle needed since the michael@0: * input is dead after the GC. michael@0: */ michael@0: extern JSString * michael@0: StringToSource(JSContext *cx, JSString *str); michael@0: michael@0: /* michael@0: * Test if strings are equal. The caller can call the function even if str1 michael@0: * or str2 are not GC-allocated things. michael@0: */ michael@0: extern bool michael@0: EqualStrings(JSContext *cx, JSString *str1, JSString *str2, bool *result); michael@0: michael@0: /* Use the infallible method instead! */ michael@0: extern bool michael@0: EqualStrings(JSContext *cx, JSLinearString *str1, JSLinearString *str2, bool *result) MOZ_DELETE; michael@0: michael@0: /* EqualStrings is infallible on linear strings. */ michael@0: extern bool michael@0: EqualStrings(JSLinearString *str1, JSLinearString *str2); michael@0: michael@0: /* michael@0: * Return less than, equal to, or greater than zero depending on whether michael@0: * str1 is less than, equal to, or greater than str2. michael@0: */ michael@0: extern bool michael@0: CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result); michael@0: michael@0: extern int32_t michael@0: CompareAtoms(JSAtom *atom1, JSAtom *atom2); michael@0: michael@0: /* michael@0: * Return true if the string matches the given sequence of ASCII bytes. michael@0: */ michael@0: extern bool michael@0: StringEqualsAscii(JSLinearString *str, const char *asciiBytes); michael@0: michael@0: /* Return true if the string contains a pattern anywhere inside it. */ michael@0: extern bool michael@0: StringHasPattern(const jschar *text, uint32_t textlen, michael@0: const jschar *pat, uint32_t patlen); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern size_t michael@0: js_strlen(const jschar *s); michael@0: michael@0: extern int32_t michael@0: js_strcmp(const jschar *lhs, const jschar *rhs); michael@0: michael@0: extern jschar * michael@0: js_strchr_limit(const jschar *s, jschar c, const jschar *limit); michael@0: michael@0: static MOZ_ALWAYS_INLINE void michael@0: js_strncpy(jschar *dst, const jschar *src, size_t nelem) michael@0: { michael@0: return mozilla::PodCopy(dst, src, nelem); michael@0: } michael@0: michael@0: extern jschar * michael@0: js_strdup(js::ThreadSafeContext *cx, const jschar *s); michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Inflate bytes in ASCII encoding to jschars. Return null on error, otherwise michael@0: * return the jschar that was malloc'ed. length is updated to the length of the michael@0: * new string (in jschars). A null char is appended, but it is not included in michael@0: * the length. michael@0: */ michael@0: extern jschar * michael@0: InflateString(ThreadSafeContext *cx, const char *bytes, size_t *length); michael@0: michael@0: /* michael@0: * Inflate bytes to JS chars in an existing buffer. 'dst' must be large michael@0: * enough for 'srclen' jschars. The buffer is NOT null-terminated. michael@0: */ michael@0: inline void michael@0: InflateStringToBuffer(const char *src, size_t srclen, jschar *dst) michael@0: { michael@0: for (size_t i = 0; i < srclen; i++) michael@0: dst[i] = (unsigned char) src[i]; michael@0: } michael@0: michael@0: /* michael@0: * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for michael@0: * 'length chars. The buffer is NOT null-terminated. The destination length michael@0: * must to be initialized with the buffer size and will contain on return the michael@0: * number of copied bytes. michael@0: */ michael@0: extern bool michael@0: DeflateStringToBuffer(JSContext *maybecx, const jschar *chars, michael@0: size_t charsLength, char *bytes, size_t *length); michael@0: michael@0: /* michael@0: * The String.prototype.replace fast-native entry point is exported for joined michael@0: * function optimization in js{interp,tracer}.cpp. michael@0: */ michael@0: extern bool michael@0: str_replace(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: extern bool michael@0: str_fromCharCode(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern bool michael@0: js_str_toString(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: extern bool michael@0: js_str_charAt(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: extern bool michael@0: js_str_charCodeAt(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: /* michael@0: * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at michael@0: * least 6 bytes long. Return the number of UTF-8 bytes of data written. michael@0: */ michael@0: extern int michael@0: js_OneUcs4ToUtf8Char(uint8_t *utf8Buffer, uint32_t ucs4Char); michael@0: michael@0: namespace js { michael@0: michael@0: extern size_t michael@0: PutEscapedStringImpl(char *buffer, size_t size, FILE *fp, JSLinearString *str, uint32_t quote); michael@0: michael@0: extern size_t michael@0: PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, const jschar *chars, michael@0: size_t length, uint32_t quote); michael@0: michael@0: /* michael@0: * Write str into buffer escaping any non-printable or non-ASCII character michael@0: * using \escapes for JS string literals. michael@0: * Guarantees that a NUL is at the end of the buffer unless size is 0. Returns michael@0: * the length of the written output, NOT including the NUL. Thus, a return michael@0: * value of size or more means that the output was truncated. If buffer michael@0: * is null, just returns the length of the output. If quote is not 0, it must michael@0: * be a single or double quote character that will quote the output. michael@0: */ michael@0: inline size_t michael@0: PutEscapedString(char *buffer, size_t size, JSLinearString *str, uint32_t quote) michael@0: { michael@0: size_t n = PutEscapedStringImpl(buffer, size, nullptr, str, quote); michael@0: michael@0: /* PutEscapedStringImpl can only fail with a file. */ michael@0: JS_ASSERT(n != size_t(-1)); michael@0: return n; michael@0: } michael@0: michael@0: inline size_t michael@0: PutEscapedString(char *buffer, size_t bufferSize, const jschar *chars, size_t length, uint32_t quote) michael@0: { michael@0: size_t n = PutEscapedStringImpl(buffer, bufferSize, nullptr, chars, length, quote); michael@0: michael@0: /* PutEscapedStringImpl can only fail with a file. */ michael@0: JS_ASSERT(n != size_t(-1)); michael@0: return n; michael@0: } michael@0: michael@0: /* michael@0: * Write str into file escaping any non-printable or non-ASCII character. michael@0: * If quote is not 0, it must be a single or double quote character that michael@0: * will quote the output. michael@0: */ michael@0: inline bool michael@0: FileEscapedString(FILE *fp, JSLinearString *str, uint32_t quote) michael@0: { michael@0: return PutEscapedStringImpl(nullptr, 0, fp, str, quote) != size_t(-1); michael@0: } michael@0: michael@0: bool michael@0: str_match(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: bool michael@0: str_search(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: bool michael@0: str_split(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: JSObject * michael@0: str_split_string(JSContext *cx, HandleTypeObject type, HandleString str, HandleString sep); michael@0: michael@0: bool michael@0: str_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp); michael@0: michael@0: bool michael@0: str_replace_regexp_raw(JSContext *cx, HandleString string, HandleObject regexp, michael@0: HandleString replacement, MutableHandleValue rval); michael@0: michael@0: bool michael@0: str_replace_string_raw(JSContext *cx, HandleString string, HandleString pattern, michael@0: HandleString replacement, MutableHandleValue rval); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern bool michael@0: js_String(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: #endif /* jsstr_h */