diff --git a/pvtoolsSrc/eget.cpp b/pvtoolsSrc/eget.cpp index c94ed84..ce7597d 100644 --- a/pvtoolsSrc/eget.cpp +++ b/pvtoolsSrc/eget.cpp @@ -157,29 +157,7 @@ void formatNTEnum(std::ostream& o, PVStructurePtr const & pvStruct) return; } - PVIntPtr index = dynamic_pointer_cast(enumt->getSubField("index")); - if (index.get() == 0) - { - std::cerr << "no int 'value.index' field in NTEnum" << std::endl; - return; - } - - PVStringArrayPtr choices = dynamic_pointer_cast(enumt->getSubField("choices")); - if (choices.get() == 0) - { - std::cerr << "no string[] 'value.choices' field in NTEnum" << std::endl; - return; - } - - int32 ix = index->get(); - if (ix < 0 || ix > static_cast(choices->getLength())) - { - o << ix; - } - else - { - choices->dumpValue(o, ix); - } + printEnumT(o, enumt); } size_t getLongestString(shared_vector const & array) @@ -1045,7 +1023,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" " -z: Pure pvAccess RPC based service (send NTURI.query as request argument)\n" - " -n: Do not format NT types, dump structure instead\n" + " -N: Do not format NT types, dump structure instead\n" " -t: Terse mode\n" " -T: Transpose vector, table, matrix\n" " -m: Monitor mode\n" @@ -1056,6 +1034,8 @@ void usage (void) " -F : Use as an alternate output field separator\n" " -f : Use as an input that provides a list PV name(s) to be read, use '-' for stdin\n" " -c: Wait for clean shutdown and report used instance count (for expert users)" + " enum format:\n" + " -n: Force enum interpretation of values as numbers (default is enum string)\n" "\n\nexamples:\n\n" "#! Get the value of the PV corr:li32:53:bdes\n" "> eget corr:li32:53:bdes\n" @@ -1472,7 +1452,7 @@ int main (int argc, char *argv[]) setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */ - while ((opt = getopt(argc, argv, ":hr:s:a:w:zntTmxp:qdcF:f:")) != -1) { + while ((opt = getopt(argc, argv, ":hr:s:a:w:zNtTmxp:qdcF:f:n")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); @@ -1539,7 +1519,7 @@ int main (int argc, char *argv[]) case 'z': /* pvAccess RPC mode */ onlyQuery = true; break; - case 'n': /* Do not format NT types */ + case 'N': /* Do not format NT types */ dumpStructure = true; break; case 't': /* Terse mode */ @@ -1601,6 +1581,9 @@ int main (int argc, char *argv[]) fromStream = true; break; } + case 'n': + setEnumPrintMode(NumberEnum); + break; case '?': fprintf(stderr, "Unrecognized option: '-%c'. ('eget -h' for help.)\n", diff --git a/pvtoolsSrc/pvget.cpp b/pvtoolsSrc/pvget.cpp index cd9659f..0410f33 100644 --- a/pvtoolsSrc/pvget.cpp +++ b/pvtoolsSrc/pvget.cpp @@ -57,6 +57,8 @@ void usage (void) " -F : Use as an alternate output field separator\n" " -f : Use as an input that provides a list PV name(s) to be read, use '-' for stdin\n" " -c: Wait for clean shutdown and report used instance count (for expert users)\n" + " enum format:\n" + " -n: Force enum interpretation of values as numbers (default is enum string)\n" "\nexample: pvget double01\n\n" , DEFAULT_REQUEST, DEFAULT_TIMEOUT); } @@ -95,7 +97,12 @@ void printValue(std::string const & channelName, PVStructure::shared_pointer con else if (mode == TerseMode) terseStructure(std::cout, pv) << std::endl; else + { std::cout << channelName << std::endl << *(pv.get()) << std::endl << std::endl; + + //pvutil_ostream myos(std::cout.rdbuf()); + //myos << channelName << std::endl << *(pv.get()) << std::endl << std::endl; + } } @@ -339,7 +346,7 @@ int main (int argc, char *argv[]) setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */ - while ((opt = getopt(argc, argv, ":hr:w:tmqdcF:f:")) != -1) { + while ((opt = getopt(argc, argv, ":hr:w:tmqdcF:f:n")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); @@ -397,6 +404,9 @@ int main (int argc, char *argv[]) fromStream = true; break; } + case 'n': + setEnumPrintMode(NumberEnum); + break; case '?': fprintf(stderr, "Unrecognized option: '-%c'. ('pvget -h' for help.)\n", diff --git a/pvtoolsSrc/pvlist.cpp b/pvtoolsSrc/pvlist.cpp index 672a26f..d263a55 100644 --- a/pvtoolsSrc/pvlist.cpp +++ b/pvtoolsSrc/pvlist.cpp @@ -604,7 +604,7 @@ int main (int argc, char *argv[]) if (quiet) cmd += 'q'; if (printInfo) - cmd += 'n'; + cmd += 'N'; cmd += "s pva://" + serverAddress + "/server?op="; if (printInfo) cmd += "info"; diff --git a/pvtoolsSrc/pvput.cpp b/pvtoolsSrc/pvput.cpp index 72d80dd..1ab4e84 100644 --- a/pvtoolsSrc/pvput.cpp +++ b/pvtoolsSrc/pvput.cpp @@ -28,8 +28,9 @@ using namespace std::tr1; using namespace epics::pvData; using namespace epics::pvAccess; -enum EnumMode { AutoEnum, NumberEnum, StringEnum }; -EnumMode enumMode = AutoEnum; +//EnumMode enumMode = AutoEnum; + +size_t fromString(PVFieldPtr const & pv, StringArray const & from, size_t fromStartIndex); size_t fromString(PVScalarArrayPtr const &pv, StringArray const & from, size_t fromStartIndex = 0) { @@ -114,64 +115,12 @@ size_t fromString(PVUnionPtr const & pvUnion, StringArray const & from, size_t f throw std::runtime_error("not enough of values"); string selector = from[fromStartIndex++]; - PVFieldPtr fieldField = pvUnion->select(selector); - if (!fieldField) + PVFieldPtr pv = pvUnion->select(selector); + if (!pv) throw std::runtime_error("invalid union selector value '" + selector + "'"); - size_t processed = 1; - - try - { - Type type = fieldField->getField()->getType(); - if(type==structure) { - PVStructurePtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - } - else if(type==scalarArray) { - PVScalarArrayPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - } - else if(type==scalar) { - - if (fromStartIndex >= fromValueCount) - throw std::runtime_error("not enough of values"); - - PVScalarPtr pv = static_pointer_cast(fieldField); - getConvert()->fromString(pv, from[fromStartIndex]); - processed++; - } - else if(type==structureArray) { - PVStructureArrayPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - } - else if(type==union_) { - PVUnionPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - } - else if(type==unionArray) { - PVUnionArrayPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - } - else { - std::ostringstream oss; - oss << "fromString unsupported fieldType " << type; - throw std::logic_error(oss.str()); - } - } - catch (std::exception &ex) - { - std::ostringstream os; - os << "failed to parse '" << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << "'"; - os << ": " << ex.what(); - throw std::runtime_error(os.str()); - } - - return processed; + size_t processed = fromString(pv, from, fromStartIndex); + return processed + 1; } size_t fromString(PVUnionArrayPtr const &pv, StringArray const & from, size_t fromStartIndex = 0) @@ -251,76 +200,68 @@ size_t fromString(PVStructurePtr const & pvStructure, StringArray const & from, } size_t processed = 0; - size_t fromValueCount = from.size(); PVFieldPtrArray const & fieldsData = pvStructure->getPVFields(); if (fieldsData.size() != 0) { size_t length = pvStructure->getStructure()->getNumberFields(); for(size_t i = 0; i < length; i++) { - PVFieldPtr fieldField = fieldsData[i]; - - try - { - Type type = fieldField->getField()->getType(); - if(type==structure) { - PVStructurePtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - fromStartIndex += count; - } - else if(type==scalarArray) { - PVScalarArrayPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - fromStartIndex += count; - } - else if(type==scalar) { - - if (fromStartIndex >= fromValueCount) - throw std::runtime_error("not enough of values"); - - PVScalarPtr pv = static_pointer_cast(fieldField); - getConvert()->fromString(pv, from[fromStartIndex]); - processed++; - fromStartIndex++; - } - else if(type==structureArray) { - PVStructureArrayPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - fromStartIndex += count; - } - else if(type==union_) { - PVUnionPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - fromStartIndex += count; - } - else if(type==unionArray) { - PVUnionArrayPtr pv = static_pointer_cast(fieldField); - size_t count = fromString(pv, from, fromStartIndex); - processed += count; - fromStartIndex += count; - } - else { - std::ostringstream oss; - oss << "fromString unsupported fieldType " << type; - throw std::logic_error(oss.str()); - } - } - catch (std::exception &ex) - { - std::ostringstream os; - os << "failed to parse '" << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << "'"; - os << ": " << ex.what(); - throw std::runtime_error(os.str()); - } + size_t count = fromString(fieldsData[i], from, fromStartIndex); + processed += count; + fromStartIndex += count; } } return processed; } +size_t fromString(PVFieldPtr const & fieldField, StringArray const & from, size_t fromStartIndex) +{ + try + { + switch (fieldField->getField()->getType()) + { + case scalar: + { + if (fromStartIndex >= from.size()) + throw std::runtime_error("not enough of values"); + + PVScalarPtr pv = static_pointer_cast(fieldField); + getConvert()->fromString(pv, from[fromStartIndex]); + return 1; + } + + case scalarArray: + return fromString(static_pointer_cast(fieldField), from, fromStartIndex); + + case structure: + return fromString(static_pointer_cast(fieldField), from, fromStartIndex); + + case structureArray: + return fromString(static_pointer_cast(fieldField), from, fromStartIndex); + + case union_: + return fromString(static_pointer_cast(fieldField), from, fromStartIndex); + + case unionArray: + return fromString(static_pointer_cast(fieldField), from, fromStartIndex); + + default: + std::ostringstream oss; + oss << "fromString unsupported fieldType " << fieldField->getField()->getType(); + throw std::logic_error(oss.str()); + } + } + catch (std::exception &ex) + { + std::ostringstream os; + os << "failed to parse '" << fieldField->getField()->getID() << ' ' + << fieldField->getFieldName() << "'"; + os << ": " << ex.what(); + throw std::runtime_error(os.str()); + } +} + + #define DEFAULT_TIMEOUT 3.0 #define DEFAULT_REQUEST "field(value)" @@ -368,6 +309,27 @@ void printValue(std::string const & channelName, PVStructure::shared_pointer con Type valueType = value->getField()->getType(); if (valueType != scalar && valueType != scalarArray) { + // special case for enum + if (valueType == structure) + { + PVStructurePtr pvStructure = static_pointer_cast(value); + if (pvStructure->getStructure()->getID() == "enum_t") + { + if (fieldSeparator == ' ') + std::cout << std::setw(30) << std::left << channelName; + else + std::cout << channelName; + + std::cout << fieldSeparator; + + printEnumT(std::cout, pvStructure); + + std::cout << std::endl; + + return; + } + } + // switch to structure mode std::cout << channelName << std::endl << *(pv.get()) << std::endl << std::endl; } @@ -705,6 +667,7 @@ int main (int argc, char *argv[]) std::cout << std::boolalpha; terseSeparator(fieldSeparator); + setEnumPrintMode(enumMode); ClientFactory::start(); ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); diff --git a/pvtoolsSrc/pvutils.cpp b/pvtoolsSrc/pvutils.cpp index b3688b2..9512556 100644 --- a/pvtoolsSrc/pvutils.cpp +++ b/pvtoolsSrc/pvutils.cpp @@ -10,6 +10,7 @@ #include #include +#include using namespace std; using namespace std::tr1; @@ -68,6 +69,18 @@ void terseArrayCount(bool flag) arrayCountFlag = flag; } +EnumMode enumMode = AutoEnum; +void setEnumPrintMode(EnumMode mode) +{ + enumMode = mode; +} + +bool formatTTypesFlag = true; +void formatTTypes(bool flag) +{ + formatTTypesFlag = flag; +} + std::ostream& terse(std::ostream& o, PVField::shared_pointer const & pv) { @@ -99,6 +112,54 @@ std::ostream& terse(std::ostream& o, PVField::shared_pointer const & pv) } } +std::ostream& printEnumT(std::ostream& o, epics::pvData::PVStructure::shared_pointer const & pvEnumT) +{ + PVInt::shared_pointer pvIndex = pvEnumT->getSubField("index"); + if (!pvIndex) + throw std::runtime_error("enum_t structure does not have 'int index' field"); + + PVStringArray::shared_pointer pvChoices = pvEnumT->getSubField("choices"); + if (!pvChoices) + throw std::runtime_error("enum_t structure does not have 'string choices[]' field"); + + if (enumMode == AutoEnum || enumMode == StringEnum) + { + int32 ix = pvIndex->get(); + if (ix < 0 || ix > static_cast(pvChoices->getLength())) + o << ix; + else + pvChoices->dumpValue(o, ix); + } + else + o << pvIndex->get(); + + return o; +} + +std::ostream& printTimeT(std::ostream& o, epics::pvData::PVStructure::shared_pointer const & pvTimeT) +{ + #define TIMETEXTLEN 32 + char timeText[TIMETEXTLEN]; + epicsTimeStamp epicsTS; + + PVTimeStamp pvTimeStamp; + if (pvTimeStamp.attach(pvTimeT)) + { + TimeStamp ts; + pvTimeStamp.get(ts); + + epicsTS.secPastEpoch = ts.getEpicsSecondsPastEpoch(); + epicsTS.nsec = ts.getNanoseconds(); + } + else + throw std::runtime_error("invalid time_t structure"); + + epicsTimeToStrftime(timeText, TIMETEXTLEN, "%Y-%m-%dT%H:%M:%S.%03f", &epicsTS); + o << timeText; + + return o; +} + std::ostream& terseStructure(std::ostream& o, PVStructure::shared_pointer const & pvStructure) { if (!pvStructure) @@ -107,6 +168,22 @@ std::ostream& terseStructure(std::ostream& o, PVStructure::shared_pointer const return o; } + // special t-types support (enum_t and time_t, etc.) + if (formatTTypesFlag) + { + string id = pvStructure->getStructure()->getID(); + if (id == "enum_t") + { + printEnumT(o, pvStructure); + return o; + } + else if (id == "time_t") + { + printTimeT(o, pvStructure); + return o; + } + } + PVFieldPtrArray fieldsData = pvStructure->getPVFields(); size_t length = pvStructure->getStructure()->getNumberFields(); bool first = true; diff --git a/pvtoolsSrc/pvutils.h b/pvtoolsSrc/pvutils.h index 2f5041c..45d8ce4 100644 --- a/pvtoolsSrc/pvutils.h +++ b/pvtoolsSrc/pvutils.h @@ -16,6 +16,13 @@ std::ostream& terseScalarArray(std::ostream& o, epics::pvData::PVScalarArray::sh std::ostream& terseStructureArray(std::ostream& o, epics::pvData::PVStructureArray::shared_pointer const & pvArray); std::ostream& terseUnionArray(std::ostream& o, epics::pvData::PVUnionArray::shared_pointer const & pvArray); +enum EnumMode { AutoEnum, NumberEnum, StringEnum }; +void setEnumPrintMode(EnumMode mode); + +void formatTTypes(bool flag); + +std::ostream& printEnumT(std::ostream& o, epics::pvData::PVStructure::shared_pointer const & pvEnumT); +std::ostream& printTimeT(std::ostream& o, epics::pvData::PVStructure::shared_pointer const & pvTimeT); /* Converts a hex character to its integer value */ char from_hex(char ch); @@ -103,3 +110,69 @@ struct dump_stack_only_on_debug }; std::ostream& operator<<(std::ostream& os, const dump_stack_only_on_debug& d); + + + +/* +#include +#include + +// usage: pvutil_ostream myos(std::cout.rdbuf()); + +class pvutil_ostream : private std::ostream +{ +public: + pvutil_ostream(std::streambuf* sb) + : std::ostream(sb) + {} + + template + friend pvutil_ostream& operator<<(pvutil_ostream&, const T&); + + // Additional overload to handle ostream specific io manipulators + friend pvutil_ostream& operator<<(pvutil_ostream&, std::ostream& (*)(std::ostream&)); + + // Accessor function to get a reference to the ostream + std::ostream& get_ostream() { return *this; } +}; + + +template +inline pvutil_ostream& +operator<<(pvutil_ostream& out, const T& value) +{ + static_cast(out) << '.'; + static_cast(out) << value; + return out; +} + +// overload for std::ostream specific io manipulators +inline pvutil_ostream& +operator<<(pvutil_ostream& out, std::ostream& (*func)(std::ostream&)) +{ + static_cast(out) << '#'; + static_cast(out) << func; + return out; +} + +// overload for PVField +template <> +inline pvutil_ostream& +operator<<(pvutil_ostream& out, const epics::pvData::PVField& value) +{ + static_cast(out) << '?'; +// static_cast(out) << value; + value.dumpValue(out); + return out; +} + +template <> +inline pvutil_ostream& +operator<<(pvutil_ostream& out, const epics::pvData::PVStructure& value) +{ + static_cast(out) << '!'; +// static_cast(out) << value; + value.dumpValue(out); + return out; +} +*/