Improved all axpect of tracing / forcing arrays
Improved ui and tree export
This commit is contained in:
@@ -64,16 +64,34 @@ static void EscapeJson(const char8 *src, StreamString &dst) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool SuffixMatch(const char8 *target, const char8 *pattern) {
|
||||
uint32 tLen = StringHelper::Length(target);
|
||||
uint32 pLen = StringHelper::Length(pattern);
|
||||
if (pLen > tLen)
|
||||
// Returns true if `str` ends with `suffix` at a word boundary (i.e. the char
|
||||
// immediately before the match is '.', or the match covers the entire string).
|
||||
static bool SuffixMatch(const char8 *str, const char8 *suffix) {
|
||||
uint32 sLen = StringHelper::Length(str);
|
||||
uint32 sufLen = StringHelper::Length(suffix);
|
||||
if (sufLen > sLen)
|
||||
return false;
|
||||
const char8 *suffix = target + (tLen - pLen);
|
||||
if (StringHelper::Compare(suffix, pattern) == 0) {
|
||||
if (tLen == pLen || *(suffix - 1) == '.')
|
||||
return true;
|
||||
}
|
||||
const char8 *tail = str + (sLen - sufLen);
|
||||
if (StringHelper::Compare(tail, suffix) != 0)
|
||||
return false;
|
||||
return (sLen == sufLen || *(tail - 1u) == '.');
|
||||
}
|
||||
|
||||
// Match a stored alias against a user-supplied name.
|
||||
// Three cases are tried in order:
|
||||
// 1. Exact match ("App.DS.Sig" == "App.DS.Sig")
|
||||
// 2. Alias is longer (alias "App.DS.Sig" ends with user name "Sig")
|
||||
// → user used a short / unqualified name in the command.
|
||||
// 3. User name is longer (user name "App.GAM.In.Sig" ends with alias "GAM.In.Sig")
|
||||
// → alias was registered with a short fallback path (FindByNameRecursive
|
||||
// failed during broker init) but the client uses the full ORD path.
|
||||
static bool AliasMatch(const char8 *aliasName, const char8 *userName) {
|
||||
if (StringHelper::Compare(aliasName, userName) == 0)
|
||||
return true;
|
||||
if (SuffixMatch(aliasName, userName)) // case 2: alias ⊇ userName
|
||||
return true;
|
||||
if (SuffixMatch(userName, aliasName)) // case 3: userName ⊇ alias
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -286,7 +304,21 @@ void DebugServiceBase::ProcessSignal(DebugSignalInfo *signalInfo, uint32 size,
|
||||
if (signalInfo == NULL_PTR(DebugSignalInfo *))
|
||||
return;
|
||||
if (signalInfo->isForcing) {
|
||||
memcpy(signalInfo->memoryAddress, signalInfo->forcedValue, size);
|
||||
uint32 nEl = signalInfo->numberOfElements;
|
||||
if (nEl <= 1u) {
|
||||
// Scalar — single memcpy.
|
||||
memcpy(signalInfo->memoryAddress, signalInfo->forcedValue, size);
|
||||
} else {
|
||||
// Array — copy only the elements whose bit is set in forcedMask.
|
||||
uint32 elemBytes = size / nEl;
|
||||
for (uint32 e = 0u; e < nEl; e++) {
|
||||
if (signalInfo->forcedMask[e >> 3u] & (uint8)(1u << (e & 7u))) {
|
||||
memcpy((uint8 *)signalInfo->memoryAddress + e * elemBytes,
|
||||
signalInfo->forcedValue + e * elemBytes,
|
||||
elemBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (signalInfo->isTracing) {
|
||||
Atomic::Add((volatile int32 *)&signalInfo->decimationCounter, 1);
|
||||
@@ -352,14 +384,39 @@ void DebugServiceBase::ConsumeStepIfNeeded(const char8 *gamName,
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
uint32 DebugServiceBase::ForceSignal(const char8 *name, const char8 *valueStr) {
|
||||
// Parse optional array-element suffix: "SignalName[idx]" → baseName + elemIdx.
|
||||
// elemIdx == -1 means "force all elements".
|
||||
const char8 *bracketPos = StringHelper::SearchChar(name, '[');
|
||||
StreamString baseName;
|
||||
int32 elemIdx = -1;
|
||||
|
||||
if (bracketPos != NULL_PTR(const char8 *)) {
|
||||
uint32 baseLen = (uint32)(bracketPos - name);
|
||||
(void)baseName.Write(name, baseLen);
|
||||
const char8 *closePos =
|
||||
StringHelper::SearchChar(bracketPos + 1u, ']');
|
||||
if (closePos != NULL_PTR(const char8 *)) {
|
||||
uint32 idxLen = (uint32)(closePos - bracketPos - 1u);
|
||||
StreamString idxStr;
|
||||
(void)idxStr.Write(bracketPos + 1u, idxLen);
|
||||
uint32 parsed = 0u;
|
||||
AnyType iv(UnsignedInteger32Bit, 0u, &parsed);
|
||||
AnyType is_src(CharString, 0u, idxStr.Buffer());
|
||||
if (TypeConvert(iv, is_src))
|
||||
elemIdx = (int32)parsed;
|
||||
}
|
||||
} else {
|
||||
baseName = name;
|
||||
}
|
||||
const char8 *effectiveName = baseName.Buffer();
|
||||
|
||||
mutex.FastLock();
|
||||
uint32 count = 0u;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == name ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), name)) {
|
||||
DebugSignalInfo *s = signals[aliases[i].signalIndex];
|
||||
uint32 elemBytes = (uint32)(s->type.numberOfBits) / 8u;
|
||||
uint32 totalBytes = elemBytes * s->numberOfElements;
|
||||
if (AliasMatch(aliases[i].name.Buffer(), effectiveName)) {
|
||||
DebugSignalInfo *s = signals[aliases[i].signalIndex];
|
||||
uint32 elemBytes = (uint32)(s->type.numberOfBits) / 8u;
|
||||
uint32 totalBytes = elemBytes * s->numberOfElements;
|
||||
if (elemBytes == 0u || totalBytes > (uint32)sizeof(s->forcedValue)) {
|
||||
REPORT_ERROR_STATIC(
|
||||
ErrorManagement::Warning,
|
||||
@@ -369,9 +426,27 @@ uint32 DebugServiceBase::ForceSignal(const char8 *name, const char8 *valueStr) {
|
||||
continue;
|
||||
}
|
||||
s->isForcing = true;
|
||||
AnyType dest(s->type, 0u, s->forcedValue);
|
||||
AnyType source(CharString, 0u, valueStr);
|
||||
(void)TypeConvert(dest, source);
|
||||
|
||||
if (elemIdx >= 0 && (uint32)elemIdx < s->numberOfElements) {
|
||||
// Force a single element — write to its slot and set its mask bit.
|
||||
uint8 *dest = (uint8 *)s->forcedValue + (uint32)elemIdx * elemBytes;
|
||||
AnyType dv(s->type, 0u, (void *)dest);
|
||||
AnyType sv(CharString, 0u, valueStr);
|
||||
(void)TypeConvert(dv, sv);
|
||||
s->forcedMask[(uint32)elemIdx >> 3u] |= (uint8)(1u << ((uint32)elemIdx & 7u));
|
||||
} else {
|
||||
// Force all elements to the same value — convert once, replicate, set all bits.
|
||||
AnyType dv(s->type, 0u, s->forcedValue);
|
||||
AnyType sv(CharString, 0u, valueStr);
|
||||
(void)TypeConvert(dv, sv);
|
||||
for (uint32 k = 1u; k < s->numberOfElements; k++) {
|
||||
memcpy(s->forcedValue + k * elemBytes, s->forcedValue, elemBytes);
|
||||
}
|
||||
uint32 fullBytes = s->numberOfElements / 8u;
|
||||
uint32 remBits = s->numberOfElements % 8u;
|
||||
memset(s->forcedMask, 0xFF, fullBytes);
|
||||
if (remBits > 0u) s->forcedMask[fullBytes] = (uint8)((1u << remBits) - 1u);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -381,12 +456,48 @@ uint32 DebugServiceBase::ForceSignal(const char8 *name, const char8 *valueStr) {
|
||||
}
|
||||
|
||||
uint32 DebugServiceBase::UnforceSignal(const char8 *name) {
|
||||
// Parse optional "[idx]" suffix. If present, clear only that element's bit;
|
||||
// if absent, clear all bits and the isForcing flag entirely.
|
||||
const char8 *bracketPos = StringHelper::SearchChar(name, '[');
|
||||
StreamString baseName;
|
||||
int32 elemIdx = -1;
|
||||
|
||||
if (bracketPos != NULL_PTR(const char8 *)) {
|
||||
uint32 baseLen = (uint32)(bracketPos - name);
|
||||
(void)baseName.Write(name, baseLen);
|
||||
const char8 *closePos = StringHelper::SearchChar(bracketPos + 1u, ']');
|
||||
if (closePos != NULL_PTR(const char8 *)) {
|
||||
uint32 idxLen = (uint32)(closePos - bracketPos - 1u);
|
||||
StreamString idxStr;
|
||||
(void)idxStr.Write(bracketPos + 1u, idxLen);
|
||||
uint32 parsed = 0u;
|
||||
AnyType iv(UnsignedInteger32Bit, 0u, &parsed);
|
||||
AnyType is_src(CharString, 0u, idxStr.Buffer());
|
||||
if (TypeConvert(iv, is_src)) elemIdx = (int32)parsed;
|
||||
}
|
||||
} else {
|
||||
baseName = name;
|
||||
}
|
||||
const char8 *effectiveName = baseName.Buffer();
|
||||
|
||||
mutex.FastLock();
|
||||
uint32 count = 0u;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == name ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), name)) {
|
||||
signals[aliases[i].signalIndex]->isForcing = false;
|
||||
if (AliasMatch(aliases[i].name.Buffer(), effectiveName)) {
|
||||
DebugSignalInfo *s = signals[aliases[i].signalIndex];
|
||||
if (elemIdx >= 0 && (uint32)elemIdx < s->numberOfElements) {
|
||||
// Clear just this element's force bit.
|
||||
s->forcedMask[(uint32)elemIdx >> 3u] &= (uint8)(~(1u << ((uint32)elemIdx & 7u)));
|
||||
// Deactivate forcing entirely if no bits remain.
|
||||
uint32 numBytes = (s->numberOfElements + 7u) / 8u;
|
||||
bool anySet = false;
|
||||
for (uint32 b = 0u; b < numBytes && !anySet; b++) anySet = (s->forcedMask[b] != 0u);
|
||||
if (!anySet) s->isForcing = false;
|
||||
} else {
|
||||
// Unforce all elements.
|
||||
memset(s->forcedMask, 0, sizeof(s->forcedMask));
|
||||
s->isForcing = false;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -400,8 +511,7 @@ uint32 DebugServiceBase::TraceSignal(const char8 *name, bool enable,
|
||||
mutex.FastLock();
|
||||
uint32 count = 0u;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == name ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), name)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), name)) {
|
||||
DebugSignalInfo *s = signals[aliases[i].signalIndex];
|
||||
s->isTracing = enable;
|
||||
s->decimationFactor = decimation;
|
||||
@@ -419,8 +529,7 @@ uint32 DebugServiceBase::SetBreak(const char8 *name, uint8 op,
|
||||
mutex.FastLock();
|
||||
uint32 count = 0u;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == name ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), name)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), name)) {
|
||||
DebugSignalInfo *s = signals[aliases[i].signalIndex];
|
||||
s->breakThreshold = threshold;
|
||||
s->breakOp = op;
|
||||
@@ -437,8 +546,7 @@ uint32 DebugServiceBase::ClearBreak(const char8 *name) {
|
||||
mutex.FastLock();
|
||||
uint32 count = 0u;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == name ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), name)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), name)) {
|
||||
signals[aliases[i].signalIndex]->breakOp = BREAK_OFF;
|
||||
count++;
|
||||
}
|
||||
@@ -454,8 +562,7 @@ bool DebugServiceBase::IsInstrumented(const char8 *fullPath, bool &traceable,
|
||||
mutex.FastLock();
|
||||
bool found = false;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == fullPath ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), fullPath)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), fullPath)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -517,8 +624,7 @@ uint32 DebugServiceBase::RegisterMonitorSignal(const char8 *path,
|
||||
m.internalID = 0x80000000u | monitoredSignals.GetNumberOfElements();
|
||||
// Re-use existing brokered signal ID if available
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == path ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), path)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), path)) {
|
||||
m.internalID = signals[aliases[i].signalIndex]->internalID;
|
||||
break;
|
||||
}
|
||||
@@ -652,8 +758,7 @@ void DebugServiceBase::GetSignalValue(const char8 *name, StreamString &out) {
|
||||
mutex.FastLock();
|
||||
DebugSignalInfo *sig = NULL_PTR(DebugSignalInfo *);
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == name ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), name)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), name)) {
|
||||
sig = signals[aliases[i].signalIndex];
|
||||
break;
|
||||
}
|
||||
@@ -809,14 +914,156 @@ void DebugServiceBase::BuildDiscoverCache() {
|
||||
}
|
||||
|
||||
void DebugServiceBase::BuildTreeCache() {
|
||||
treeCacheValid = false;
|
||||
treeCache = "";
|
||||
treeCache += "{\"Name\":\"Root\",\"Class\":\"ObjectRegistryDatabase\","
|
||||
"\"Children\":[\n";
|
||||
(void)ExportTree(ObjectRegistryDatabase::Instance(), treeCache,
|
||||
NULL_PTR(const char8 *));
|
||||
treeCache += "\n]}\nOK TREE\n";
|
||||
treeCacheValid = true;
|
||||
// No-op: tree is now served per-node via ExportTreeNode.
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ExportTreeNode — serve one level of the object tree
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void DebugServiceBase::ExportTreeNode(const char8 *path, StreamString &out) {
|
||||
bool isRoot =
|
||||
(path == NULL_PTR(const char8 *) || StringHelper::Length(path) == 0);
|
||||
|
||||
out += "{\"Path\":\"";
|
||||
EscapeJson(isRoot ? "" : path, out);
|
||||
out += "\",\"Children\":[\n";
|
||||
|
||||
uint32 count = 0u;
|
||||
|
||||
ReferenceContainer *container = NULL_PTR(ReferenceContainer *);
|
||||
DataSourceI * ds = NULL_PTR(DataSourceI *);
|
||||
GAM * gam = NULL_PTR(GAM *);
|
||||
|
||||
if (isRoot) {
|
||||
container = ObjectRegistryDatabase::Instance();
|
||||
} else {
|
||||
Reference ref = ObjectRegistryDatabase::Instance()->Find(path);
|
||||
if (ref.IsValid()) {
|
||||
container = dynamic_cast<ReferenceContainer *>(ref.operator->());
|
||||
ds = dynamic_cast<DataSourceI *>(ref.operator->());
|
||||
gam = dynamic_cast<GAM *>(ref.operator->());
|
||||
}
|
||||
}
|
||||
|
||||
// ReferenceContainer children
|
||||
if (container != NULL_PTR(ReferenceContainer *)) {
|
||||
uint32 n = container->Size();
|
||||
for (uint32 i = 0u; i < n; i++) {
|
||||
Reference child = container->Get(i);
|
||||
if (!child.IsValid())
|
||||
continue;
|
||||
const char8 *cname = child->GetName();
|
||||
if (cname == NULL_PTR(const char8 *))
|
||||
cname = "unnamed";
|
||||
|
||||
ReferenceContainer *irc =
|
||||
dynamic_cast<ReferenceContainer *>(child.operator->());
|
||||
DataSourceI *ids = dynamic_cast<DataSourceI *>(child.operator->());
|
||||
GAM * igam = dynamic_cast<GAM *>(child.operator->());
|
||||
bool hasCh =
|
||||
(irc != NULL_PTR(ReferenceContainer *) && irc->Size() > 0u) ||
|
||||
ids != NULL_PTR(DataSourceI *) || igam != NULL_PTR(GAM *);
|
||||
|
||||
if (count > 0u)
|
||||
out += ",\n";
|
||||
out += "{\"Name\":\"";
|
||||
EscapeJson(cname, out);
|
||||
out += "\",\"Class\":\"";
|
||||
EscapeJson(child->GetClassProperties()->GetName(), out);
|
||||
out.Printf("\",\"HasChildren\":%s}", hasCh ? "true" : "false");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// DataSourceI signals
|
||||
if (ds != NULL_PTR(DataSourceI *)) {
|
||||
uint32 ns = ds->GetNumberOfSignals();
|
||||
for (uint32 j = 0u; j < ns; j++) {
|
||||
StreamString sn;
|
||||
(void)ds->GetSignalName(j, sn);
|
||||
const char8 *st = TypeDescriptor::GetTypeNameFromTypeDescriptor(
|
||||
ds->GetSignalType(j));
|
||||
uint8 d = 0u;
|
||||
(void)ds->GetSignalNumberOfDimensions(j, d);
|
||||
uint32 el = 0u;
|
||||
(void)ds->GetSignalNumberOfElements(j, el);
|
||||
StreamString sfp;
|
||||
sfp.Printf("%s.%s", path, sn.Buffer());
|
||||
bool tr = false, fo = false;
|
||||
(void)IsInstrumented(sfp.Buffer(), tr, fo);
|
||||
|
||||
if (count > 0u)
|
||||
out += ",\n";
|
||||
out += "{\"Name\":\"";
|
||||
EscapeJson(sn.Buffer(), out);
|
||||
out += "\",\"Class\":\"Signal\",\"Type\":\"";
|
||||
EscapeJson(st ? st : "Unknown", out);
|
||||
out.Printf("\",\"Dimensions\":%u,\"Elements\":%u,"
|
||||
"\"IsTraceable\":%s,\"IsForcable\":%s,\"HasChildren\":false}",
|
||||
d, el, tr ? "true" : "false", fo ? "true" : "false");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// GAM input signals
|
||||
if (gam != NULL_PTR(GAM *)) {
|
||||
uint32 nIn = gam->GetNumberOfInputSignals();
|
||||
for (uint32 j = 0u; j < nIn; j++) {
|
||||
StreamString sn;
|
||||
(void)gam->GetSignalName(InputSignals, j, sn);
|
||||
const char8 *st = TypeDescriptor::GetTypeNameFromTypeDescriptor(
|
||||
gam->GetSignalType(InputSignals, j));
|
||||
uint32 d = 0u;
|
||||
(void)gam->GetSignalNumberOfDimensions(InputSignals, j, d);
|
||||
uint32 el = 0u;
|
||||
(void)gam->GetSignalNumberOfElements(InputSignals, j, el);
|
||||
StreamString sfp;
|
||||
sfp.Printf("%s.In.%s", path, sn.Buffer());
|
||||
bool tr = false, fo = false;
|
||||
(void)IsInstrumented(sfp.Buffer(), tr, fo);
|
||||
|
||||
if (count > 0u)
|
||||
out += ",\n";
|
||||
out += "{\"Name\":\"In.";
|
||||
EscapeJson(sn.Buffer(), out);
|
||||
out += "\",\"Class\":\"InputSignal\",\"Type\":\"";
|
||||
EscapeJson(st ? st : "Unknown", out);
|
||||
out.Printf("\",\"Dimensions\":%u,\"Elements\":%u,"
|
||||
"\"IsTraceable\":%s,\"IsForcable\":%s,\"HasChildren\":false}",
|
||||
d, el, tr ? "true" : "false", fo ? "true" : "false");
|
||||
count++;
|
||||
}
|
||||
|
||||
uint32 nOut = gam->GetNumberOfOutputSignals();
|
||||
for (uint32 j = 0u; j < nOut; j++) {
|
||||
StreamString sn;
|
||||
(void)gam->GetSignalName(OutputSignals, j, sn);
|
||||
const char8 *st = TypeDescriptor::GetTypeNameFromTypeDescriptor(
|
||||
gam->GetSignalType(OutputSignals, j));
|
||||
uint32 d = 0u;
|
||||
(void)gam->GetSignalNumberOfDimensions(OutputSignals, j, d);
|
||||
uint32 el = 0u;
|
||||
(void)gam->GetSignalNumberOfElements(OutputSignals, j, el);
|
||||
StreamString sfp;
|
||||
sfp.Printf("%s.Out.%s", path, sn.Buffer());
|
||||
bool tr = false, fo = false;
|
||||
(void)IsInstrumented(sfp.Buffer(), tr, fo);
|
||||
|
||||
if (count > 0u)
|
||||
out += ",\n";
|
||||
out += "{\"Name\":\"Out.";
|
||||
EscapeJson(sn.Buffer(), out);
|
||||
out += "\",\"Class\":\"OutputSignal\",\"Type\":\"";
|
||||
EscapeJson(st ? st : "Unknown", out);
|
||||
out.Printf("\",\"Dimensions\":%u,\"Elements\":%u,"
|
||||
"\"IsTraceable\":%s,\"IsForcable\":%s,\"HasChildren\":false}",
|
||||
d, el, tr ? "true" : "false", fo ? "true" : "false");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
out += "\n]}\nOK TREE\n";
|
||||
}
|
||||
|
||||
void DebugServiceBase::InfoNode(const char8 *path, StreamString &out) {
|
||||
@@ -857,8 +1104,7 @@ void DebugServiceBase::InfoNode(const char8 *path, StreamString &out) {
|
||||
mutex.FastLock();
|
||||
bool found = false;
|
||||
for (uint32 i = 0u; i < aliases.GetNumberOfElements(); i++) {
|
||||
if (aliases[i].name == path ||
|
||||
SuffixMatch(aliases[i].name.Buffer(), path)) {
|
||||
if (AliasMatch(aliases[i].name.Buffer(), path)) {
|
||||
DebugSignalInfo *s = signals[aliases[i].signalIndex];
|
||||
const char8 *tn =
|
||||
TypeDescriptor::GetTypeNameFromTypeDescriptor(s->type);
|
||||
@@ -922,7 +1168,6 @@ void DebugServiceBase::SetFullConfig(ConfigurationDatabase &config) {
|
||||
config.Copy(fullConfig);
|
||||
manualConfigSet = true;
|
||||
BuildDiscoverCache();
|
||||
BuildTreeCache();
|
||||
}
|
||||
|
||||
void DebugServiceBase::RebuildConfigFromRegistry() {
|
||||
@@ -1289,9 +1534,10 @@ void DebugServiceBase::HandleCommand(const StreamString &cmdIn,
|
||||
} else if (token == "DISCOVER") {
|
||||
Discover(out);
|
||||
} else if (token == "TREE") {
|
||||
if (!treeCacheValid)
|
||||
BuildTreeCache();
|
||||
out += treeCache;
|
||||
StreamString path;
|
||||
(void)cmd.GetToken(path, delims, term);
|
||||
ExportTreeNode(path.Size() > 0u ? path.Buffer() : NULL_PTR(const char8 *),
|
||||
out);
|
||||
} else if (token == "INFO") {
|
||||
StreamString path;
|
||||
if (cmd.GetToken(path, delims, term))
|
||||
|
||||
Reference in New Issue
Block a user