void IniSetting::ParserCallback::traverseToSet(const String &key, const std::string& offset, Variant& value, Variant& cur_settings, const std::string& stopChar) { assert(stopChar == "@" || stopChar == ":"); assert(offset != stopChar); assert(cur_settings.isArray()); auto isSymlink = stopChar == ":"; auto start = offset.c_str(); auto p = start; auto& first(cur_settings.toArrRef().lvalAt(key)); forceToArray(first); Variant *setting = &first; String index; bool done = false; while (!done) { index = String(p); p += index.size() + 1; if (strcmp(p, stopChar.c_str()) != 0) { forceToArray(*setting); setting = &setting->toArrRef().lvalAt(index); } else { done = true; } } if (isSymlink) { setting->toArrRef().setRef(index, value); } else { setting->toArrRef().set(index, value); } }
void IniSetting::ParserCallback::onPopEntry( const std::string &key, const std::string &value, const std::string &offset, void *arg) { Variant *arr = (Variant*)arg; forceToArray(*arr); bool oEmpty = offset.empty(); // Substitution copy or symlink // Offset come in like: hhvm.a.b\0c\0@ // Check for `\0` because it is possible, although unlikely, to have // something like hhvm.a.b[c@]. Thus we wouldn't want to make a substitution. if (!oEmpty && (offset.size() == 1 || offset[offset.size() - 2] == '\0') && (offset.back() == '@' || offset.back() == ':')) { makeSettingSub(key, offset, value, *arr); } else { // Normal array value String skey(key); auto& hash = arr->toArrRef().lvalAt(skey); forceToArray(hash); if (!oEmpty) { // a[b] makeArray(hash, offset, value); } else { // a[] hash.toArrRef().append(value); } } }
static void _xml_add_to_info(XmlParser *parser, const String& nameStr) { if (parser->info.isNull()) { return; } forceToArray(parser->info); if (!parser->info.toCArrRef().exists(nameStr)) { parser->info.toArrRef().set(nameStr, Array::Create()); } auto& inner = parser->info.toArrRef().lvalAt(nameStr); forceToArray(inner).append(parser->curtag); parser->curtag++; }
void IniSetting::ParserCallback::onPopEntry( const std::string &key, const std::string &value, const std::string &offset, void *arg) { Variant *arr = (Variant*)arg; forceToArray(*arr); auto& hash = arr->toArrRef().lvalAt(String(key)); forceToArray(hash); if (!offset.empty()) { makeArray(hash, offset, value); } else { hash.toArrRef().append(value); } }
void ExecutionContext::registerShutdownFunction(const Variant& function, Array arguments, ShutdownType type) { Array callback = make_map_array(s_name, function, s_args, arguments); Variant& funcs = m_shutdowns.lvalAt(type); forceToArray(funcs).append(callback); }
void IniSetting::ParserCallback::makeArray(Variant& hash, const std::string& offset, const std::string& value) { assert(!offset.empty()); Variant *val = &hash; assert(val->isArray()); auto start = offset.c_str(); auto p = start; bool last = false; do { String index(p); last = p + index.size() >= start + offset.size(); // This is mandatory in case we have a nested array like: // hhvm.a[b][c][d] // b will be hash and an array already, but c and d might // not exist and will need to be made an array forceToArray(*val); val = &val->toArrRef().lvalAt(index); if (last) { *val = Variant(value); } else { p += index.size() + 1; } } while (!last); }
void IniSetting::ParserCallback::onEntry( const std::string &key, const std::string &value, void *arg) { Variant *arr = (Variant*)arg; String skey(key); Variant sval(value); forceToArray(*arr).set(skey, sval); }
bool ExecutionContext::removeShutdownFunction(const Variant& function, ShutdownType type) { bool ret = false; auto& funcs = forceToArray(m_shutdowns.lvalAt(type)); PackedArrayInit newFuncs(funcs.size()); for (ArrayIter iter(funcs); iter; ++iter) { if (!same(iter.second().toArray()[s_name], function)) { newFuncs.appendWithRef(iter.secondRef()); } else { ret = true; } } funcs = newFuncs.toArray(); return ret; }
Array TimeZone::GetAbbreviations() { Array ret; for (const timelib_tz_lookup_table *entry = timelib_timezone_abbreviations_list(); entry->name; entry++) { ArrayInit element(3, ArrayInit::Map{}); element.set(s_dst, (bool)entry->type); element.set(s_offset, entry->gmtoffset); if (entry->full_tz_name) { element.set(s_timezone_id, String(entry->full_tz_name, CopyString)); } else { element.set(s_timezone_id, uninit_null()); } auto& val = ret.lvalAt(String(entry->name)); forceToArray(val).append(element.toArray()); } return ret; }
Variant json_type_object_to_variant(json_object *new_obj, const bool assoc, const bool stable_maps, const bool collections) { struct json_object_iterator it, itEnd; json_object *jobj; Variant var, tmpvar; if (collections) { var = newobj<c_Map>(); } else if (assoc) { var = Array::Create(); } else { var = SystemLib::AllocStdClassObject(); } it = json_object_iter_begin(new_obj); itEnd = json_object_iter_end(new_obj); while (!json_object_iter_equal(&it, &itEnd)) { String key(json_object_iter_peek_name(&it), CopyString); jobj = json_object_iter_peek_value(&it); tmpvar = json_object_to_variant(jobj, assoc, stable_maps, collections); if (!assoc) { if (key.empty()) { var.getObjectData()->o_set(s_empty, tmpvar); } else { var.getObjectData()->o_set(key, tmpvar); } } else { if (collections) { auto keyTV = make_tv<KindOfString>(key.get()); collectionSet(var.getObjectData(), &keyTV, tmpvar.asCell()); } else { forceToArray(var).set(key, tmpvar); } } json_object_iter_next(&it); } return var; }
void DummySandbox::run() { TRACE(2, "DummySandbox::run\n"); RequestInfo *ti = RequestInfo::s_requestInfo.getNoCheck(); while (!m_stopped) { try { CLISession hphpSession; DSandboxInfo sandbox = m_proxy->getSandbox(); std::string msg; if (sandbox.valid()) { SourceRootInfo sri(sandbox.m_user, sandbox.m_name); if (sandbox.m_path.empty()) { sandbox.m_path = sri.path(); } if (!sri.sandboxOn()) { msg = "Invalid sandbox was specified. " "PHP files may not be loaded properly.\n"; } else { auto server = php_global_exchange(s__SERVER, init_null()); forceToArray(server); Array arr = server.toArrRef(); server.unset(); php_global_set(s__SERVER, sri.setServerVariables(std::move(arr))); } Debugger::RegisterSandbox(sandbox); g_context->setSandboxId(sandbox.id()); std::string doc = getStartupDoc(sandbox); if (!doc.empty()) { char cwd[PATH_MAX]; getcwd(cwd, sizeof(cwd)); Logger::Info("Start loading startup doc '%s', pwd = '%s'", doc.c_str(), cwd); bool error; std::string errorMsg; bool ret = hphp_invoke(g_context.getNoCheck(), doc, false, null_array, uninit_null(), "", "", error, errorMsg, true, false, true, RuntimeOption::EvalPreludePath); if (!ret || error) { msg += "Unable to pre-load " + doc; if (!errorMsg.empty()) { msg += ": " + errorMsg; } } Logger::Info("Startup doc " + doc + " loaded"); } } else { g_context->setSandboxId(m_proxy->getDummyInfo().id()); } if (!DebuggerHook::attach<HphpdHook>(ti)) { const char* fail = "Could not attach hphpd to request: another debugger" " is already attached."; Logger::Error("%s", fail); Debugger::InterruptSessionStarted(nullptr, fail); throw DebuggerClientAttachFailureException(); } { DebuggerDummyEnv dde; // This is really the entire point of having the dummy sandbox. This // fires the initial session started interrupt to the client after // it first attaches. Debugger::InterruptSessionStarted(nullptr, msg.c_str()); } // Blocking until Ctrl-C is issued by end user and DebuggerProxy cannot // find a real sandbox thread to handle it. { Lock lock(this); while (!m_stopped && m_signum != CmdSignal::SignalBreak) { wait(1); } if (m_stopped) { // stopped by worker thread break; } m_signum = CmdSignal::SignalNone; } } catch (const DebuggerClientExitException& e) { // stopped by the dummy sandbox thread itself break; } catch (const DebuggerException& e) { } } }
void IniSetting::ParserCallback::onEntry( const std::string &key, const std::string &value, void *arg) { Variant *arr = (Variant*)arg; forceToArray(*arr).set(String(key), Variant(value)); }
void DummySandbox::run() { TRACE(2, "DummySandbox::run\n"); ThreadInfo *ti = ThreadInfo::s_threadInfo.getNoCheck(); while (!m_stopped) { try { CLISession hphpSession; DSandboxInfo sandbox = m_proxy->getSandbox(); std::string msg; if (sandbox.valid()) { GlobalVariables *g = get_global_variables(); SourceRootInfo sri(sandbox.m_user, sandbox.m_name); if (sandbox.m_path.empty()) { sandbox.m_path = sri.path(); } if (!sri.sandboxOn()) { msg = "Invalid sandbox was specified. " "PHP files may not be loaded properly.\n"; } else { auto& server = tvAsVariant(g->nvGet(s__SERVER.get())); forceToArray(server); sri.setServerVariables(server.toArrRef()); } Debugger::RegisterSandbox(sandbox); g_context->setSandboxId(sandbox.id()); std::string doc = getStartupDoc(sandbox); if (!doc.empty()) { char cwd[PATH_MAX]; getcwd(cwd, sizeof(cwd)); Logger::Info("Start loading startup doc '%s', pwd = '%s'", doc.c_str(), cwd); bool error; std::string errorMsg; bool ret = hphp_invoke(g_context.getNoCheck(), doc, false, null_array, uninit_null(), "", "", error, errorMsg, true, false, true); if (!ret || error) { msg += "Unable to pre-load " + doc; if (!errorMsg.empty()) { msg += ": " + errorMsg; } } Logger::Info("Startup doc " + doc + " loaded"); } } else { g_context->setSandboxId(m_proxy->getDummyInfo().id()); } ti->m_reqInjectionData.setDebugger(true); { DebuggerDummyEnv dde; // This is really the entire point of having the dummy sandbox. This // fires the initial session started interrupt to the client after // it first attaches. Debugger::InterruptSessionStarted(nullptr, msg.c_str()); } // Blocking until Ctrl-C is issued by end user and DebuggerProxy cannot // find a real sandbox thread to handle it. { Lock lock(this); while (!m_stopped && m_signum != CmdSignal::SignalBreak) { wait(1); } if (m_stopped) { // stopped by worker thread break; } m_signum = CmdSignal::SignalNone; } } catch (const DebuggerClientExitException &e) { // stopped by the dummy sandbox thread itself break; } catch (const DebuggerException &e) { } } }