blob: 742d6340ee0a2bfe74d2f007f3b1b9195ca0add3 [file] [log] [blame]
/**
* This file is part of the DOM implementation for KDE.
*
* (C) 1999 Lars Knoll (knoll@kde.org)
* Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "PlatformString.h"
#include "CString.h"
#include "DeprecatedString.h"
#include "TextEncoding.h"
#include <kjs/identifier.h>
#include <wtf/Vector.h>
#include <stdarg.h>
using KJS::Identifier;
using KJS::UString;
namespace WebCore {
String::String(const UChar* str, unsigned len)
{
if (!str)
return;
if (len == 0)
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(str, len);
}
String::String(const UChar* str)
{
if (!str)
return;
int len = 0;
while (str[len] != UChar(0))
len++;
if (len == 0)
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(str, len);
}
String::String(const DeprecatedString& str)
{
if (str.isNull())
return;
if (str.isEmpty())
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(reinterpret_cast<const UChar*>(str.unicode()), str.length());
}
String::String(const char* str)
{
if (!str)
return;
int l = strlen(str);
if (l == 0)
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(str, l);
}
String::String(const char* str, unsigned length)
{
if (!str)
return;
if (length == 0)
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(str, length);
}
void String::append(const String &str)
{
if (str.m_impl) {
if (!m_impl) {
// ### FIXME!!!
m_impl = str.m_impl;
return;
}
m_impl = m_impl->copy();
m_impl->append(str.m_impl.get());
}
}
void String::append(char c)
{
if (!m_impl)
m_impl = new StringImpl(&c, 1);
else {
m_impl = m_impl->copy();
m_impl->append(c);
}
}
void String::append(UChar c)
{
if (!m_impl)
m_impl = new StringImpl(&c, 1);
else {
m_impl = m_impl->copy();
m_impl->append(c);
}
}
String operator+(const String& a, const String& b)
{
if (a.isEmpty())
return b.copy();
if (b.isEmpty())
return a.copy();
String c = a.copy();
c += b;
return c;
}
String operator+(const String& s, const char* cs)
{
return s + String(cs);
}
String operator+(const char* cs, const String& s)
{
return String(cs) + s;
}
void String::insert(const String& str, unsigned pos)
{
if (!m_impl)
m_impl = str.m_impl->copy();
else
m_impl->insert(str.m_impl.get(), pos);
}
void String::insert(const UChar* str, unsigned length, unsigned pos)
{
if (!m_impl)
m_impl = new StringImpl(str, length);
else
m_impl->insert(str, length, pos);
}
UChar String::operator[](unsigned i) const
{
if (!m_impl || i >= m_impl->length())
return 0;
return m_impl->characters()[i];
}
unsigned String::length() const
{
if (!m_impl)
return 0;
return m_impl->length();
}
void String::truncate(unsigned len)
{
if (m_impl)
m_impl->truncate(len);
}
void String::remove(unsigned pos, int len)
{
if (m_impl)
m_impl->remove(pos, len);
}
String String::substring(unsigned pos, unsigned len) const
{
if (!m_impl)
return String();
return m_impl->substring(pos, len);
}
String String::lower() const
{
if (!m_impl)
return String();
return m_impl->lower();
}
String String::upper() const
{
if (!m_impl)
return String();
return m_impl->upper();
}
String String::stripWhiteSpace() const
{
if (!m_impl)
return String();
return m_impl->stripWhiteSpace();
}
String String::simplifyWhiteSpace() const
{
if (!m_impl)
return String();
return m_impl->simplifyWhiteSpace();
}
String String::foldCase() const
{
if (!m_impl)
return String();
return m_impl->foldCase();
}
bool String::percentage(int& result) const
{
if (!m_impl || !m_impl->length())
return false;
if ((*m_impl)[m_impl->length() - 1] != '%')
return false;
result = DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(m_impl->characters()), m_impl->length() - 1).string().toInt();
return true;
}
const UChar* String::characters() const
{
if (!m_impl)
return 0;
return m_impl->characters();
}
const UChar* String::charactersWithNullTermination()
{
if (!m_impl)
return 0;
return m_impl->charactersWithNullTermination();
}
DeprecatedString String::deprecatedString() const
{
if (!m_impl)
return DeprecatedString::null;
if (!m_impl->characters())
return DeprecatedString("", 0);
return DeprecatedString(reinterpret_cast<const DeprecatedChar*>(m_impl->characters()), m_impl->length());
}
String String::format(const char *format, ...)
{
va_list args;
va_start(args, format);
Vector<char, 256> buffer;
// Do the format once to get the length.
#if PLATFORM(WIN_OS)
int result = _vscprintf(format, args);
#else
char ch;
int result = vsnprintf(&ch, 1, format, args);
// We need to call va_end() and then va_start() again here, as the
// contents of args is undefined after the call to vsnprintf
// according to http://man.cx/snprintf(3)
//
// Not calling va_end/va_start here happens to work on lots of
// systems, but fails e.g. on 64bit Linux.
va_end(args);
va_start(args, format);
#endif
if (result == 0)
return String("");
if (result < 0)
return String();
unsigned len = result;
buffer.resize(len + 1);
// Now do the formatting again, guaranteed to fit.
vsnprintf(buffer.data(), buffer.size(), format, args);
va_end(args);
return new StringImpl(buffer.data(), len);
}
String String::number(int n)
{
return String::format("%d", n);
}
String String::number(unsigned n)
{
return String::format("%u", n);
}
String String::number(long n)
{
return String::format("%ld", n);
}
String String::number(unsigned long n)
{
return String::format("%lu", n);
}
String String::number(long long n)
{
#if PLATFORM(WIN_OS)
return String::format("%I64i", n);
#else
return String::format("%lli", n);
#endif
}
String String::number(unsigned long long n)
{
#if PLATFORM(WIN_OS)
return String::format("%I64u", n);
#else
return String::format("%llu", n);
#endif
}
String String::number(double n)
{
return String::format("%.6lg", n);
}
int String::toInt(bool* ok) const
{
if (!m_impl) {
if (ok)
*ok = false;
return 0;
}
return m_impl->toInt(ok);
}
double String::toDouble(bool* ok) const
{
if (!m_impl) {
if (ok)
*ok = false;
return 0;
}
return m_impl->toDouble(ok);
}
String String::copy() const
{
if (!m_impl)
return String();
return m_impl->copy();
}
bool String::isEmpty() const
{
return !m_impl || !m_impl->length();
}
Length* String::toCoordsArray(int& len) const
{
return m_impl ? m_impl->toCoordsArray(len) : 0;
}
Length* String::toLengthArray(int& len) const
{
return m_impl ? m_impl->toLengthArray(len) : 0;
}
Vector<String> String::split(const String& separator, bool allowEmptyEntries) const
{
Vector<String> result;
int startPos = 0;
int endPos;
while ((endPos = find(separator, startPos)) != -1) {
if (allowEmptyEntries || startPos != endPos)
result.append(substring(startPos, endPos - startPos));
startPos = endPos + separator.length();
}
if (allowEmptyEntries || startPos != (int)length())
result.append(substring(startPos));
return result;
}
Vector<String> String::split(UChar separator, bool allowEmptyEntries) const
{
Vector<String> result;
return split(String(&separator, 1), allowEmptyEntries);
}
#ifndef NDEBUG
Vector<char> String::ascii() const
{
if (m_impl)
return m_impl->ascii();
const char* nullMsg = "(null impl)";
Vector<char> buffer(strlen(nullMsg) + 1);
for (int i = 0; nullMsg[i]; ++i) {
buffer.append(nullMsg[i]);
}
buffer.append('\0');
return buffer;
}
#endif
CString String::latin1() const
{
return Latin1Encoding().encode(characters(), length());
}
CString String::utf8() const
{
return UTF8Encoding().encode(characters(), length());
}
bool operator==(const String& a, const DeprecatedString& b)
{
unsigned l = a.length();
if (l != b.length())
return false;
if (!memcmp(a.characters(), b.unicode(), l * sizeof(UChar)))
return true;
return false;
}
String::String(const Identifier& str)
{
if (str.isNull())
return;
if (str.isEmpty())
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(reinterpret_cast<const UChar*>(str.data()), str.size());
}
String::String(const UString& str)
{
if (str.isNull())
return;
if (str.isEmpty())
m_impl = StringImpl::empty();
else
m_impl = new StringImpl(reinterpret_cast<const UChar*>(str.data()), str.size());
}
String::operator Identifier() const
{
if (!m_impl)
return Identifier();
return Identifier(reinterpret_cast<const KJS::UChar*>(m_impl->characters()), m_impl->length());
}
String::operator UString() const
{
if (!m_impl)
return UString();
return UString(reinterpret_cast<const KJS::UChar*>(m_impl->characters()), m_impl->length());
}
String String::newUninitialized(size_t length, UChar*& characterBuffer)
{
return StringImpl::newUninitialized(length, characterBuffer);
}
String String::adopt(Vector<UChar>& buffer)
{
// For an empty buffer, construct an empty string, not a null string,
// and use a standard constructor so we get the shared empty string.
if (buffer.isEmpty())
return "";
return StringImpl::adopt(buffer);
}
} // namespace WebCore
#ifndef NDEBUG
// For debugging only -- leaks memory
WebCore::String* string(const char* s)
{
return new WebCore::String(s);
}
#endif