Array ClassInfo::GetConstants() { if (!s_loaded) Load(); Array res; Array dyn; { const ConstantMap &scm = s_systemFuncs->getConstants(); for (ConstantMap::const_iterator it = scm.begin(); it != scm.end(); ++it) { res.set(it->first, it->second->value); } } { const ConstantMap &ucm = s_userFuncs->getConstants(); for (ConstantMap::const_iterator it = ucm.begin(); it != ucm.end(); ++it) { res.set(it->first, it->second->value); } } if (s_hook) { dyn = s_hook->getConstants(); if (!dyn.isNull()) { res.merge(dyn); } } dyn = get_globals()->getDynamicConstants(); if (!dyn.isNull()) { res.merge(dyn); } return res; }
Variant f_stream_context_create(const Array& options /* = null_array */, const Array& params /* = null_array */) { if (!options.isNull() && !StreamContext::validateOptions(options)) { return false; } return Resource(NEWOBJ(StreamContext)(options, params)); }
Array ClassInfo::GetClasses(bool declaredOnly) { if (!s_loaded) Load(); Array ret; for (ClassMap::const_iterator iter = s_classes.begin(); iter != s_classes.end(); ++iter) { if (!declaredOnly || !(iter->second->m_attribute & IsVolatile)) { ret.append(iter->first); } } // This way, the order of newly declared classes can be more consistent // with PHP. if (declaredOnly) { Array classes = get_globals()->getVolatileClasses(); for (ArrayIter iter(classes); iter; ++iter) { ret.append(iter.first()); } } if (s_hook) { Array dyn = s_hook->getClasses(); if (!dyn.isNull()) { ret = ret.merge(dyn); } } return ret; }
bool ExecutionContext::callUserErrorHandler(const Exception &e, int64 errnum, bool swallowExceptions) { int errline = 0; String errfile; Array backtrace; const ExtendedException *ee = dynamic_cast<const ExtendedException*>(&e); if (ee) { ArrayPtr arr = ee->getBackTrace(); if (arr) { backtrace = *arr; Array top = backtrace.rvalAt(0); if (!top.isNull()) { errfile = top.rvalAt("file"); errline = top.rvalAt("line").toInt64(); } } } if (backtrace.isNull()) { backtrace = stackTraceToBackTrace(e.getStackTrace()); } bool retval = false; RequestData::Data *data = s_request_data->data; if (!data->systemExceptionHandlers.empty()) { // Avoid calling the user error handler recursively if (!data->insideUserHandler) { data->insideUserHandler = true; try { if (!same(f_call_user_func_array (data->systemExceptionHandlers.back(), CREATE_VECTOR6(errnum, String(e.getMessage()), errfile, errline, "", backtrace)), false)) { retval = true; } } catch (...) { data->insideUserHandler = false; if (!swallowExceptions) throw; } data->insideUserHandler = false; } } return retval; }
Array StreamContext::getParams() const { Array params = m_params; if (params.isNull()) { params = Array::Create(); } const String& options_key = String::FromCStr("options"); params.set(options_key, getOptions()); return params; }
Array CmdWhere::fetchStackTrace(DebuggerClient *client) { Array st = client->getStackTrace(); if (st.isNull()) { CmdWherePtr cmd = client->xend<CmdWhere>(this); st = cmd->m_stacktrace; client->setStackTrace(st); } return st; }
Variant f_stream_context_create(const Array& options /* = null_array */, const Array& params /* = null_array */) { if (!options.isNull() && !StreamContext::validateOptions(options)) { raise_warning("options should have the form " "[\"wrappername\"][\"optionname\"] = $value"); return Resource(NEWOBJ(StreamContext)(HPHP::null_array, HPHP::null_array)); } return Resource(NEWOBJ(StreamContext)(options, params)); }
bool same(const Variant& v1, const Array& v2) { bool null1 = v1.isNull(); bool null2 = v2.isNull(); if (null1 && null2) return true; if (null1 || null2) return false; if (!v1.isArray()) return false; auto const ad = v1.getArrayData(); return v2->equal(ad, true); }
bool BaseExecutionContext::callUserErrorHandler(const Exception &e, int errnum, bool swallowExceptions) { switch (getErrorState()) { case ExecutingUserHandler: case ErrorRaisedByUserHandler: return false; default: break; } if (!m_userErrorHandlers.empty() && (m_userErrorHandlers.back().second & errnum) != 0) { int errline = 0; String errfile; Array backtrace; const ExtendedException *ee = dynamic_cast<const ExtendedException*>(&e); if (ee) { ArrayPtr arr = ee->getBackTrace(); if (arr) { backtrace = *arr; Array top = backtrace.rvalAt(0); if (!top.isNull()) { errfile = top.rvalAt("file"); errline = top.rvalAt("line").toInt64(); } } } if (backtrace.isNull()) { backtrace = stackTraceToBackTrace(e.getStackTrace()); } try { ErrorStateHelper esh(this, ExecutingUserHandler); if (!same(f_call_user_func_array (m_userErrorHandlers.back().first, CREATE_VECTOR6(errnum, String(e.getMessage()), errfile, errline, "", backtrace)), false)) { return true; } } catch (...) { if (!swallowExceptions) throw; } } return false; }
Array CmdWhere::fetchStackTrace(DebuggerClient &client) { Array st = client.getStackTrace(); if (st.isNull()) { m_stackArgs = client.getDebuggerStackArgs(); CmdWherePtr cmd = client.xend<CmdWhere>(this); st = cmd->m_stacktrace; client.setStackTrace(st); } return st; }
Variant f_stream_context_get_default(const Array& options /* = null_array */) { Resource &resource = g_context->getStreamContext(); if (resource.isNull()) { resource = Resource(NEWOBJ(StreamContext)(Array::Create(), Array::Create())); g_context->setStreamContext(resource); } StreamContext *context = resource.getTyped<StreamContext>(); if (!options.isNull() && !f_stream_context_set_option0(context, options)) { return false; } return resource; }
Array ClassInfo::GetClassLike(unsigned mask, unsigned value) { assert(s_loaded); Array ret = Array::Create(); for (ClassMap::const_iterator iter = s_class_like.begin(); iter != s_class_like.end(); ++iter) { const ClassInfo *info = iter->second->getDeclared(); if (!info || (info->m_attribute & mask) != value) continue; ret.append(info->m_name); } if (value & IsInterface) { Array dyn = Unit::getInterfacesInfo(); if (!dyn.isNull()) { ret.merge(dyn); // De-dup values, then renumber (for aesthetics). ret = ArrayUtil::StringUnique(ret).toArrRef(); ret->renumber(); } } else if (value & IsTrait) { Array dyn = Unit::getTraitsInfo(); if (!dyn.isNull()) { ret.merge(dyn); // De-dup values, then renumber (for aesthetics). ret = ArrayUtil::StringUnique(ret).toArrRef(); ret->renumber(); } } else { Array dyn = Unit::getClassesInfo(); if (!dyn.isNull()) { ret.merge(dyn); // De-dup values, then renumber (for aesthetics). ret = ArrayUtil::StringUnique(ret).toArrRef(); ret->renumber(); } } return ret; }
Array CmdWhere::fetchStackTrace(DebuggerClient &client) { Array st = client.getStackTrace(); // Only grab a new stack trace if we don't have one cached, or if // the one cached does not match the type of stack trace being // requested. bool isAsync = m_type == KindOfWhereAsync; if (st.isNull() || (isAsync != client.isStackTraceAsync())) { m_stackArgs = client.getDebuggerClientStackArgs(); auto cmd = client.xend<CmdWhere>(this); st = cmd->m_stacktrace; client.setStackTrace(st, isAsync); } return st; }
ATTRIBUTE_NORETURN void raise_fatal_error(const char* msg, const Array& bt /* = null_array */, bool recoverable /* = false */, bool silent /* = false */, bool throws /* = true */) { if (RuntimeOption::PHP7_EngineExceptions && throws) { VMRegAnchor _; SystemLib::throwErrorObject(Variant(msg)); } auto ex = bt.isNull() && !recoverable ? FatalErrorException(msg) : FatalErrorException(msg, bt, recoverable); ex.setSilent(silent); throw ex; }
Array ClassInfo::GetInterfaces(bool declaredOnly) { if (!s_loaded) Load(); Array ret; for (ClassMap::const_iterator iter = s_interfaces.begin(); iter != s_interfaces.end(); ++iter) { if (!declaredOnly || iter->second->isDeclared()) { ret.append(iter->first); } } if (s_hook) { Array dyn = s_hook->getInterfaces(); if (!dyn.isNull()) { ret = ret.merge(dyn); } } return ret; }
Array ClassInfo::GetUserFunctions() { if (!s_loaded) Load(); Array ret = Array::Create(); if (s_userFuncs) { const MethodMap &methods = s_userFuncs->getMethods(); for (MethodMap::const_iterator iter = methods.begin(); iter != methods.end(); ++iter) { ret.append(iter->first); } } if (s_hook) { Array dyn = s_hook->getClasses(); if (!dyn.isNull()) { ret = ret.merge(dyn); } } return ret; }
void ExtendedLogger::Log(LogLevelType level, const Array& stackTrace, bool escape /* = true */, bool escapeMore /* = false */) { assert(!escapeMore || escape); ThreadData *threadData = s_threadData.get(); if (threadData->message != -1 && ++threadData->message > MaxMessagesPerRequest && MaxMessagesPerRequest >= 0) { return; } if (stackTrace.isNull()) return; if (UseLogFile) { FILE *f = Output ? Output : GetStandardOut(level); PrintStackTrace(f, stackTrace, escape, escapeMore); FILE *tf = threadData->log; if (tf) { PrintStackTrace(tf, stackTrace, escape, escapeMore); } } }
Array FrameInjection::GetBacktrace(bool skip /* = false */, bool withSelf /* = false */, bool withThis /* = true */) { Array bt = Array::Create(); FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (skip && t) { t = t->m_prev; } // This is used by onError with extended exceptions if (withSelf && t) { String filename = t->getFileName(); // If the top frame is not an extension function, and has actually been // entered (i.e. has a real line number) add it to the trace if (filename != "" && t->m_line != 0) { Array frame = Array::Create(); frame.set(s_file, filename, true); frame.set(s_line, t->m_line, true); bt.append(frame); } } Array sbt = bt; FrameInjection *st = t; while (t && (RuntimeOption::InjectedStackTraceLimit < 0 || bt.size() < RuntimeOption::InjectedStackTraceLimit)) { Array frame = t->getStackFrame(withSelf, withThis); if (frame.isNull()) return bt; bt.append(frame); t = t->m_prev; } if (!t) return bt; // The stack depth has exceeded the limit. Re-construct bt to include the // top and bottom frames. This is considered more useful in cases such as // infinite recursion. ASSERT(bt.size() == RuntimeOption::InjectedStackTraceLimit); int half = RuntimeOption::InjectedStackTraceLimit / 2; // start over, get the top half bt = sbt; t = st; while (t && bt.size() < half) { Array frame = t->getStackFrame(withSelf, withThis); if (frame.isNull()) assert(false); bt.append(frame); t = t->m_prev; } // then the bottom half std::vector<FrameInjection *> remainingFrames; while (t) { if (!t->m_prev && (t->m_flags & PseudoMain)) break; remainingFrames.push_back(t); t = t->m_prev; } int remaining = remainingFrames.size(); int omitted = remaining - half; assert(omitted >= 0); if (omitted > 0) { std::string tmp("(...) "); tmp += boost::lexical_cast<std::string>(omitted) + " omitted frame" + ((omitted > 1) ? "s" : ""); Array frame; frame.set(s_function, tmp); bt.append(frame); } for (int i = omitted; i < remaining; i++) { Array frame = remainingFrames[i]->getStackFrame(withSelf, withThis); if (frame.isNull()) assert(false); bt.append(frame); } return bt; }
Array FrameInjection::GetBacktrace(bool skip /* = false */, bool withSelf /* = false */, bool withThis /* = true */) { Array bt = Array::Create(); FrameInjection *t = ThreadInfo::s_threadInfo->m_top; if (skip && t) { t = t->m_prev; } // This is used by onError with extended exceptions if (withSelf && t) { String filename = t->getFileName(); // If the top frame is not an extension function, // add it to the trace if (filename != "") { Array frame = Array::Create(); frame.set(s_file, filename, true); frame.set(s_line, t->m_line, true); bt.append(frame); } } while (t) { Array frame = Array::Create(); if (t->m_prev) { String file = t->m_prev->getFileName(); if (!file.empty() && t->m_prev->m_line) { frame.set(s_file, file, true); frame.set(s_line, t->m_prev->m_line, true); } } else if (t->m_flags & PseudoMain) { // Stop at top, don't include top file break; } if (t->m_flags & PseudoMain) { frame.set(s_function, "include", true); frame.set(s_args, Array::Create(t->getFileName()), true); } else { const char *c = strstr(t->m_name, "::"); if (c) { frame.set(s_function, String(c + 2), true); frame.set(s_class, t->m_class->copy(), true); if (!t->m_object.isNull()) { if (withThis) { frame.set(s_object, t->m_object, true); } frame.set(s_type, "->", true); } else { frame.set(s_type, "::", true); } } else { frame.set(s_function, t->m_name, true); } Array args = t->getArgs(); if (!args.isNull()) { frame.set(s_args, args, true); } else { frame.set(s_args, Array::Create(), true); } } bt.append(frame); t = t->m_prev; } return bt; }
bool TestCppBase::TestArray() { // Array::Create(), Array constructors and informational { Array arr; VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(arr.isNull()); arr = Array::Create(); VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(!arr.isNull()); arr = Array::Create(0); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0].toInt32() == 0); arr = Array::Create("test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(equal(arr[0], String("test"))); Array arrCopy = arr; arr = Array::Create(arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0].toArray().size() == 1); VS(arr[0], arrCopy); arr = Array::Create("name", 1); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[s_name].toInt32() == 1); arr = Array::Create(s_name, "test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(equal(arr[s_name], String("test"))); arrCopy = arr; arr = Array::Create(s_name, arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VS(arr[s_name], arrCopy); VERIFY(arr[s_name].toArray().size() == 1); } // iteration { Array arr = make_map_array("n1", "v1", "n2", "v2"); int i = 0; for (ArrayIter iter = arr.begin(); iter; ++iter, ++i) { if (i == 0) { VERIFY(equal(iter.first(), String("n1"))); VERIFY(equal(iter.second(), String("v1"))); } else { VERIFY(equal(iter.first(), String("n2"))); VERIFY(equal(iter.second(), String("v2"))); } } VERIFY(i == 2); } static const StaticString s_Array("Array"); // conversions { Array arr0; VERIFY(arr0.toBoolean() == false); VERIFY(arr0.toByte() == 0); VERIFY(arr0.toInt16() == 0); VERIFY(arr0.toInt32() == 0); VERIFY(arr0.toInt64() == 0); VERIFY(arr0.toDouble() == 0.0); VERIFY(arr0.toString().empty()); Array arr1 = Array::Create("test"); VERIFY(arr1.toBoolean() == true); VERIFY(arr1.toByte() == 1); VERIFY(arr1.toInt16() == 1); VERIFY(arr1.toInt32() == 1); VERIFY(arr1.toInt64() == 1); VERIFY(arr1.toDouble() == 1.0); VERIFY(arr1.toString() == s_Array); } // offset { Array arr; arr.set(0, "v1"); arr.set(1, "v2"); VS(arr, make_packed_array("v1", "v2")); } { Array arr; arr.set(s_n1, "v1"); arr.set(s_n2, "v2"); VS(arr, make_map_array("n1", "v1", "n2", "v2")); } { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VS(arr, make_packed_array("v1", "v2")); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VS(arr, make_map_array("n1", "v1", "n2", "v2")); } { Array arr; Variant name = "name"; arr.lvalAt(name) = String("value"); VS(arr, make_map_array("name", "value")); } { Array arr; arr.lvalAt(1) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant(1.5)) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(s_1) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant("1")) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } // membership { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VERIFY(arr.exists(0)); arr.remove(0); VERIFY(!arr.exists(0)); VS(arr, Array::Create(1, "v2")); arr.append("v3"); VS(arr, make_map_array(1, "v2", 2, "v3")); } { static const StaticString s_0("0"); Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(String(s_0)); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant("0")); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant("0"))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant(0.5))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(Variant()) = 123; VERIFY(arr.exists(empty_string_ref)); arr.remove(Variant()); VERIFY(!arr.exists(empty_string_ref)); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VERIFY(arr.exists(s_n1)); arr.remove(s_n1); VERIFY(!arr.exists(s_n1)); VS(arr, Array::Create(s_n2, "v2")); arr.append("v3"); VS(arr, make_map_array("n2", "v2", 0, "v3")); } { Array arr; arr.lvalAt() = String("test"); VS(arr, make_packed_array("test")); } { Array arr; arr.lvalAt(s_name) = String("value"); VERIFY(arr.exists(s_name)); } { Array arr; arr.lvalAt(1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(s_1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant(1.5)) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant("1")) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } // merge { Array arr = Array::Create(0) + Array::Create(1); VS(arr, Array::Create(0)); arr += make_packed_array(0, 1); VS(arr, make_packed_array(0, 1)); arr = Array::Create(0).merge(Array::Create(1)); VS(arr, make_packed_array(0, 1)); arr = arr.merge(make_packed_array(0, 1)); VS(arr, make_packed_array(0, 1, 0, 1)); arr = Array::Create("s0").merge(Array::Create("s1")); VS(arr, make_packed_array("s0", "s1")); arr = Array::Create("n0", "s0") + Array::Create("n1", "s1"); VS(arr, make_map_array("n0", "s0", "n1", "s1")); arr += make_map_array("n0", "s0", "n1", "s1"); VS(arr, make_map_array("n0", "s0", "n1", "s1")); arr = Array::Create("n0", "s0").merge(Array::Create("n1", "s1")); VS(arr, make_map_array("n0", "s0", "n1", "s1")); Array arrX = make_map_array("n0", "s2", "n1", "s3"); arr = arr.merge(arrX); VS(arr, make_map_array("n0", "s2", "n1", "s3")); } { Array arr = make_map_array(0, "a", 1, "b"); VERIFY(arr->isVectorData()); } { Array arr = make_map_array(1, "a", 0, "b"); VERIFY(!arr->isVectorData()); } { Array arr = make_map_array(1, "a", 2, "b"); VERIFY(!arr->isVectorData()); } { Array arr = make_map_array(1, "a"); arr.set(0, "b"); VERIFY(!arr->isVectorData()); } return Count(true); }
bool TestCppBase::TestArray() { // Array::Create(), Array constructors and informational { Array arr; VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(arr.isNull()); arr = Array::Create(); VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(!arr.isNull()); arr = Array::Create(0); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY((int)arr[0] == 0); VS(arr, Array(ArrayInit(1).set(0).create())); arr = Array::Create("test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0] == "test"); VS(arr, Array(ArrayInit(1).set("test").create())); Array arrCopy = arr; arr = Array::Create(arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0].toArray().size() == 1); VS(arr[0], arrCopy); VS(arr, Array(ArrayInit(1).set(arrCopy).create())); arr = Array::Create("name", 1); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY((int)arr[s_name] == 1); VS(arr, Array(ArrayInit(1).set(s_name, 1).create())); arr = Array::Create(s_name, "test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[s_name] == "test"); VS(arr, Array(ArrayInit(1).set(s_name, "test").create())); arrCopy = arr; arr = Array::Create(s_name, arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VS(arr[s_name], arrCopy); VERIFY(arr[s_name].toArray().size() == 1); VS(arr, Array(ArrayInit(1).set(s_name, arrCopy).create())); } // iteration { Array arr = CREATE_MAP2("n1", "v1", "n2", "v2"); int i = 0; for (ArrayIter iter = arr.begin(); iter; ++iter, ++i) { if (i == 0) { VERIFY(iter.first() == "n1"); VERIFY(iter.second() == "v1"); } else { VERIFY(iter.first() == "n2"); VERIFY(iter.second() == "v2"); } } VERIFY(i == 2); } /* TODO: fix this { Variant arr = CREATE_MAP2("n1", "v1", "n2", "v2"); arr.escalate(); for (ArrayIterPtr iter = arr.begin(arr, true); !iter->end(); iter->next()){ unset(arr.lvalAt(iter->first())); } VS(arr, Array::Create()); } */ // conversions { Array arr0; VERIFY(arr0.toBoolean() == false); VERIFY(arr0.toByte() == 0); VERIFY(arr0.toInt16() == 0); VERIFY(arr0.toInt32() == 0); VERIFY(arr0.toInt64() == 0); VERIFY(arr0.toDouble() == 0.0); VERIFY(arr0.toString() == ""); Array arr1 = Array::Create("test"); VERIFY(arr1.toBoolean() == true); VERIFY(arr1.toByte() == 1); VERIFY(arr1.toInt16() == 1); VERIFY(arr1.toInt32() == 1); VERIFY(arr1.toInt64() == 1); VERIFY(arr1.toDouble() == 1.0); VERIFY(arr1.toString() == "Array"); } // offset { Array arr; arr.set(0, "v1"); arr.set(1, "v2"); VS(arr, CREATE_VECTOR2("v1", "v2")); } { Array arr; arr.set(s_n1, "v1"); arr.set(s_n2, "v2"); VS(arr, CREATE_MAP2("n1", "v1", "n2", "v2")); } { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VS(arr, CREATE_VECTOR2("v1", "v2")); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VS(arr, CREATE_MAP2("n1", "v1", "n2", "v2")); } { Array arr; Variant name = "name"; arr.lvalAt(name) = String("value"); VS(arr, CREATE_MAP1("name", "value")); } { Array arr; arr.lvalAt(s_A) = 10; arr.lvalAt(s_A)++; VS(arr[s_A], 11); } { Array arr; arr.lvalAt(1) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant(1.5)) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(s_1) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant("1")) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } // membership { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VERIFY(arr.exists(0)); arr.remove(0); VERIFY(!arr.exists(0)); VS(arr, Array::Create(1, "v2")); arr.append("v3"); VS(arr, CREATE_MAP2(1, "v2", 2, "v3")); } { static const StaticString s_0("0"); Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(String(s_0)); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant("0")); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant("0"))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant(0.5))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(Variant()) = 123; VERIFY(arr.exists(empty_string)); arr.remove(Variant()); VERIFY(!arr.exists(empty_string)); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VERIFY(arr.exists(s_n1)); arr.remove(s_n1); VERIFY(!arr.exists(s_n1)); VS(arr, Array::Create(s_n2, "v2")); arr.append("v3"); VS(arr, CREATE_MAP2("n2", "v2", 0, "v3")); } { Array arr; arr.lvalAt() = String("test"); VS(arr, CREATE_VECTOR1("test")); } { Array arr; arr.lvalAt(s_name) = String("value"); VERIFY(arr.exists(s_name)); } { Array arr; arr.lvalAt(1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(s_1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(1.5) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant(1.5)) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant("1")) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } // merge { Array arr = Array::Create(0) + Array::Create(1); VS(arr, Array::Create(0)); arr += CREATE_VECTOR2(0, 1); VS(arr, CREATE_VECTOR2(0, 1)); arr = Array::Create(0).merge(Array::Create(1)); VS(arr, CREATE_VECTOR2(0, 1)); arr = arr.merge(CREATE_VECTOR2(0, 1)); VS(arr, CREATE_VECTOR4(0, 1, 0, 1)); arr = Array::Create("s0").merge(Array::Create("s1")); VS(arr, CREATE_VECTOR2("s0", "s1")); arr = Array::Create("n0", "s0") + Array::Create("n1", "s1"); VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1")); arr += CREATE_MAP2("n0", "s0", "n1", "s1"); VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1")); arr = Array::Create("n0", "s0").merge(Array::Create("n1", "s1")); VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1")); Array arrX = CREATE_MAP2("n0", "s2", "n1", "s3"); arr = arr.merge(arrX); VS(arr, CREATE_MAP2("n0", "s2", "n1", "s3")); } // slice { Array arr = CREATE_VECTOR2("test1", "test2"); Array sub = arr.slice(1, 1, true); VS(sub, CREATE_MAP1(1, "test2")); } { Array arr = CREATE_VECTOR2("test1", "test2"); Array sub = arr.slice(1, 1, false); VS(sub, CREATE_VECTOR1("test2")); } { Array arr = CREATE_MAP2("n1", "test1", "n2", "test2"); Array sub = arr.slice(1, 1, true); VS(sub, CREATE_MAP1("n2", "test2")); } { Array arr = CREATE_MAP2("n1", "test1", "n2", "test2"); Array sub = arr.slice(1, 1, false); VS(sub, CREATE_MAP1("n2", "test2")); } // escalation { Array arr; lval(arr.lvalAt(0)).lvalAt(0) = 1.2; VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Array arr; lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2))); } { Array arr = Array::Create(); lval(arr.lvalAt(0)).lvalAt(0) = 1.2; VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Array arr = Array::Create(); lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2))); } { Array arr = Array::Create("test"); arr.lvalAt(0) = CREATE_VECTOR1(1.2); VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Array arr = Array::Create("test"); lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP2(0, "test", s_name, CREATE_VECTOR1(1.2))); } { Array arr = Array::Create(); arr.append("apple"); arr.set(2, "pear"); VS(arr[2], "pear"); } { Array arr = CREATE_MAP2(0, "a", 1, "b"); VERIFY(arr->isVectorData()); } { Array arr = CREATE_MAP2(1, "a", 0, "b"); VERIFY(!arr->isVectorData()); } { Array arr = CREATE_MAP2(1, "a", 2, "b"); VERIFY(!arr->isVectorData()); } { Array arr = CREATE_MAP1(1, "a"); arr.set(0, "b"); VERIFY(!arr->isVectorData()); } return Count(true); }
/** * New sprintf implementation for PHP. * * Modifiers: * * " " pad integers with spaces * "-" left adjusted field * n field size * "."n precision (floats only) * "+" Always place a sign (+ or -) in front of a number * * Type specifiers: * * "%" literal "%", modifiers are ignored. * "b" integer argument is printed as binary * "c" integer argument is printed as a single character * "d" argument is an integer * "f" the argument is a float * "o" integer argument is printed as octal * "s" argument is a string * "x" integer argument is printed as lowercase hexadecimal * "X" integer argument is printed as uppercase hexadecimal */ char *string_printf(const char *format, int len, CArrRef args, int *outlen) { Array vargs = args; if (!vargs.isNull() && !vargs->isVectorData()) { vargs = Array::Create(); for (ArrayIter iter(args); iter; ++iter) { vargs.append(iter.second()); } } if (len == 0) { return strdup(""); } int size = 240; char *result = (char *)malloc(size); int outpos = 0; int argnum = 0, currarg = 1; for (int inpos = 0; inpos < len; ++inpos) { char ch = format[inpos]; int expprec = 0; if (ch != '%') { appendchar(&result, &outpos, &size, ch); continue; } if (format[inpos + 1] == '%') { appendchar(&result, &outpos, &size, '%'); inpos++; continue; } /* starting a new format specifier, reset variables */ int alignment = ALIGN_RIGHT; int adjusting = 0; char padding = ' '; int always_sign = 0; int width, precision; inpos++; /* skip the '%' */ ch = format[inpos]; if (isascii(ch) && !isalpha(ch)) { /* first look for argnum */ int temppos = inpos; while (isdigit((int)format[temppos])) temppos++; if (format[temppos] == '$') { argnum = getnumber(format, &inpos); if (argnum <= 0) { free(result); throw_invalid_argument("argnum: must be greater than zero"); return nullptr; } inpos++; /* skip the '$' */ } else { argnum = currarg++; } /* after argnum comes modifiers */ for (;; inpos++) { ch = format[inpos]; if (ch == ' ' || ch == '0') { padding = ch; } else if (ch == '-') { alignment = ALIGN_LEFT; /* space padding, the default */ } else if (ch == '+') { always_sign = 1; } else if (ch == '\'') { padding = format[++inpos]; } else { break; } } ch = format[inpos]; /* after modifiers comes width */ if (isdigit(ch)) { if ((width = getnumber(format, &inpos)) < 0) { free(result); throw_invalid_argument("width: must be greater than zero " "and less than %d", INT_MAX); return nullptr; } adjusting |= ADJ_WIDTH; } else { width = 0; } ch = format[inpos]; /* after width and argnum comes precision */ if (ch == '.') { ch = format[++inpos]; if (isdigit((int)ch)) { if ((precision = getnumber(format, &inpos)) < 0) { free(result); throw_invalid_argument("precision: must be greater than zero " "and less than %d", INT_MAX); return nullptr; } ch = format[inpos]; adjusting |= ADJ_PRECISION; expprec = 1; } else { precision = 0; } } else { precision = 0; } } else { width = precision = 0; argnum = currarg++; } if (argnum > vargs.size()) { free(result); throw_invalid_argument("arguments: (too few)"); return nullptr; } if (ch == 'l') { ch = format[++inpos]; } /* now we expect to find a type specifier */ Variant tmp = vargs[argnum-1]; switch (ch) { case 's': { String s = tmp.toString(); appendstring(&result, &outpos, &size, s.c_str(), width, precision, padding, alignment, s.size(), 0, expprec, 0); break; } case 'd': appendint(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, always_sign); break; case 'u': appenduint(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment); break; case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': appenddouble(&result, &outpos, &size, tmp.toDouble(), width, padding, alignment, precision, adjusting, ch, always_sign); break; case 'c': appendchar(&result, &outpos, &size, tmp.toByte()); break; case 'o': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 3, hexchars, expprec); break; case 'x': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 4, hexchars, expprec); break; case 'X': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 4, HEXCHARS, expprec); break; case 'b': append2n(&result, &outpos, &size, tmp.toInt64(), width, padding, alignment, 1, hexchars, expprec); break; case '%': appendchar(&result, &outpos, &size, '%'); break; default: break; } } /* possibly, we have to make sure we have room for the terminating null? */ result[outpos]=0; if (outlen) *outlen = outpos; return result; }
Array FrameInjection::getStackFrame(bool withSelf, bool withThis) { Array frame = Array::Create(); if (m_prev) { String file = m_prev->getFileName(); if (!file.empty() && m_prev->m_line) { frame.set(s_file, file, true); frame.set(s_line, m_prev->m_line, true); } } else if (m_flags & PseudoMain) { // Stop at top, don't include top file return Array(); } if (m_flags & PseudoMain) { frame.set(s_function, "include", true); frame.set(s_args, Array::Create(getFileName()), true); } else { const char *c = strstr(m_name, "::"); const char *f = m_name; if (c) { f = c + 2; frame.set(s_class, getClassName()->copy(), true); if (ObjectData *obj = getObjectV()) { if (withThis) { frame.set(s_object, Object(obj), true); } frame.set(s_type, "->", true); } else { frame.set(s_type, "::", true); } } ASSERT(f); switch (f[0]) { case ParserBase::CharClosure: frame.set(s_function, s_closureBrackets, true); break; case ParserBase::CharContinuationFromClosure: frame.set(s_function, s_closureGenBrackets, true); break; default: if (const char *c = strstr(f, "$$")) { frame.set(s_function, String(f, c - f, CopyString), true); } else { if (isEvalFrame()) { frame.set(s_function, String(f, CopyString), true); } else { frame.set(s_function, f, true); } } break; } Array args = getArgs(); if (!args.isNull()) { frame.set(s_args, args, true); } else { frame.set(s_args, Array::Create(), true); } } return frame; }