From 0b44c4894c5383ff5aa93b25ae6307aca2bd8521 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 12 Oct 2012 22:50:05 +0200 Subject: [PATCH] multiple scalars and scalarArrays --- testApp/remote/eget.cpp | 274 +++++++++++++++++++++++++--------------- 1 file changed, 170 insertions(+), 104 deletions(-) diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index a745671..bf776cd 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -125,6 +125,18 @@ void formatNTScalarArray(std::ostream& o, PVStructurePtr const & pvStruct) formatVector(o, "", value, mode == TerseMode); } +size_t getLongestString(vector const & array) +{ + size_t max = 0; + size_t len = array.size(); + for (size_t i = 0; i < len; i++) + { + size_t l = array[i].size(); + if (l > max) max = l; + } + return max; +} + size_t getLongestString(PVScalarArrayPtr const & array) { size_t max = 0; @@ -146,7 +158,7 @@ size_t getLongestString(PVScalarArrayPtr const & array) // labels are optional // if provided labels.size() must equals columnData.size() void formatTable(std::ostream& o, - PVStringArrayPtr const & labels, + vector const & labels, vector const & columnData, bool transpose) { @@ -154,7 +166,7 @@ void formatTable(std::ostream& o, size_t maxValues = 0; // value with longest string form - size_t maxColumnLength = labels.get() ? getLongestString(labels) : 0; + size_t maxColumnLength = labels.size() ? getLongestString(labels) : 0; // // get maxValue and maxColumnLength @@ -163,22 +175,20 @@ void formatTable(std::ostream& o, for (size_t i = 0; i < numColumns; i++) { PVScalarArrayPtr array = columnData[i]; + if (array.get()) + { + size_t arrayLength = array->getLength(); + if (maxValues < arrayLength) maxValues = arrayLength; - size_t arrayLength = array->getLength(); - if (maxValues < arrayLength) maxValues = arrayLength; - - size_t colLen = getLongestString(array); - if (colLen > maxColumnLength) maxColumnLength = colLen; + size_t colLen = getLongestString(array); + if (colLen > maxColumnLength) maxColumnLength = colLen; + } } // add some space size_t padding = 2; maxColumnLength += padding; - // get labels - StringArrayData labelsData; - labels->get(0, numColumns, labelsData); - if (!transpose) { @@ -188,11 +198,14 @@ void formatTable(std::ostream& o, // // first print labels - for (size_t i = 0; i < numColumns; i++) - { - o << std::setw(maxColumnLength) << std::right << labelsData.data[i]; - } - o << std::endl; + if (labels.size()) + { + for (size_t i = 0; i < numColumns; i++) + { + o << std::setw(maxColumnLength) << std::right << labels[i]; + } + o << std::endl; + } // then values for (size_t r = 0; r < maxValues; r++) @@ -200,8 +213,9 @@ void formatTable(std::ostream& o, for (size_t i = 0; i < numColumns; i++) { o << std::setw(maxColumnLength) << std::right; - if (r < columnData[i]->getLength()) - columnData[i]->dumpValue(o, r); + PVScalarArrayPtr array = columnData[i]; + if (array.get() && r < array->getLength()) + array->dumpValue(o, r); else o << ""; } @@ -220,12 +234,15 @@ void formatTable(std::ostream& o, for (size_t i = 0; i < numColumns; i++) { - o << std::setw(maxColumnLength) << std::left << labelsData.data[i]; + if (labels.size()) + o << std::setw(maxColumnLength) << std::left << labels[i]; + for (size_t r = 0; r < maxValues; r++) { o << std::setw(maxColumnLength) << std::right; - if (r < columnData[i]->getLength()) - columnData[i]->dumpValue(o, r); + PVScalarArrayPtr array = columnData[i]; + if (array.get() && r < array->getLength()) + array->dumpValue(o, r); else o << ""; } @@ -273,7 +290,11 @@ void formatNTTable(std::ostream& o, PVStructurePtr const & pvStruct) columnData.push_back(array); } - formatTable(o, labels, columnData, mode == TerseMode); + // get labels + StringArrayData labelsData; + labels->get(0, numColumns, labelsData); + + formatTable(o, labelsData.data, columnData, mode == TerseMode); } @@ -433,10 +454,89 @@ void formatNT(std::ostream& o, PVFieldPtr const & pv) +void printValue(String const & channelName, PVStructure::shared_pointer const & pv) +{ + if (mode == ValueOnlyMode) + { + PVField::shared_pointer value = pv->getSubField("value"); + if (value.get() == 0) + { + std::cerr << "no 'value' field" << std::endl; + std::cout << channelName << std::endl << *(pv.get()) << std::endl << std::endl; + } + else + { + Type valueType = value->getField()->getType(); + if (valueType == scalar) + std::cout << *(value.get()) << std::endl; + else if (valueType == scalarArray) + { + //formatScalarArray(std::cout, dynamic_pointer_cast(value)); + formatVector(std::cout, "", dynamic_pointer_cast(value), false); + } + else + { + // switch to structure mode + std::cout << channelName << std::endl << *(pv.get()) << std::endl << std::endl; + } + } + } + else if (mode == TerseMode) + terseStructure(std::cout, pv) << std::endl; + else + std::cout << channelName << std::endl << *(pv.get()) << std::endl << std::endl; +} +// only in ValueOnlyMode +void printValues(vector const & names, vector const & values) +{ + size_t len = values.size(); + vector scalars; + vector scalarArrays; + for (size_t i = 0; i < len; i++) + { + PVField::shared_pointer value = values[i]->getSubField("value"); + if (value.get() != 0) + { + Type type = value->getField()->getType(); + if (type == scalarArray) + scalarArrays.push_back(dynamic_pointer_cast(value)); + else if (type == scalar) + { + scalars.push_back(dynamic_pointer_cast(value)); + // TODO also try to make an PVStringArray out of a scalar + } + } + } + + if (scalars.size() == len) + { + bool first = true; + for (size_t i = 0; i < len; i++) + { + if (first) + first = false; + else + std::cout << fieldSeparator; + std::cout << *(scalars[i].get()); + } + std::cout << std::endl; + } + else if (scalarArrays.size() == len) + { + // TODO labels switch + formatTable(std::cout, names, scalarArrays, false); + } + else + { + // classic output + for (size_t i = 0; i < len; i++) + printValue(names[i], values[i]); + } +} #define DEFAULT_TIMEOUT 3.0 #define DEFAULT_REQUEST "field(value)" @@ -455,7 +555,7 @@ void usage (void) " -r : Get request string, specifies what fields to return and options, default is '%s'\n" " -w : Wait time, specifies timeout, default is %f second(s)\n" " -q: Pure pvAccess RPC based service (send NTURI.query as request argument)\n" - " -t: Terse mode - print only value, without field names\n" + " -t: Terse mode / transpose vector, table, matrix.\n" " -d: Enable debug output\n" " -F : Use as an alternate output field separator\n" " -c: Wait for clean shutdown and report used instance count (for expert users)" @@ -473,20 +573,25 @@ void usage (void) } - class ChannelGetRequesterImpl : public ChannelGetRequester { private: + String m_channelName; + bool m_printValue; + ChannelGet::shared_pointer m_channelGet; PVStructure::shared_pointer m_pvStructure; BitSet::shared_pointer m_bitSet; Mutex m_pointerMutex; Event m_event; - String m_channelName; public: - ChannelGetRequesterImpl(String channelName) : m_channelName(channelName) {} + ChannelGetRequesterImpl(String channelName, bool printValue) : + m_channelName(channelName), + m_printValue(printValue) + { + } virtual String getRequesterName() { @@ -540,39 +645,15 @@ class ChannelGetRequesterImpl : public ChannelGetRequester { Lock lock(m_pointerMutex); { - // needed since we access the data - ScopedLock dataLock(m_channelGet); - - if (mode == ValueOnlyMode) - { - PVField::shared_pointer value = m_pvStructure->getSubField("value"); - if (value.get() == 0) - { - std::cerr << "no 'value' field" << std::endl; - std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; - } - else - { - Type valueType = value->getField()->getType(); - if (valueType == scalar) - std::cout << *(value.get()) << std::endl; - else if (valueType == scalarArray) - { - //formatScalarArray(std::cout, dynamic_pointer_cast(value)); - formatVector(std::cout, "", dynamic_pointer_cast(value), false); - } - else - { - // switch to structure mode - std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; - } - } - } - else if (mode == TerseMode) - terseStructure(std::cout, m_pvStructure) << std::endl; - else - std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + if (m_printValue) + { + // needed since we access the data + ScopedLock dataLock(m_channelGet); + + printValue(m_channelName, m_pvStructure); + } } + // this is OK since calle holds also owns it m_channelGet.reset(); } @@ -592,53 +673,18 @@ class ChannelGetRequesterImpl : public ChannelGetRequester } + PVStructure::shared_pointer getPVStructure() + { + Lock lock(m_pointerMutex); + return m_pvStructure; + } + bool waitUntilGet(double timeOut) { return m_event.wait(timeOut); } }; -/* -PVFieldPtr pvField = m_pvStructure->getSubField("value"); - if (pvField.get()) - { - PVScalarArrayPtr pvScalarArray = std::tr1::dynamic_pointer_cast(pvField); - if (pvScalarArray.get()) - { - size_t len = pvScalarArray->getLength(); - for (size_t i = 0; i < len; i++) - { - pvScalarArray->dumpValue(std::cout, i) << std::endl; - } - } - else - { - std::cout << *(pvField.get()) << std::endl; - } - } - else - { - // do a structure mode, as fallback - std::cerr << "no 'value' field" << std::endl; - String str; - m_pvStructure->toString(&str); - std::cout << str << std::endl; - } - } - else if (mode == TerseMode) - { - String str; - convertToString(&str, m_pvStructure.get(), 0); - std::cout << str << std::endl; - } - else //if (mode == StructureMode) - { - String str; - m_pvStructure->toString(&str); - std::cout << str << std::endl; - } - } -*/ class ChannelRPCRequesterImpl : public ChannelRPCRequester { @@ -889,7 +935,15 @@ int main (int argc, char *argv[]) shared_ptr channelRequesterImpl(new ChannelRequesterImpl()); channels[n] = provider->createChannel(pvs[n], channelRequesterImpl); } - + + // TODO maybe unify for nPvs == 1?! + bool collectValues = (mode == ValueOnlyMode) && nPvs > 1; + + vector collectedValues; + collectedValues.reserve(nPvs); + vector collectedNames; + collectedNames.reserve(nPvs); + // for now a simple iterating sync implementation, guarantees order for (int n = 0; n < nPvs; n++) { @@ -906,7 +960,8 @@ int main (int argc, char *argv[]) shared_ptr getFieldRequesterImpl; // probe for value field - if (mode == ValueOnlyMode) + // but only if there is only one PV request (otherwise mode change makes a mess) + if (mode == ValueOnlyMode && nPvs == 1) { getFieldRequesterImpl.reset(new GetFieldRequesterImpl(channel)); // get all to be immune to bad clients not supporting selective getField request @@ -929,9 +984,17 @@ int main (int argc, char *argv[]) } } - shared_ptr getRequesterImpl(new ChannelGetRequesterImpl(channel->getChannelName())); + shared_ptr getRequesterImpl( + new ChannelGetRequesterImpl(channel->getChannelName(), !collectValues) + ); ChannelGet::shared_pointer channelGet = channel->createChannelGet(getRequesterImpl, pvRequest); - allOK &= getRequesterImpl->waitUntilGet(timeOut); + bool ok = getRequesterImpl->waitUntilGet(timeOut); + allOK &= ok; + if (ok && collectValues) + { + collectedValues.push_back(getRequesterImpl->getPVStructure()); + //collectedNames.push_back(channel->getChannelName()); + } } else { @@ -946,7 +1009,10 @@ int main (int argc, char *argv[]) channel->destroy(); std::cerr << "[" << channel->getChannelName() << "] connection timeout" << std::endl; } - } + } + + if (collectValues) + printValues(collectedNames, collectedValues); ClientFactory::stop(); }