mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
fce32ab69e
|
@ -205,7 +205,7 @@ check-docublocks:
|
|||
grep -v '.*#.*:.*' \
|
||||
>> /tmp/rawindoc.txt
|
||||
cat /tmp/rawindoc.txt | sed -e "s;.*ck ;;" -e "s;.*ne ;;" |sort -u > /tmp/indoc.txt
|
||||
grep -R '^/// @startDocuBlock' ../DocuBlocks --include "*.md" --include "*.mdpp" |grep -v aardvark > /tmp/rawinprog.txt
|
||||
grep -R '^@startDocuBlock' ../DocuBlocks --include "*.md" --include "*.mdpp" |grep -v aardvark > /tmp/rawinprog.txt
|
||||
# searching the Inline docublocks needs some more blacklisting:
|
||||
grep -R '@startDocuBlockInline' --include "*.h" --include "*.cpp" --include "*.js" --include "*.mdpp" . |\
|
||||
grep -v ppbook |\
|
||||
|
@ -264,9 +264,9 @@ build-books:
|
|||
make build-books-keep-md NAME=AQL
|
||||
make build-books-keep-md NAME=HTTP
|
||||
|
||||
make ppbook-check-html-link NAME=Users
|
||||
make ppbook-check-html-link NAME=AQL
|
||||
make ppbook-check-html-link NAME=HTTP
|
||||
#make ppbook-check-html-link NAME=Users
|
||||
#make ppbook-check-html-link NAME=AQL
|
||||
#make ppbook-check-html-link NAME=HTTP
|
||||
|
||||
make check-docublocks
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ BOOST_AUTO_TEST_CASE (tst_json_string_utf8_1) {
|
|||
BOOST_CHECK_EQUAL(true, TRI_IsStringJson(json));
|
||||
|
||||
STRINGIFY
|
||||
BOOST_CHECK_EQUAL("\"\\uCF54\\uB9AC\\uC544\\uB2F7\\uCEF4 \\uBA54\\uC77C\\uC54C\\uB9AC\\uBBF8 \\uC11C\\uBE44\\uC2A4 \\uC911\\uB2E8\\uC548\\uB0B4 [\\uC548\\uB0B4] \\uAC1C\\uC778\\uC815\\uBCF4\\uCDE8\\uAE09\\uBC29\\uCE68 \\uBCC0\\uACBD \\uC548\\uB0B4 \\uD68C\\uC0AC\\uC18C\\uAC1C | \\uAD11\\uACE0\\uC548\\uB0B4 | \\uC81C\\uD734\\uC548\\uB0B4 | \\uAC1C\\uC778\\uC815\\uBCF4\\uCDE8\\uAE09\\uBC29\\uCE68 | \\uCCAD\\uC18C\\uB144\\uBCF4\\uD638\\uC815\\uCC45 | \\uC2A4\\uD338\\uBC29\\uC9C0\\uC815\\uCC45 | \\uC0AC\\uC774\\uBC84\\uACE0\\uAC1D\\uC13C\\uD130 | \\uC57D\\uAD00\\uC548\\uB0B4 | \\uC774\\uBA54\\uC77C \\uBB34\\uB2E8\\uC218\\uC9D1\\uAC70\\uBD80 | \\uC11C\\uBE44\\uC2A4 \\uC804\\uCCB4\\uBCF4\\uAE30\"", STRING_VALUE);
|
||||
BOOST_CHECK_EQUAL("\"코리아닷컴 메일알리미 서비스 중단안내 [안내] 개인정보취급방침 변경 안내 회사소개 | 광고안내 | 제휴안내 | 개인정보취급방침 | 청소년보호정책 | 스팸방지정책 | 사이버고객센터 | 약관안내 | 이메일 무단수집거부 | 서비스 전체보기\"", STRING_VALUE);
|
||||
|
||||
FREE_JSON
|
||||
FREE_BUFFER
|
||||
|
@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE (tst_json_string_utf8_2) {
|
|||
TRI_json_t* json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, value, strlen(value));
|
||||
|
||||
STRINGIFY
|
||||
BOOST_CHECK_EQUAL("\"\\u00E4\\u00F6\\u00FC\\u00DF\\u00C4\\u00D6\\u00DC\\u20AC\\u00B5\"", STRING_VALUE);
|
||||
BOOST_CHECK_EQUAL("\"äöüßÄÖÜ€µ\"", STRING_VALUE);
|
||||
|
||||
FREE_JSON
|
||||
FREE_BUFFER
|
||||
|
@ -327,7 +327,7 @@ BOOST_AUTO_TEST_CASE (tst_json_string_utf8_3) {
|
|||
TRI_json_t* json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, value, strlen(value));
|
||||
|
||||
STRINGIFY
|
||||
BOOST_CHECK_EQUAL("\"a\\uD835\\uDEE2\"", STRING_VALUE);
|
||||
BOOST_CHECK_EQUAL("\"a𝛢\"", STRING_VALUE);
|
||||
|
||||
FREE_JSON
|
||||
FREE_BUFFER
|
||||
|
@ -509,7 +509,7 @@ BOOST_AUTO_TEST_CASE (tst_json_array_keys_utf8) {
|
|||
TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "мадридского", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, 4));
|
||||
|
||||
STRINGIFY
|
||||
BOOST_CHECK_EQUAL("{\"\\u00E4\\u00F6\\u00FC\\u00C4\\u00D6\\u00DC\\u00DF\":1,\"\\uCF54\\uB9AC\\uC544\\uB2F7\\uCEF4\":2,\"\\u30B8\\u30E3\\u30D1\\u30F3\":3,\"\\u043C\\u0430\\u0434\\u0440\\u0438\\u0434\\u0441\\u043A\\u043E\\u0433\\u043E\":4}", STRING_VALUE);
|
||||
BOOST_CHECK_EQUAL("{\"äöüÄÖÜß\":1,\"코리아닷컴\":2,\"ジャパン\":3,\"мадридского\":4}", STRING_VALUE);
|
||||
|
||||
FREE_JSON
|
||||
FREE_BUFFER
|
||||
|
|
|
@ -2219,70 +2219,59 @@ void AstNode::stringify(arangodb::basics::StringBuffer* buffer, bool verbose,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
if (verbose || n > 0) {
|
||||
if (verbose || n > 1) {
|
||||
buffer->appendChar('[');
|
||||
buffer->appendChar('[');
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendChar(',');
|
||||
}
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendChar(',');
|
||||
}
|
||||
|
||||
AstNode* member = getMember(i);
|
||||
if (member != nullptr) {
|
||||
member->stringify(buffer, verbose, failIfLong);
|
||||
}
|
||||
}
|
||||
if (verbose || n > 1) {
|
||||
buffer->appendChar(']');
|
||||
AstNode* member = getMember(i);
|
||||
if (member != nullptr) {
|
||||
member->stringify(buffer, verbose, failIfLong);
|
||||
}
|
||||
}
|
||||
buffer->appendChar(']');
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == NODE_TYPE_OBJECT) {
|
||||
// must be JavaScript-compatible!
|
||||
if (verbose) {
|
||||
buffer->appendChar('{');
|
||||
size_t const n = numMembers();
|
||||
buffer->appendChar('{');
|
||||
size_t const n = numMembers();
|
||||
|
||||
if (failIfLong && n > TooLongThreshold) {
|
||||
// intentionally do not stringify this node because the output would be
|
||||
// too long
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendChar(',');
|
||||
}
|
||||
|
||||
AstNode* member = getMember(i);
|
||||
|
||||
if (member->type == NODE_TYPE_OBJECT_ELEMENT) {
|
||||
TRI_ASSERT(member->numMembers() == 1);
|
||||
|
||||
buffer->appendChar('"');
|
||||
buffer->appendJsonEncoded(member->getStringValue(),
|
||||
member->getStringLength());
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("\":"));
|
||||
|
||||
member->getMember(0)->stringify(buffer, verbose, failIfLong);
|
||||
} else if (member->type == NODE_TYPE_CALCULATED_OBJECT_ELEMENT) {
|
||||
TRI_ASSERT(member->numMembers() == 2);
|
||||
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("$["));
|
||||
member->getMember(0)->stringify(buffer, verbose, failIfLong);
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("]:"));
|
||||
member->getMember(1)->stringify(buffer, verbose, failIfLong);
|
||||
} else {
|
||||
TRI_ASSERT(false);
|
||||
}
|
||||
}
|
||||
buffer->appendChar('}');
|
||||
} else {
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("[object Object]"));
|
||||
if (failIfLong && n > TooLongThreshold) {
|
||||
// intentionally do not stringify this node because the output would be
|
||||
// too long
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendChar(',');
|
||||
}
|
||||
|
||||
AstNode* member = getMember(i);
|
||||
|
||||
if (member->type == NODE_TYPE_OBJECT_ELEMENT) {
|
||||
TRI_ASSERT(member->numMembers() == 1);
|
||||
|
||||
buffer->appendJsonEncoded(member->getStringValue(),
|
||||
member->getStringLength());
|
||||
buffer->appendChar(':');
|
||||
|
||||
member->getMember(0)->stringify(buffer, verbose, failIfLong);
|
||||
} else if (member->type == NODE_TYPE_CALCULATED_OBJECT_ELEMENT) {
|
||||
TRI_ASSERT(member->numMembers() == 2);
|
||||
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("$["));
|
||||
member->getMember(0)->stringify(buffer, verbose, failIfLong);
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("]:"));
|
||||
member->getMember(1)->stringify(buffer, verbose, failIfLong);
|
||||
} else {
|
||||
TRI_ASSERT(false);
|
||||
}
|
||||
}
|
||||
buffer->appendChar('}');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2809,9 +2798,7 @@ void AstNode::appendValue(arangodb::basics::StringBuffer* buffer) const {
|
|||
}
|
||||
|
||||
case VALUE_TYPE_STRING: {
|
||||
buffer->appendChar('"');
|
||||
buffer->appendJsonEncoded(value.value._string, value.length);
|
||||
buffer->appendChar('"');
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
|
|||
{"SUBSTRING", Function("SUBSTRING", "AQL_SUBSTRING", "s,n|n", true, true,
|
||||
false, true, true)},
|
||||
{"CONTAINS", Function("CONTAINS", "AQL_CONTAINS", "s,s|b", true, true,
|
||||
false, true, true)},
|
||||
false, true, true, &Functions::Contains)},
|
||||
{"LIKE", Function("LIKE", "AQL_LIKE", "s,r|b", true, true, false, true,
|
||||
true, &Functions::Like)},
|
||||
{"LEFT",
|
||||
|
@ -858,16 +858,12 @@ void Executor::generateCodeExpression(AstNode const* node) {
|
|||
void Executor::generateCodeString(char const* value, size_t length) {
|
||||
TRI_ASSERT(value != nullptr);
|
||||
|
||||
_buffer->appendChar('"');
|
||||
_buffer->appendJsonEncoded(value, length);
|
||||
_buffer->appendChar('"');
|
||||
}
|
||||
|
||||
/// @brief generates code for a string value
|
||||
void Executor::generateCodeString(std::string const& value) {
|
||||
_buffer->appendChar('"');
|
||||
_buffer->appendJsonEncoded(value.c_str(), value.size());
|
||||
_buffer->appendChar('"');
|
||||
}
|
||||
|
||||
/// @brief generate JavaScript code for an array
|
||||
|
|
|
@ -60,6 +60,13 @@ using namespace arangodb::aql;
|
|||
thread_local std::unordered_map<std::string, RegexMatcher*>* RegexCache =
|
||||
nullptr;
|
||||
|
||||
/// @brief convert a number value into an AqlValue
|
||||
static AqlValue NumberValue(arangodb::AqlTransaction* trx, int value) {
|
||||
TransactionBuilderLeaser builder(trx);
|
||||
builder->add(VPackValue(value));
|
||||
return AqlValue(builder.get());
|
||||
}
|
||||
|
||||
/// @brief convert a number value into an AqlValue
|
||||
static AqlValue NumberValue(arangodb::AqlTransaction* trx, double value) {
|
||||
if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL || value == -HUGE_VAL) {
|
||||
|
@ -337,21 +344,9 @@ void Functions::Stringify(arangodb::AqlTransaction* trx,
|
|||
return;
|
||||
}
|
||||
|
||||
if (slice.isArray()) {
|
||||
bool first = true;
|
||||
for (auto const& sub : VPackArrayIterator(slice, true)) {
|
||||
if (!first) {
|
||||
buffer.push_back(',');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
Stringify(trx, buffer, sub);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (slice.isObject()) {
|
||||
buffer.append("[object Object]");
|
||||
if (slice.isObject() || slice.isArray()) {
|
||||
VPackDumper dumper(&buffer, trx->transactionContext()->getVPackOptions());
|
||||
dumper.dump(slice);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1156,6 +1151,62 @@ AqlValue Functions::Nth(arangodb::aql::Query* query,
|
|||
return value.at(index, mustDestroy, true);
|
||||
}
|
||||
|
||||
/// @brief function CONTAINS
|
||||
AqlValue Functions::Contains(arangodb::aql::Query* query,
|
||||
arangodb::AqlTransaction* trx,
|
||||
VPackFunctionParameters const& parameters) {
|
||||
ValidateParameters(parameters, "CONTAINS", 2, 3);
|
||||
|
||||
AqlValue value = ExtractFunctionParameterValue(trx, parameters, 0);
|
||||
AqlValue search = ExtractFunctionParameterValue(trx, parameters, 1);
|
||||
AqlValue returnIndex = ExtractFunctionParameterValue(trx, parameters, 2);
|
||||
|
||||
int result = -1; // default is "not found"
|
||||
{
|
||||
StringBufferLeaser buffer(trx);
|
||||
arangodb::basics::VPackStringBufferAdapter adapter(buffer->stringBuffer());
|
||||
|
||||
AppendAsString(trx, adapter, value);
|
||||
size_t const valueLength = buffer->length();
|
||||
|
||||
size_t const searchOffset = buffer->length();
|
||||
AppendAsString(trx, adapter, search);
|
||||
size_t const searchLength = buffer->length() - valueLength;
|
||||
|
||||
if (searchLength > 0) {
|
||||
char const* found = static_cast<char const*>(memmem(buffer->c_str(), valueLength, buffer->c_str() + searchOffset, searchLength));
|
||||
|
||||
if (found != nullptr) {
|
||||
// find offset into string
|
||||
int bytePosition = static_cast<int>(found - buffer->c_str());
|
||||
char const* p = buffer->c_str();
|
||||
int pos = 0;
|
||||
while (pos < bytePosition) {
|
||||
unsigned char c = static_cast<unsigned char>(*p);
|
||||
if (c < 128) {
|
||||
++pos;
|
||||
} else if (c < 224) {
|
||||
pos += 2;
|
||||
} else if (c < 240) {
|
||||
pos += 3;
|
||||
} else if (c < 248) {
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
result = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnIndex.toBoolean()) {
|
||||
// return numeric value
|
||||
return NumberValue(trx, result);
|
||||
}
|
||||
|
||||
// return boolean
|
||||
return AqlValue(result != -1);
|
||||
}
|
||||
|
||||
/// @brief function CONCAT
|
||||
AqlValue Functions::Concat(arangodb::aql::Query* query,
|
||||
arangodb::AqlTransaction* trx,
|
||||
|
@ -1172,21 +1223,8 @@ AqlValue Functions::Concat(arangodb::aql::Query* query,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (member.isArray()) {
|
||||
// append each member individually
|
||||
AqlValueMaterializer materializer(trx);
|
||||
VPackSlice slice = materializer.slice(member, false);
|
||||
for (auto const& sub : VPackArrayIterator(slice, true)) {
|
||||
if (sub.isNone() || sub.isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Stringify(trx, adapter, sub);
|
||||
}
|
||||
} else {
|
||||
// convert member to a string and append
|
||||
AppendAsString(trx, adapter, member);
|
||||
}
|
||||
// convert member to a string and append
|
||||
AppendAsString(trx, adapter, member);
|
||||
}
|
||||
|
||||
size_t length = buffer->length();
|
||||
|
|
|
@ -89,6 +89,8 @@ struct Functions {
|
|||
VPackFunctionParameters const&);
|
||||
static AqlValue Nth(arangodb::aql::Query*, arangodb::AqlTransaction*,
|
||||
VPackFunctionParameters const&);
|
||||
static AqlValue Contains(arangodb::aql::Query*, arangodb::AqlTransaction*,
|
||||
VPackFunctionParameters const&);
|
||||
static AqlValue Concat(arangodb::aql::Query*, arangodb::AqlTransaction*,
|
||||
VPackFunctionParameters const&);
|
||||
static AqlValue Like(arangodb::aql::Query*, arangodb::AqlTransaction*,
|
||||
|
|
|
@ -152,6 +152,8 @@ RocksDBFeature* RocksDBFeature::instance() {
|
|||
}
|
||||
|
||||
int RocksDBFeature::syncWal() {
|
||||
#ifndef _WIN32
|
||||
// SyncWAL() always reports a "not implemented" error on Windows
|
||||
if (Instance == nullptr || !Instance->isEnabled()) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -164,7 +166,7 @@ int RocksDBFeature::syncWal() {
|
|||
LOG(ERR) << "error syncing rocksdb WAL: " << status.ToString();
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -1317,7 +1317,6 @@ static void JS_PropertiesVocbaseCol(
|
|||
}
|
||||
|
||||
TRI_document_collection_t* document = collection->_collection;
|
||||
TRI_collection_t* base = document;
|
||||
|
||||
// check if we want to change some parameters
|
||||
if (0 < args.Length()) {
|
||||
|
@ -1337,18 +1336,18 @@ static void JS_PropertiesVocbaseCol(
|
|||
// only work under the lock
|
||||
WRITE_LOCKER(writeLocker, document->_infoLock);
|
||||
|
||||
if (base->_info.isVolatile() &&
|
||||
if (document->_info.isVolatile() &&
|
||||
arangodb::basics::VelocyPackHelper::getBooleanValue(
|
||||
slice, "waitForSync", base->_info.waitForSync())) {
|
||||
slice, "waitForSync", document->_info.waitForSync())) {
|
||||
ReleaseCollection(collection);
|
||||
// the combination of waitForSync and isVolatile makes no sense
|
||||
TRI_V8_THROW_EXCEPTION_PARAMETER(
|
||||
"volatile collections do not support the waitForSync option");
|
||||
}
|
||||
|
||||
if (base->_info.isVolatile() !=
|
||||
if (document->_info.isVolatile() !=
|
||||
arangodb::basics::VelocyPackHelper::getBooleanValue(
|
||||
slice, "isVolatile", base->_info.isVolatile())) {
|
||||
slice, "isVolatile", document->_info.isVolatile())) {
|
||||
TRI_V8_THROW_EXCEPTION_PARAMETER(
|
||||
"isVolatile option cannot be changed at runtime");
|
||||
}
|
||||
|
@ -1363,11 +1362,11 @@ static void JS_PropertiesVocbaseCol(
|
|||
"indexBuckets must be a two-power between 1 and 1024");
|
||||
}
|
||||
|
||||
} // Leave the scope and free the JOURNAL lock
|
||||
} // Leave the scope and free the lock
|
||||
|
||||
// try to write new parameter to file
|
||||
bool doSync = base->_vocbase->_settings.forceSyncProperties;
|
||||
res = base->updateCollectionInfo(base->_vocbase, slice, doSync);
|
||||
bool doSync = document->_vocbase->_settings.forceSyncProperties;
|
||||
res = document->updateCollectionInfo(document->_vocbase, slice, doSync);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
ReleaseCollection(collection);
|
||||
|
@ -1377,7 +1376,7 @@ static void JS_PropertiesVocbaseCol(
|
|||
try {
|
||||
VPackBuilder infoBuilder;
|
||||
infoBuilder.openObject();
|
||||
TRI_CreateVelocyPackCollectionInfo(base->_info, infoBuilder);
|
||||
TRI_CreateVelocyPackCollectionInfo(document->_info, infoBuilder);
|
||||
infoBuilder.close();
|
||||
|
||||
// now log the property changes
|
||||
|
@ -1411,12 +1410,12 @@ static void JS_PropertiesVocbaseCol(
|
|||
TRI_GET_GLOBAL_STRING(IsSystemKey);
|
||||
TRI_GET_GLOBAL_STRING(IsVolatileKey);
|
||||
TRI_GET_GLOBAL_STRING(JournalSizeKey);
|
||||
result->Set(DoCompactKey, v8::Boolean::New(isolate, base->_info.doCompact()));
|
||||
result->Set(IsSystemKey, v8::Boolean::New(isolate, base->_info.isSystem()));
|
||||
result->Set(DoCompactKey, v8::Boolean::New(isolate, document->_info.doCompact()));
|
||||
result->Set(IsSystemKey, v8::Boolean::New(isolate, document->_info.isSystem()));
|
||||
result->Set(IsVolatileKey,
|
||||
v8::Boolean::New(isolate, base->_info.isVolatile()));
|
||||
v8::Boolean::New(isolate, document->_info.isVolatile()));
|
||||
result->Set(JournalSizeKey,
|
||||
v8::Number::New(isolate, base->_info.maximalSize()));
|
||||
v8::Number::New(isolate, document->_info.maximalSize()));
|
||||
result->Set(TRI_V8_ASCII_STRING("indexBuckets"),
|
||||
v8::Number::New(isolate, document->_info.indexBuckets()));
|
||||
|
||||
|
@ -1434,7 +1433,7 @@ static void JS_PropertiesVocbaseCol(
|
|||
}
|
||||
TRI_GET_GLOBAL_STRING(WaitForSyncKey);
|
||||
result->Set(WaitForSyncKey,
|
||||
v8::Boolean::New(isolate, base->_info.waitForSync()));
|
||||
v8::Boolean::New(isolate, document->_info.waitForSync()));
|
||||
|
||||
ReleaseCollection(collection);
|
||||
TRI_V8_RETURN(result);
|
||||
|
@ -1458,11 +1457,11 @@ static int RenameGraphCollections(v8::Isolate* isolate,
|
|||
v8::HandleScope scope(isolate);
|
||||
|
||||
StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE);
|
||||
buffer.appendText("require('@arangodb/general-graph')._renameCollection(\"");
|
||||
buffer.appendText("require('@arangodb/general-graph')._renameCollection(");
|
||||
buffer.appendJsonEncoded(oldName.c_str(), oldName.size());
|
||||
buffer.appendText("\", \"");
|
||||
buffer.appendChar(',');
|
||||
buffer.appendJsonEncoded(newName.c_str(), newName.size());
|
||||
buffer.appendText("\");");
|
||||
buffer.appendText(");");
|
||||
|
||||
TRI_ExecuteJavaScriptString(
|
||||
isolate, isolate->GetCurrentContext(),
|
||||
|
|
|
@ -476,9 +476,7 @@ void ImportHelper::addField(char const* field, size_t fieldLength, size_t row,
|
|||
|
||||
if (row == 0 || escaped) {
|
||||
// head line or escaped value
|
||||
_lineBuffer.appendChar('"');
|
||||
_lineBuffer.appendJsonEncoded(field);
|
||||
_lineBuffer.appendChar('"');
|
||||
_lineBuffer.appendJsonEncoded(field, fieldLength);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -514,9 +512,7 @@ void ImportHelper::addField(char const* field, size_t fieldLength, size_t row,
|
|||
_lineBuffer.appendInteger(num);
|
||||
} catch (...) {
|
||||
// conversion failed
|
||||
_lineBuffer.appendChar('"');
|
||||
_lineBuffer.appendJsonEncoded(field);
|
||||
_lineBuffer.appendChar('"');
|
||||
_lineBuffer.appendJsonEncoded(field, fieldLength);
|
||||
}
|
||||
} else if (IsDecimal(field, fieldLength)) {
|
||||
// double value
|
||||
|
@ -539,9 +535,7 @@ void ImportHelper::addField(char const* field, size_t fieldLength, size_t row,
|
|||
_lineBuffer.appendText(field, fieldLength);
|
||||
_lineBuffer.appendChar('"');
|
||||
} else {
|
||||
_lineBuffer.appendChar('"');
|
||||
_lineBuffer.appendJsonEncoded(field);
|
||||
_lineBuffer.appendChar('"');
|
||||
_lineBuffer.appendJsonEncoded(field, fieldLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2122,7 +2122,7 @@ function ARITHMETIC_MODULUS (lhs, rhs) {
|
|||
function AQL_CONCAT () {
|
||||
'use strict';
|
||||
|
||||
var result = '', i, j;
|
||||
var result = '', i;
|
||||
|
||||
for (i = 0; i < arguments.length; ++i) {
|
||||
var element = arguments[i];
|
||||
|
@ -2130,16 +2130,7 @@ function AQL_CONCAT () {
|
|||
if (weight === TYPEWEIGHT_NULL) {
|
||||
continue;
|
||||
}
|
||||
else if (weight === TYPEWEIGHT_ARRAY) {
|
||||
for (j = 0; j < element.length; ++j) {
|
||||
if (TYPEWEIGHT(element[j]) !== TYPEWEIGHT_NULL) {
|
||||
result += AQL_TO_STRING(element[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result += AQL_TO_STRING(element);
|
||||
}
|
||||
result += AQL_TO_STRING(element);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -2161,28 +2152,13 @@ function AQL_CONCAT_SEPARATOR () {
|
|||
if (i > 0 && weight === TYPEWEIGHT_NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
separator = AQL_TO_STRING(element);
|
||||
continue;
|
||||
}
|
||||
else if (found) {
|
||||
result += separator;
|
||||
}
|
||||
|
||||
if (weight === TYPEWEIGHT_ARRAY) {
|
||||
found = false;
|
||||
for (j = 0; j < element.length; ++j) {
|
||||
if (TYPEWEIGHT(element[j]) !== TYPEWEIGHT_NULL) {
|
||||
if (found) {
|
||||
result += separator;
|
||||
}
|
||||
result += AQL_TO_STRING(element[j]);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (found) {
|
||||
result += separator;
|
||||
}
|
||||
result += AQL_TO_STRING(element);
|
||||
found = true;
|
||||
}
|
||||
|
@ -2718,9 +2694,10 @@ function AQL_TO_STRING (value) {
|
|||
case TYPEWEIGHT_STRING:
|
||||
return value;
|
||||
case TYPEWEIGHT_NUMBER:
|
||||
return value.toString();
|
||||
case TYPEWEIGHT_ARRAY:
|
||||
case TYPEWEIGHT_OBJECT:
|
||||
return value.toString();
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,8 +73,8 @@ function ahuacatlDynamicAttributesTestSuite () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testDynamicAttributesNonStringNames : function () {
|
||||
var expected = { "true" : 12, "false" : 15, "123" : 21, "-42.5" : 99, "" : 117, "1,2,3,4" : 131, "[object Object]" : 149 };
|
||||
var query = "{ [ PASSTHRU(null) ] : 7, [ PASSTHRU(true) ] : 12, [ PASSTHRU(false) ] : 15, [ PASSTHRU(123) ] : 21, [ PASSTHRU(-42.5) ] : 99, [ PASSTHRU([ ]) ] : 117, [ PASSTHRU([ 1, 2, 3, 4 ]) ] : 131, [ PASSTHRU({ a: 1 }) ] : 149 }";
|
||||
var expected = { "" : 7, "true" : 12, "false" : 15, "123" : 21, "-42.5" : 99, "[]" : 117, "[1]" : 121, "[1,2,3,4]" : 131, "{\"a\":1}" : 149 };
|
||||
var query = "{ [ PASSTHRU(null) ] : 7, [ PASSTHRU(true) ] : 12, [ PASSTHRU(false) ] : 15, [ PASSTHRU(123) ] : 21, [ PASSTHRU(-42.5) ] : 99, [ PASSTHRU([ ]) ] : 117, [ PASSTHRU([ 1 ]) ] : 121, [ PASSTHRU([ 1, 2, 3, 4 ]) ] : 131, [ PASSTHRU({ a: 1 }) ] : 149 }";
|
||||
checkResult(query, expected);
|
||||
},
|
||||
|
||||
|
|
|
@ -288,8 +288,12 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ -1 ], getQueryResults(buildQuery(i, "\"test\", \"test2\", \"test3\"")));
|
||||
assertEqual([ false ], getQueryResults(buildQuery(i, "null, null")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "4, 4")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "{ }, { }")));
|
||||
assertEqual([ false ], getQueryResults(buildQuery(i, "[ ], [ ]")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "{}, {}")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "{a:1,b:2}, {a:1,b:2}")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "[], []")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "[1,2,3], [1,2,3]")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "[1,2], [1,2]")));
|
||||
assertEqual([ true ], getQueryResults(buildQuery(i, "[1,2,3], 2")));
|
||||
assertEqual([ false ], getQueryResults(buildQuery(i, "null, \"yes\"")));
|
||||
assertEqual([ false ], getQueryResults(buildQuery(i, "3, null")));
|
||||
}
|
||||
|
@ -460,8 +464,10 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "" ], getQueryResults("RETURN LEFT(null, 2)"));
|
||||
assertEqual([ "tr" ], getQueryResults("RETURN LEFT(true, 2)"));
|
||||
assertEqual([ "4" ], getQueryResults("RETURN LEFT(4, 2)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN LEFT([ ], 2)"));
|
||||
assertEqual([ "[o" ], getQueryResults("RETURN LEFT({ }, 2)"));
|
||||
assertEqual([ "[]" ], getQueryResults("RETURN LEFT([ ], 2)"));
|
||||
assertEqual([ "[" ], getQueryResults("RETURN LEFT([ ], 1)"));
|
||||
assertEqual([ "{}" ], getQueryResults("RETURN LEFT({ }, 2)"));
|
||||
assertEqual([ "{" ], getQueryResults("RETURN LEFT({ }, 1)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN LEFT('foo', null)"));
|
||||
assertEqual([ "f" ], getQueryResults("RETURN LEFT('foo', true)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN LEFT('foo', 'bar')"));
|
||||
|
@ -493,8 +499,10 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "" ], getQueryResults("RETURN RIGHT(null, 2)"));
|
||||
assertEqual([ "ue" ], getQueryResults("RETURN RIGHT(true, 2)"));
|
||||
assertEqual([ "4" ], getQueryResults("RETURN RIGHT(4, 2)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN RIGHT([ ], 2)"));
|
||||
assertEqual([ "t]" ], getQueryResults("RETURN RIGHT({ }, 2)"));
|
||||
assertEqual([ "[]" ], getQueryResults("RETURN RIGHT([ ], 2)"));
|
||||
assertEqual([ "]" ], getQueryResults("RETURN RIGHT([ ], 1)"));
|
||||
assertEqual([ "{}" ], getQueryResults("RETURN RIGHT({ }, 2)"));
|
||||
assertEqual([ "}" ], getQueryResults("RETURN RIGHT({ }, 1)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN RIGHT('foo', null)"));
|
||||
assertEqual([ "o" ], getQueryResults("RETURN RIGHT('foo', true)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN RIGHT('foo', 'bar')"));
|
||||
|
@ -672,13 +680,13 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "" ], getQueryResults("RETURN TRIM(null)"));
|
||||
assertEqual([ "true" ], getQueryResults("RETURN TRIM(true)"));
|
||||
assertEqual([ "4" ], getQueryResults("RETURN TRIM(4)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN TRIM([ ])"));
|
||||
assertEqual([ "[object Object]" ], getQueryResults("RETURN TRIM({ })"));
|
||||
assertEqual([ "[]" ], getQueryResults("RETURN TRIM([ ])"));
|
||||
assertEqual([ "{}" ], getQueryResults("RETURN TRIM({ })"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', null)"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', true)"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', 'bar')"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', [ ])"));
|
||||
assertEqual([ "f" ], getQueryResults("RETURN TRIM('foo', { })")); // { } = "[object Object]"
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', { })"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', -1)"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', -1.5)"));
|
||||
assertEqual([ "foo" ], getQueryResults("RETURN TRIM('foo', 3)"));
|
||||
|
@ -836,12 +844,15 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST(null, 'foo')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST(true, 'foo')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST(4, 'foo')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST([], 'foo')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST([ ], 'foo')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST({}, 'foo')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST({ }, 'foo')"));
|
||||
assertEqual([ 0 ], getQueryResults("RETURN FIND_FIRST('foo', null)"));
|
||||
assertEqual([ 0 ], getQueryResults("RETURN FIND_FIRST('foo', '')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', true)"));
|
||||
assertEqual([ 0 ], getQueryResults("RETURN FIND_FIRST('foo', [ ])"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', [])"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', [1,2])"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', { })"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', -1)"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_FIRST('foo', -1.5)"));
|
||||
|
@ -948,7 +959,7 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ 3 ], getQueryResults("RETURN FIND_LAST('foo', null)"));
|
||||
assertEqual([ 3 ], getQueryResults("RETURN FIND_LAST('foo', '')"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', true)"));
|
||||
assertEqual([ 3 ], getQueryResults("RETURN FIND_LAST('foo', [ ])"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', [ ])"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', { })"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', -1)"));
|
||||
assertEqual([ -1 ], getQueryResults("RETURN FIND_LAST('foo', -1.5)"));
|
||||
|
@ -986,7 +997,7 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
|
||||
testConcatList : function () {
|
||||
var expected = [ "theQuickBrownアボカドJumps名称について" ];
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT([ 'the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について' ])");
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT('the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について' )");
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
|
@ -998,12 +1009,12 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN CONCAT()");
|
||||
assertEqual([ "yestrue" ], getQueryResults("RETURN CONCAT(\"yes\", true)"));
|
||||
assertEqual([ "yes4" ], getQueryResults("RETURN CONCAT(\"yes\", 4)"));
|
||||
assertEqual([ "yes" ], getQueryResults("RETURN CONCAT(\"yes\", [ ])"));
|
||||
assertEqual([ "yes[object Object]" ], getQueryResults("RETURN CONCAT(\"yes\", { })"));
|
||||
assertEqual([ "yes[]" ], getQueryResults("RETURN CONCAT(\"yes\", [ ])"));
|
||||
assertEqual([ "yes{}" ], getQueryResults("RETURN CONCAT(\"yes\", { })"));
|
||||
assertEqual([ "trueyes" ], getQueryResults("RETURN CONCAT(true, \"yes\")"));
|
||||
assertEqual([ "4yes" ], getQueryResults("RETURN CONCAT(4, \"yes\")"));
|
||||
assertEqual([ "yes" ], getQueryResults("RETURN CONCAT([ ], \"yes\")"));
|
||||
assertEqual([ "[object Object]yes" ], getQueryResults("RETURN CONCAT({ }, \"yes\")"));
|
||||
assertEqual([ "[]yes" ], getQueryResults("RETURN CONCAT([ ], \"yes\")"));
|
||||
assertEqual([ "{}yes" ], getQueryResults("RETURN CONCAT({ }, \"yes\")"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1032,7 +1043,7 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
|
||||
testConcatCxxList : function () {
|
||||
var expected = [ "theQuickBrownアボカドJumps名称について" ];
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return NOOPT(CONCAT([ 'the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について' ]))");
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return NOOPT(CONCAT('the', 'Quick', '', null, 'Brown', null, 'アボカド', 'Jumps', '名称について'))");
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
|
@ -1044,12 +1055,15 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(CONCAT())");
|
||||
assertEqual([ "yestrue" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", true))"));
|
||||
assertEqual([ "yes4" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", 4))"));
|
||||
assertEqual([ "yes" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", [ ]))"));
|
||||
assertEqual([ "yes[object Object]" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", { }))"));
|
||||
assertEqual([ "yes[]" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", [ ]))"));
|
||||
assertEqual([ "yes{}" ], getQueryResults("RETURN NOOPT(CONCAT(\"yes\", { }))"));
|
||||
assertEqual([ "trueyes" ], getQueryResults("RETURN NOOPT(CONCAT(true, \"yes\"))"));
|
||||
assertEqual([ "4yes" ], getQueryResults("RETURN NOOPT(CONCAT(4, \"yes\"))"));
|
||||
assertEqual([ "yes" ], getQueryResults("RETURN NOOPT(CONCAT([ ], \"yes\"))"));
|
||||
assertEqual([ "[object Object]yes" ], getQueryResults("RETURN NOOPT(CONCAT({ }, \"yes\"))"));
|
||||
assertEqual([ "[]yes" ], getQueryResults("RETURN NOOPT(CONCAT([ ], \"yes\"))"));
|
||||
assertEqual([ "[1,2,3]yes" ], getQueryResults("RETURN NOOPT(CONCAT([ 1,2,3], \"yes\"))"));
|
||||
assertEqual([ "[1,2,3]yes" ], getQueryResults("RETURN NOOPT(CONCAT([ 1 , 2, 3 ], \"yes\"))"));
|
||||
assertEqual([ "{}yes" ], getQueryResults("RETURN NOOPT(CONCAT({ }, \"yes\"))"));
|
||||
assertEqual([ "{\"a\":\"foo\",\"b\":2}yes" ], getQueryResults("RETURN NOOPT(CONCAT({ a: \"foo\", b: 2 }, \"yes\"))"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1077,7 +1091,7 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testConcatSeparatorList1 : function () {
|
||||
var expected = [ "the,Quick,Brown,Fox,Jumps,higher,than,you" ];
|
||||
var expected = [ "[\"the\",\"Quick\",null,\"Brown\",null,\"Fox\",\"Jumps\"],higher,[\"than\",\"you\"]" ];
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR(',', [ 'the', 'Quick', null, 'Brown', null, 'Fox', 'Jumps' ], 'higher', [ 'than', 'you' ])");
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
@ -1087,11 +1101,21 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testConcatSeparatorList2 : function () {
|
||||
var expected = [ "the*/*/Quick*/*/Brown*/*/*/*/Fox*/*/Jumps*/*/higher*/*/than*/*/you" ];
|
||||
var expected = [ "[\"the\",\"Quick\",null,\"Brown\",\"\",\"Fox\",\"Jumps\"]*/*/[]*/*/higher*/*/[\"than\",\"you\"]" ];
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR('*/*/', [ 'the', 'Quick', null, 'Brown', '', 'Fox', 'Jumps' ], [ ], 'higher', [ 'than', 'you' ])");
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test concat_separator function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testConcatSeparatorList3 : function () {
|
||||
var expected = [ "the*/*/Quick*/*/Brown*/*/*/*/Fox*/*/Jumps*/*/[]*/*/higher*/*/[\"than\",\"you\"]" ];
|
||||
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT_SEPARATOR('*/*/', 'the', 'Quick', null, 'Brown', '', 'Fox', 'Jumps', [ ], 'higher', [ 'than', 'you' ])");
|
||||
assertEqual(expected, actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test concat_separator function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1102,16 +1126,17 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(null, \"yes\", \"yes\")"));
|
||||
assertEqual([ "yestrueyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(true, \"yes\", \"yes\")"));
|
||||
assertEqual([ "yes4yes" ], getQueryResults("RETURN CONCAT_SEPARATOR(4, \"yes\", \"yes\")"));
|
||||
assertEqual([ "yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR([ ], \"yes\", \"yes\")"));
|
||||
assertEqual([ "yes[object Object]yes" ], getQueryResults("RETURN CONCAT_SEPARATOR({ }, \"yes\", \"yes\")"));
|
||||
assertEqual([ "yes[]yes" ], getQueryResults("RETURN CONCAT_SEPARATOR([ ], \"yes\", \"yes\")"));
|
||||
assertEqual([ "yes{}yes" ], getQueryResults("RETURN CONCAT_SEPARATOR({ }, \"yes\", \"yes\")"));
|
||||
assertEqual([ "trueyesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", true, \"yes\")"));
|
||||
assertEqual([ "4yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", 4, \"yes\")"));
|
||||
assertEqual([ "yes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", [ ], \"yes\")"));
|
||||
assertEqual([ "[object Object]yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", { }, \"yes\")"));
|
||||
assertEqual([ "[]yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", [ ], \"yes\")"));
|
||||
assertEqual([ "{}yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", { }, \"yes\")"));
|
||||
assertEqual([ "yesyestrue" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", true)"));
|
||||
assertEqual([ "yesyes4" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", 4)"));
|
||||
assertEqual([ "yesyes" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ ])"));
|
||||
assertEqual([ "yesyes[object Object]" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", { })"));
|
||||
assertEqual([ "yesyes[]" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ ])"));
|
||||
assertEqual([ "yesyes[1,2,3]" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", [ 1,2,3 ])"));
|
||||
assertEqual([ "yesyes{}" ], getQueryResults("RETURN CONCAT_SEPARATOR(\"yes\", \"yes\", { })"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1154,8 +1179,12 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ 0 ], getQueryResults("RETURN CHAR_LENGTH(null)"));
|
||||
assertEqual([ 4 ], getQueryResults("RETURN CHAR_LENGTH(true)"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN CHAR_LENGTH(3)"));
|
||||
assertEqual([ 0 ], getQueryResults("RETURN CHAR_LENGTH([ ])"));
|
||||
assertEqual([ 15 ], getQueryResults("RETURN CHAR_LENGTH({ })"));
|
||||
assertEqual([ 2 ], getQueryResults("RETURN CHAR_LENGTH([ ])"));
|
||||
assertEqual([ 7 ], getQueryResults("RETURN CHAR_LENGTH([ 1, 2, 3 ])"));
|
||||
assertEqual([ 2 ], getQueryResults("RETURN CHAR_LENGTH({ })"));
|
||||
assertEqual([ 7 ], getQueryResults("RETURN CHAR_LENGTH({ a:1 })"));
|
||||
assertEqual([ 11 ], getQueryResults("RETURN CHAR_LENGTH({ a: \"foo\" })"));
|
||||
assertEqual([ 13 ], getQueryResults("RETURN CHAR_LENGTH({ a:1, b: 2 })"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1198,8 +1227,11 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "" ], getQueryResults("RETURN LOWER(null)"));
|
||||
assertEqual([ "true" ], getQueryResults("RETURN LOWER(true)"));
|
||||
assertEqual([ "3" ], getQueryResults("RETURN LOWER(3)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN LOWER([])"));
|
||||
assertEqual([ "[object object]" ], getQueryResults("RETURN LOWER({})"));
|
||||
assertEqual([ "[]" ], getQueryResults("RETURN LOWER([])"));
|
||||
assertEqual([ "[1,2,3]" ], getQueryResults("RETURN LOWER([1,2,3])"));
|
||||
assertEqual([ "{}" ], getQueryResults("RETURN LOWER({})"));
|
||||
assertEqual([ "{\"a\":1,\"b\":2}" ], getQueryResults("RETURN LOWER({A:1,b:2})"));
|
||||
assertEqual([ "{\"a\":1,\"a\":2,\"b\":3}" ], getQueryResults("RETURN LOWER({A:1,a:2,b:3})"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1232,8 +1264,10 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "" ], getQueryResults("RETURN UPPER(null)"));
|
||||
assertEqual([ "TRUE" ], getQueryResults("RETURN UPPER(true)"));
|
||||
assertEqual([ "3" ], getQueryResults("RETURN UPPER(3)"));
|
||||
assertEqual([ "" ], getQueryResults("RETURN UPPER([])"));
|
||||
assertEqual([ "[OBJECT OBJECT]" ], getQueryResults("RETURN UPPER({})"));
|
||||
assertEqual([ "[]" ], getQueryResults("RETURN UPPER([])"));
|
||||
assertEqual([ "[1,2,3]" ], getQueryResults("RETURN UPPER([1,2,3])"));
|
||||
assertEqual([ "{}" ], getQueryResults("RETURN UPPER({})"));
|
||||
assertEqual([ "{\"A\":1,\"B\":2}" ], getQueryResults("RETURN UPPER({a:1, b:2})"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1309,8 +1343,10 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "" ], getQueryResults(buildQuery(i, "null, 1")));
|
||||
assertEqual([ "true" ], getQueryResults(buildQuery(i, "true, 0")));
|
||||
assertEqual([ "3" ], getQueryResults(buildQuery(i, "3, 0")));
|
||||
assertEqual([ "" ], getQueryResults(buildQuery(i, "[ ], 0")));
|
||||
assertEqual([ "[object Object]" ], getQueryResults(buildQuery(i, "{ }, 0")));
|
||||
assertEqual([ "[]" ], getQueryResults(buildQuery(i, "[ ], 0")));
|
||||
assertEqual([ "[1,2,3]" ], getQueryResults(buildQuery(i, "[ 1, 2, 3 ], 0")));
|
||||
assertEqual([ "2,3]" ], getQueryResults(buildQuery(i, "[ 1, 2, 3 ], 3")));
|
||||
assertEqual([ "{}" ], getQueryResults(buildQuery(i, "{ }, 0")));
|
||||
assertEqual([ "" ], getQueryResults(buildQuery(i, "\"yes\", null, 0")));
|
||||
assertEqual([ "" ], getQueryResults(buildQuery(i, "\"yes\", true, 0")));
|
||||
assertEqual([ "" ], getQueryResults(buildQuery(i, "\"yes\", \"yes\", 0")));
|
||||
|
@ -1444,8 +1480,13 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "c4ca4238a0b923820dcc509a6f75849b" ], getQueryResults("RETURN MD5(1)"));
|
||||
assertEqual([ "6bb61e3b7bce0931da574d19d1d82c88" ], getQueryResults("RETURN MD5(-1)"));
|
||||
assertEqual([ "d41d8cd98f00b204e9800998ecf8427e" ], getQueryResults("RETURN MD5(null)"));
|
||||
assertEqual([ "d751713988987e9331980363e24189ce" ], getQueryResults("RETURN MD5([])"));
|
||||
assertEqual([ "8d5162ca104fa7e79fe80fd92bb657fb" ], getQueryResults("RETURN MD5([0])"));
|
||||
assertEqual([ "35dba5d75538a9bbe0b4da4422759a0e" ], getQueryResults("RETURN MD5('[1]')"));
|
||||
assertEqual([ "1441a7909c087dbbe7ce59881b9df8b9" ], getQueryResults("RETURN MD5({ })"));
|
||||
assertEqual([ "f79408e5ca998cd53faf44af31e6eb45" ], getQueryResults("RETURN MD5([1,2])"));
|
||||
assertEqual([ "99914b932bd37a50b983c5e7c90ae93b" ], getQueryResults("RETURN MD5({ })"));
|
||||
assertEqual([ "99914b932bd37a50b983c5e7c90ae93b" ], getQueryResults("RETURN MD5({})"));
|
||||
assertEqual([ "608de49a4600dbb5b173492759792e4a" ], getQueryResults("RETURN MD5({a:1,b:2})"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1499,7 +1540,7 @@ function ahuacatlStringFunctionsTestSuite () {
|
|||
assertEqual([ "6bb61e3b7bce0931da574d19d1d82c88" ], getQueryResults("RETURN NOOPT(MD5(-1))"));
|
||||
assertEqual([ "d41d8cd98f00b204e9800998ecf8427e" ], getQueryResults("RETURN NOOPT(MD5(null))"));
|
||||
assertEqual([ "35dba5d75538a9bbe0b4da4422759a0e" ], getQueryResults("RETURN NOOPT(MD5('[1]'))"));
|
||||
assertEqual([ "1441a7909c087dbbe7ce59881b9df8b9" ], getQueryResults("RETURN NOOPT(MD5({ }))"));
|
||||
assertEqual([ "99914b932bd37a50b983c5e7c90ae93b" ], getQueryResults("RETURN NOOPT(MD5({}))"));
|
||||
assertEqual([ "c7cb8c1df686c0219d540849efe3bce3" ], getQueryResults("RETURN NOOPT(MD5('[1,2,4,7,11,16,22,29,37,46,56,67,79,92,106,121,137,154,172,191,211,232,254,277,301,326,352,379,407,436,466,497,529,562,596,631,667,704,742,781,821,862,904,947,991,1036,1082,1129,1177,1226,1276,1327,1379,1432,1486,1541,1597,1654,1712,1771,1831,1892,1954,2017,2081,2146,2212,2279,2347,2416,2486,2557,2629,2702,2776,2851,2927,3004,3082,3161,3241,3322,3404,3487,3571,3656,3742,3829,3917,4006,4096,4187,4279,4372,4466,4561,4657,4754,4852,4951]'))"));
|
||||
},
|
||||
|
||||
|
|
|
@ -679,23 +679,23 @@ function ahuacatlOperatorsTestSuite () {
|
|||
{ex: "1 ", val: "'1 '"},
|
||||
{ex: "0", val: "'0'"},
|
||||
{ex: "-1", val: "'-1'"},
|
||||
{ex: "", val: "[ ]"},
|
||||
{ex: "0", val: "[ 0 ]"},
|
||||
{ex: "0,1", val: "[ 0, 1 ]"},
|
||||
{ex: "1,2", val: "[ 1, 2 ]"},
|
||||
{ex: "-1,0", val: "[ -1, 0 ]"},
|
||||
{ex: "0,1,1,2,9,4", val: "[ 0, 1, [1, 2], [ [ 9, 4 ] ] ]"},
|
||||
{ex: "[object Object]", val: "[ { } ]"},
|
||||
{ex: "0,1,[object Object]", val: "[ 0, 1, { } ]"},
|
||||
{ex: "[object Object],[object Object]", val: "[ { }, { } ]"},
|
||||
{ex: "", val: "['']"},
|
||||
{ex: "false", val: "[ false ]"},
|
||||
{ex: "true", val: "[ true ]"},
|
||||
{ex: "[object Object]", val: "{ }"},
|
||||
{ex: "[object Object]", val: "{ 'a' : true }"},
|
||||
{ex: "[object Object]", val: "{ 'a' : true, 'b' : 0 }"},
|
||||
{ex: "[object Object]", val: "{ 'a' : { }, 'b' : { } }"},
|
||||
{ex: "[object Object]", val: "{ 'a' : [ ], 'b' : [ ] }"}
|
||||
{ex: "[]", val: "[ ]"},
|
||||
{ex: "[0]", val: "[ 0 ]"},
|
||||
{ex: "[0,1]", val: "[ 0, 1 ]"},
|
||||
{ex: "[1,2]", val: "[ 1, 2 ]"},
|
||||
{ex: "[-1,0]", val: "[ -1, 0 ]"},
|
||||
{ex: "[0,1,[1,2],[[9,4]]]", val: "[ 0, 1, [1, 2], [ [ 9, 4 ] ] ]"},
|
||||
{ex: "[{}]", val: "[ { } ]"},
|
||||
{ex: "[0,1,{}]", val: "[ 0, 1, { } ]"},
|
||||
{ex: "[{},{}]", val: "[ { }, { } ]"},
|
||||
{ex: "[\"\"]", val: "['']"},
|
||||
{ex: "[false]", val: "[ false ]"},
|
||||
{ex: "[true]", val: "[ true ]"},
|
||||
{ex: "{}", val: "{ }"},
|
||||
{ex: "{\"a\":true}", val: "{ 'a' : true }"},
|
||||
{ex: "{\"a\":true,\"b\":0}", val: "{ 'a' : true, 'b' : 0 }"},
|
||||
{ex: "{\"a\":{},\"b\":{}}", val: "{ 'a' : { }, 'b' : { } }"},
|
||||
{ex: "{\"a\":[],\"b\":[]}", val: "{ 'a' : [ ], 'b' : [ ] }"}
|
||||
];
|
||||
values.forEach(function(v) {
|
||||
var q = `RETURN TO_STRING(${v.val})`;
|
||||
|
@ -4126,22 +4126,22 @@ function ahuacatlOperatorsTestSuite () {
|
|||
assertEqual("1", aql.AQL_CONCAT(undefined, 1));
|
||||
assertEqual("2", aql.AQL_CONCAT(undefined, 2));
|
||||
assertEqual("-1", aql.AQL_CONCAT(undefined, -1));
|
||||
assertEqual("", aql.AQL_CONCAT(undefined, [ ]));
|
||||
assertEqual("1", aql.AQL_CONCAT(undefined, [ 1 ]));
|
||||
assertEqual("12", aql.AQL_CONCAT(undefined, [ 1, 2 ]));
|
||||
assertEqual("[object Object]", aql.AQL_CONCAT(undefined, { }));
|
||||
assertEqual("[object Object]", aql.AQL_CONCAT(undefined, { 'a' : 0 }));
|
||||
assertEqual("[]", aql.AQL_CONCAT(undefined, [ ]));
|
||||
assertEqual("[1]", aql.AQL_CONCAT(undefined, [ 1 ]));
|
||||
assertEqual("[1,2]", aql.AQL_CONCAT(undefined, [ 1, 2 ]));
|
||||
assertEqual("{}", aql.AQL_CONCAT(undefined, { }));
|
||||
assertEqual("{\"a\":0}", aql.AQL_CONCAT(undefined, { 'a' : 0 }));
|
||||
assertEqual("false", aql.AQL_CONCAT(false, undefined));
|
||||
assertEqual("true", aql.AQL_CONCAT(true, undefined));
|
||||
assertEqual("0", aql.AQL_CONCAT(0, undefined));
|
||||
assertEqual("1", aql.AQL_CONCAT(1, undefined));
|
||||
assertEqual("2", aql.AQL_CONCAT(2, undefined));
|
||||
assertEqual("-1", aql.AQL_CONCAT(-1, undefined));
|
||||
assertEqual("", aql.AQL_CONCAT([ ], undefined));
|
||||
assertEqual("1", aql.AQL_CONCAT([ 1 ], undefined));
|
||||
assertEqual("12", aql.AQL_CONCAT([ 1, 2 ], undefined));
|
||||
assertEqual("[object Object]", aql.AQL_CONCAT({ }, undefined));
|
||||
assertEqual("[object Object]", aql.AQL_CONCAT({ 'a' : 0 }, undefined));
|
||||
assertEqual("[]", aql.AQL_CONCAT([ ], undefined));
|
||||
assertEqual("[1]", aql.AQL_CONCAT([ 1 ], undefined));
|
||||
assertEqual("[1,2]", aql.AQL_CONCAT([ 1, 2 ], undefined));
|
||||
assertEqual("{}", aql.AQL_CONCAT({ }, undefined));
|
||||
assertEqual("{\"a\":0}", aql.AQL_CONCAT({ 'a' : 0 }, undefined));
|
||||
assertEqual("1", aql.AQL_CONCAT(1, NaN));
|
||||
assertEqual("1", aql.AQL_CONCAT(1, null));
|
||||
assertEqual("1false", aql.AQL_CONCAT(1, false));
|
||||
|
@ -4151,10 +4151,10 @@ function ahuacatlOperatorsTestSuite () {
|
|||
assertEqual("10", aql.AQL_CONCAT(1, '0'));
|
||||
assertEqual("11", aql.AQL_CONCAT(1, '1'));
|
||||
assertEqual("1a", aql.AQL_CONCAT(1, 'a'));
|
||||
assertEqual("1", aql.AQL_CONCAT(1, [ ]));
|
||||
assertEqual("10", aql.AQL_CONCAT(1, [ 0 ]));
|
||||
assertEqual("1[object Object]", aql.AQL_CONCAT(1, { }));
|
||||
assertEqual("1[object Object]", aql.AQL_CONCAT(1, { 'a' : 0 }));
|
||||
assertEqual("1[]", aql.AQL_CONCAT(1, [ ]));
|
||||
assertEqual("1[0]", aql.AQL_CONCAT(1, [ 0 ]));
|
||||
assertEqual("1{}", aql.AQL_CONCAT(1, { }));
|
||||
assertEqual("1{\"a\":0}", aql.AQL_CONCAT(1, { 'a' : 0 }));
|
||||
assertEqual("1", aql.AQL_CONCAT(NaN, 1));
|
||||
assertEqual("1", aql.AQL_CONCAT(null, 1));
|
||||
assertEqual("false1", aql.AQL_CONCAT(false, 1));
|
||||
|
@ -4164,10 +4164,10 @@ function ahuacatlOperatorsTestSuite () {
|
|||
assertEqual("01", aql.AQL_CONCAT('0', 1));
|
||||
assertEqual("11", aql.AQL_CONCAT('1', 1));
|
||||
assertEqual("a1", aql.AQL_CONCAT('a', 1));
|
||||
assertEqual("1", aql.AQL_CONCAT([ ], 1));
|
||||
assertEqual("01", aql.AQL_CONCAT([ 0 ], 1));
|
||||
assertEqual("[object Object]1", aql.AQL_CONCAT({ }, 1));
|
||||
assertEqual("[object Object]1", aql.AQL_CONCAT({ 'a' : 0 }, 1));
|
||||
assertEqual("[]1", aql.AQL_CONCAT([ ], 1));
|
||||
assertEqual("[0]1", aql.AQL_CONCAT([ 0 ], 1));
|
||||
assertEqual("{}1", aql.AQL_CONCAT({ }, 1));
|
||||
assertEqual("{\"a\":0}1", aql.AQL_CONCAT({ 'a' : 0 }, 1));
|
||||
assertEqual("10", aql.AQL_CONCAT(1, 0));
|
||||
assertEqual("1000", aql.AQL_CONCAT(100, 0));
|
||||
assertEqual("-10", aql.AQL_CONCAT(-1, 0));
|
||||
|
@ -4175,12 +4175,13 @@ function ahuacatlOperatorsTestSuite () {
|
|||
assertEqual("00", aql.AQL_CONCAT(0, 0));
|
||||
assertEqual("false", aql.AQL_CONCAT('', false));
|
||||
assertEqual("true", aql.AQL_CONCAT('', true));
|
||||
assertEqual("", aql.AQL_CONCAT('', [ ]));
|
||||
assertEqual("[object Object]", aql.AQL_CONCAT('', { }));
|
||||
assertEqual("[]", aql.AQL_CONCAT('', [ ]));
|
||||
assertEqual("{}", aql.AQL_CONCAT('', { }));
|
||||
assertEqual("afalse", aql.AQL_CONCAT('a', false));
|
||||
assertEqual("atrue", aql.AQL_CONCAT('a', true));
|
||||
assertEqual("a", aql.AQL_CONCAT('a', [ ]));
|
||||
assertEqual("a[object Object]", aql.AQL_CONCAT('a', { }));
|
||||
assertEqual("a[]", aql.AQL_CONCAT('a', [ ]));
|
||||
assertEqual("a{}", aql.AQL_CONCAT('a', { }));
|
||||
assertEqual("a{\"foo\":\"bar\"}", aql.AQL_CONCAT('a', { foo: "bar" }));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -27,50 +27,6 @@
|
|||
#include "Basics/fpconv.h"
|
||||
#include "Zip/zip.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escape tables
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define Z16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escape values for characters used in JSON string printing
|
||||
/// use when forward slashes need no escaping
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static char const JsonEscapeTableWithoutSlash[256] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n',
|
||||
'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, '\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escape values for characters used in JSON string printing
|
||||
/// use when forward slashes need escaping
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static char const JsonEscapeTableWithSlash[256] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n',
|
||||
'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, '/', // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, '\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief append a character without check
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -136,266 +92,6 @@ static int AppendString(TRI_string_buffer_t* self, char const* str,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escapes UTF-8 range U+0000 to U+007F
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void EscapeUtf8Range0000T007F(TRI_string_buffer_t* self,
|
||||
char const** src) {
|
||||
uint8_t c = (uint8_t) * (*src);
|
||||
|
||||
uint16_t i1 = (((uint16_t)c) & 0xF0) >> 4;
|
||||
uint16_t i2 = (((uint16_t)c) & 0x0F);
|
||||
|
||||
AppendString(self, "00", 2);
|
||||
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
|
||||
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escapes UTF-8 range U+0080 to U+07FF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void EscapeUtf8Range0080T07FF(TRI_string_buffer_t* self,
|
||||
char const** src) {
|
||||
uint8_t c = (uint8_t) * ((*src) + 0);
|
||||
uint8_t d = (uint8_t) * ((*src) + 1);
|
||||
|
||||
// correct UTF-8
|
||||
if ((d & 0xC0) == 0x80) {
|
||||
uint16_t n = ((c & 0x1F) << 6) | (d & 0x3F);
|
||||
TRI_ASSERT(n >= 128);
|
||||
|
||||
uint16_t i1 = (n & 0xF000) >> 12;
|
||||
uint16_t i2 = (n & 0x0F00) >> 8;
|
||||
uint16_t i3 = (n & 0x00F0) >> 4;
|
||||
uint16_t i4 = (n & 0x000F);
|
||||
|
||||
AppendChar(self, '\\');
|
||||
AppendChar(self, 'u');
|
||||
|
||||
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
|
||||
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
|
||||
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
|
||||
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
|
||||
|
||||
(*src) += 1;
|
||||
}
|
||||
|
||||
// corrupted UTF-8
|
||||
else {
|
||||
AppendChar(self, *(*src));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escapes UTF-8 range U+0800 to U+D7FF and U+E000 to U+FFFF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void EscapeUtf8Range0800TFFFF(TRI_string_buffer_t* self,
|
||||
char const** src) {
|
||||
uint8_t c = (uint8_t) * ((*src) + 0);
|
||||
uint8_t d = (uint8_t) * ((*src) + 1);
|
||||
uint8_t e = (uint8_t) * ((*src) + 2);
|
||||
|
||||
// correct UTF-8 (3-byte sequence UTF-8 1110xxxx 10xxxxxx)
|
||||
if ((d & 0xC0) == 0x80 && (e & 0xC0) == 0x80) {
|
||||
uint16_t n = ((c & 0x0F) << 12) | ((d & 0x3F) << 6) | (e & 0x3F);
|
||||
|
||||
TRI_ASSERT(n >= 2048 && (n < 55296 || n > 57343));
|
||||
|
||||
uint16_t i1 = (n & 0xF000) >> 12;
|
||||
uint16_t i2 = (n & 0x0F00) >> 8;
|
||||
uint16_t i3 = (n & 0x00F0) >> 4;
|
||||
uint16_t i4 = (n & 0x000F);
|
||||
|
||||
AppendChar(self, '\\');
|
||||
AppendChar(self, 'u');
|
||||
|
||||
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
|
||||
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
|
||||
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
|
||||
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
|
||||
|
||||
(*src) += 2;
|
||||
}
|
||||
|
||||
// corrupted UTF-8
|
||||
else {
|
||||
AppendChar(self, *(*src));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief escapes UTF-8 range U+10000 to U+10FFFF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void EscapeUtf8Range10000T10FFFF(TRI_string_buffer_t* self,
|
||||
char const** src) {
|
||||
uint8_t c = (uint8_t) * ((*src) + 0);
|
||||
uint8_t d = (uint8_t) * ((*src) + 1);
|
||||
uint8_t e = (uint8_t) * ((*src) + 2);
|
||||
uint8_t f = (uint8_t) * ((*src) + 3);
|
||||
|
||||
// correct UTF-8 (4-byte sequence UTF-8 1110xxxx 10xxxxxx 10xxxxxx)
|
||||
if ((d & 0xC0) == 0x80 && (e & 0xC0) == 0x80 && (f & 0xC0) == 0x80) {
|
||||
uint32_t n = ((c & 0x0F) << 18) | ((d & 0x3F) << 12) | ((e & 0x3F) << 6) |
|
||||
(f & 0x3F);
|
||||
TRI_ASSERT(n >= 65536 && n <= 1114111);
|
||||
|
||||
// construct the surrogate pairs
|
||||
n -= 0x10000;
|
||||
|
||||
uint32_t s1 = ((n & 0xFFC00) >> 10) + 0xD800;
|
||||
uint32_t s2 = (n & 0x3FF) + 0xDC00;
|
||||
|
||||
// encode high surrogate
|
||||
uint16_t i1 = (s1 & 0xF000) >> 12;
|
||||
uint16_t i2 = (s1 & 0x0F00) >> 8;
|
||||
uint16_t i3 = (s1 & 0x00F0) >> 4;
|
||||
uint16_t i4 = (s1 & 0x000F);
|
||||
|
||||
AppendChar(self, '\\');
|
||||
AppendChar(self, 'u');
|
||||
|
||||
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
|
||||
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
|
||||
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
|
||||
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
|
||||
|
||||
// encode low surrogate
|
||||
i1 = (s2 & 0xF000) >> 12;
|
||||
i2 = (s2 & 0x0F00) >> 8;
|
||||
i3 = (s2 & 0x00F0) >> 4;
|
||||
i4 = (s2 & 0x000F);
|
||||
|
||||
AppendChar(self, '\\');
|
||||
AppendChar(self, 'u');
|
||||
|
||||
AppendChar(self, (i1 < 10) ? ('0' + i1) : ('A' + i1 - 10));
|
||||
AppendChar(self, (i2 < 10) ? ('0' + i2) : ('A' + i2 - 10));
|
||||
AppendChar(self, (i3 < 10) ? ('0' + i3) : ('A' + i3 - 10));
|
||||
AppendChar(self, (i4 < 10) ? ('0' + i4) : ('A' + i4 - 10));
|
||||
|
||||
// advance src
|
||||
(*src) += 3;
|
||||
}
|
||||
|
||||
// corrupted UTF-8
|
||||
else {
|
||||
AppendChar(self, *(*src));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief appends characters but json-encode the string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int AppendJsonEncodedValue(TRI_string_buffer_t* self, char const*& ptr,
|
||||
bool escapeSlash) {
|
||||
int res = Reserve(self, 2);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// next character as unsigned char
|
||||
uint8_t c = (uint8_t)*ptr;
|
||||
|
||||
// character is in the normal latin1 range
|
||||
if ((c & 0x80) == 0) {
|
||||
// special character, escape
|
||||
char esc;
|
||||
if (escapeSlash) {
|
||||
esc = JsonEscapeTableWithSlash[c];
|
||||
} else {
|
||||
esc = JsonEscapeTableWithoutSlash[c];
|
||||
}
|
||||
|
||||
if (esc) {
|
||||
AppendChar(self, '\\');
|
||||
AppendChar(self, esc);
|
||||
|
||||
if (esc == 'u') {
|
||||
// unicode output, must allocate more memory
|
||||
res = Reserve(self, 4);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
EscapeUtf8Range0000T007F(self, &ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// normal latin1
|
||||
else {
|
||||
AppendChar(self, *ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// unicode range 0080 - 07ff (2-byte sequence UTF-8)
|
||||
else if ((c & 0xE0) == 0xC0) {
|
||||
// hopefully correct UTF-8
|
||||
if (*(ptr + 1) != '\0') {
|
||||
res = Reserve(self, 6);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
EscapeUtf8Range0080T07FF(self, &ptr);
|
||||
}
|
||||
|
||||
// corrupted UTF-8
|
||||
else {
|
||||
AppendChar(self, *ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// unicode range 0800 - ffff (3-byte sequence UTF-8)
|
||||
else if ((c & 0xF0) == 0xE0) {
|
||||
// hopefully correct UTF-8
|
||||
if (*(ptr + 1) != '\0' && *(ptr + 2) != '\0') {
|
||||
res = Reserve(self, 6);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
EscapeUtf8Range0800TFFFF(self, &ptr);
|
||||
}
|
||||
|
||||
// corrupted UTF-8
|
||||
else {
|
||||
AppendChar(self, *ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// unicode range 10000 - 10ffff (4-byte sequence UTF-8)
|
||||
else if ((c & 0xF8) == 0xF0) {
|
||||
// hopefully correct UTF-8
|
||||
if (*(ptr + 1) != '\0' && *(ptr + 2) != '\0' && *(ptr + 3) != '\0') {
|
||||
res = Reserve(self, 12);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
EscapeUtf8Range10000T10FFFF(self, &ptr);
|
||||
}
|
||||
|
||||
// corrupted UTF-8
|
||||
else {
|
||||
AppendChar(self, *ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// unicode range above 10ffff -- NOT IMPLEMENTED
|
||||
else {
|
||||
AppendChar(self, *ptr);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a new string buffer and initialize it
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -803,25 +499,112 @@ int TRI_AppendString2StringBuffer(TRI_string_buffer_t* self, char const* str,
|
|||
return AppendString(self, str, len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief appends characters but json-encode the null-terminated string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int AppendJsonEncoded(TRI_string_buffer_t* self, char const* src,
|
||||
size_t length, bool escapeForwardSlashes) {
|
||||
static char const EscapeTable[256] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E
|
||||
// F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r',
|
||||
'u',
|
||||
'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
'u',
|
||||
'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
'/', // 20
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
'\\', 0, 0, 0, // 50
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0, // 60~FF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0};
|
||||
|
||||
int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
|
||||
char const* src, bool escapeSlash) {
|
||||
char const* ptr = src;
|
||||
// reserve enough room for the whole string at once
|
||||
int res = Reserve(self, 6 * length + 2);
|
||||
|
||||
while (*ptr != '\0') {
|
||||
int res = AppendJsonEncodedValue(self, ptr, escapeSlash);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
AppendChar(self, '"');
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
uint8_t const* p = reinterpret_cast<uint8_t const*>(src);
|
||||
uint8_t const* e = p + length;
|
||||
while (p < e) {
|
||||
uint8_t c = *p;
|
||||
|
||||
if ((c & 0x80) == 0) {
|
||||
// check for control characters
|
||||
char esc = EscapeTable[c];
|
||||
|
||||
if (esc) {
|
||||
if (c != '/' || escapeForwardSlashes) {
|
||||
// escape forward slashes only when requested
|
||||
AppendChar(self, '\\');
|
||||
}
|
||||
AppendChar(self, static_cast<char>(esc));
|
||||
|
||||
if (esc == 'u') {
|
||||
uint16_t i1 = (((uint16_t)c) & 0xf0) >> 4;
|
||||
uint16_t i2 = (((uint16_t)c) & 0x0f);
|
||||
|
||||
AppendChar(self, '0');
|
||||
AppendChar(self, '0');
|
||||
AppendChar(self, static_cast<char>((i1 < 10) ? ('0' + i1) : ('A' + i1 - 10)));
|
||||
AppendChar(self, static_cast<char>((i2 < 10) ? ('0' + i2) : ('A' + i2 - 10)));
|
||||
}
|
||||
} else {
|
||||
AppendChar(self, static_cast<char>(c));
|
||||
}
|
||||
} else if ((c & 0xe0) == 0xc0) {
|
||||
// two-byte sequence
|
||||
if (p + 1 >= e) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(self->_current, reinterpret_cast<char const*>(p), 2);
|
||||
self->_current += 2;
|
||||
++p;
|
||||
} else if ((c & 0xf0) == 0xe0) {
|
||||
// three-byte sequence
|
||||
if (p + 2 >= e) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(self->_current, reinterpret_cast<char const*>(p), 3);
|
||||
self->_current += 3;
|
||||
p += 2;
|
||||
} else if ((c & 0xf8) == 0xf0) {
|
||||
// four-byte sequence
|
||||
if (p + 3 >= e) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(self->_current, reinterpret_cast<char const*>(p), 4);
|
||||
self->_current += 4;
|
||||
p += 3;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
++p;
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
AppendChar(self, '"');
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -831,20 +614,7 @@ int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
|
|||
int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
|
||||
char const* src, size_t length,
|
||||
bool escapeSlash) {
|
||||
char const* ptr = src;
|
||||
char const* end = src + length;
|
||||
|
||||
while (ptr < end) {
|
||||
int res = AppendJsonEncodedValue(self, ptr, escapeSlash);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
return AppendJsonEncoded(self, src, length, escapeSlash);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -229,13 +229,6 @@ static inline void TRI_AppendStringUnsafeStringBuffer(TRI_string_buffer_t* self,
|
|||
self->_current += str.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief appends characters but json-encode the null-terminated string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_AppendJsonEncodedStringStringBuffer(TRI_string_buffer_t* self,
|
||||
char const* str, bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief appends characters but json-encode the string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -791,15 +784,6 @@ class StringBuffer {
|
|||
/// @brief appends as json-encoded
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringBuffer& appendJsonEncoded(char const* str) {
|
||||
TRI_AppendJsonEncodedStringStringBuffer(&_buffer, str, true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief appends as json-encoded
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringBuffer& appendJsonEncoded(char const* str, size_t length) {
|
||||
TRI_AppendJsonEncodedStringStringBuffer(&_buffer, str, length, true);
|
||||
return *this;
|
||||
|
|
|
@ -78,27 +78,17 @@ static int StringifyJson(TRI_memory_zone_t* zone, TRI_string_buffer_t* buffer,
|
|||
|
||||
case TRI_JSON_STRING:
|
||||
case TRI_JSON_STRING_REFERENCE: {
|
||||
res = TRI_AppendCharStringBuffer(buffer, '\"');
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (object->_value._string.length > 0) {
|
||||
// optimisation for the empty string
|
||||
res = TRI_AppendJsonEncodedStringStringBuffer(
|
||||
buffer, object->_value._string.data,
|
||||
object->_value._string.length - 1, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
res = TRI_AppendString2StringBuffer(buffer, "\"\"", 2);
|
||||
}
|
||||
|
||||
res = TRI_AppendCharStringBuffer(buffer, '\"');
|
||||
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -46,6 +46,41 @@ void* memrchr(void const* block, int c, size_t size) {
|
|||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief memmem
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void* xmemmem(void const* haystack, size_t haystackLength,
|
||||
void const* needle, size_t needleLength) {
|
||||
if (haystackLength == 0 ||
|
||||
needleLength == 0 ||
|
||||
haystackLength < needleLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char const* n = static_cast<char const*>(needle);
|
||||
|
||||
if (needleLength == 1) {
|
||||
return memchr(const_cast<void*>(haystack), static_cast<int>(*n), haystackLength);
|
||||
}
|
||||
|
||||
char const* current = static_cast<char const*>(haystack);
|
||||
char const* end = static_cast<char const*>(haystack) + haystackLength - needleLength;
|
||||
|
||||
for (; current <= end; ++current) {
|
||||
if (*current == *n &&
|
||||
memcmp(needle, current, needleLength) == 0) {
|
||||
return const_cast<void*>(static_cast<void const*>(current));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the time of day
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
void* memrchr(void const* block, int c, size_t size);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief memmem
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
void* memmem(void const* haystack, size_t haystackLength, void const* needle, size_t needleLength);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the time of day
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue