From 90cffa60d6ca163804ec702d1cd1b59b59deca00 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 7 Oct 2018 12:16:13 -0700 Subject: [PATCH] format NTTable as CSV --- src/factory/printer.cpp | 42 +++++++++++++------ testApp/misc/testprinter.cpp | 79 ++++++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 21 deletions(-) diff --git a/src/factory/printer.cpp b/src/factory/printer.cpp index 4afaee4..f1cb18a 100644 --- a/src/factory/printer.cpp +++ b/src/factory/printer.cpp @@ -170,6 +170,21 @@ bool printEnumT(std::ostream& strm, const PVStructure& top) return true; } +void csvEscape(std::string& S) +{ + // concise, not particularly efficient... + std::string temp(escape(S).style(escape::CSV).str()); + if(S.find_first_of(" ,\\")!=S.npos) {// only quote if necessary (stupid Excel) + std::string temp2; + temp2.reserve(temp.size()+2); + temp2.push_back('\"'); + temp2 += temp; + temp2.push_back('\"'); + temp2.swap(temp); + } + S = temp; +} + bool printTable(std::ostream& strm, const PVStructure& top) { PVStructure::const_shared_pointer cf(top.getSubField("value")); @@ -184,6 +199,7 @@ bool printTable(std::ostream& strm, const PVStructure& top) } } + // maybe output a line with meta-data { bool havets = !!top.getSubField("timeStamp"); bool haveal = !!top.getSubField("alarm"); @@ -210,7 +226,7 @@ bool printTable(std::ostream& strm, const PVStructure& top) } const PVFieldPtrArray& columns = cf->getPVFields(); - std::vector > coldat(columns.size()); + std::vector > coldat(columns.size()); std::vector widths(columns.size()); labels.reserve(columns.size()); @@ -220,42 +236,42 @@ bool printTable(std::ostream& strm, const PVStructure& top) for(size_t i=0, N=columns.size(); i=labels.size()) { labels.push_back(cf->getStructure()->getFieldName(i)); + } else { + csvEscape(labels[i]); } widths[i] = labels[i].size(); - static_cast(columns[i].get())->getAs(coldat[i]); + { + shared_vector ro; + static_cast(columns[i].get())->getAs(ro); + coldat[i] = thaw(ro); + } + // truncate if some columns are longer than others nrows = std::min(nrows, coldat[i].size()); for(size_t j=0, M=coldat[i].size(); j=lhs.size() || Rp>=rhs.size()) { + // reached end without match + Lp = lhs.size(); + Rp = rhs.size(); + } for(size_t l=L; lL); // must make progress + assert(Rp>R); L = Lp; R = Rp; // loop around and print matching line @@ -166,6 +173,54 @@ void showNTScalarString() testDiff(" bar MINOR DEVICE FOO \n", print(input->stream())); } +static const pvd::StructureConstPtr table(pvd::getFieldCreate()->createFieldBuilder() + ->setId("epics:nt/NTTable:1.0") + ->addArray("labels", pvd::pvString) + ->addNestedStructure("value") + ->addArray("colA", pvd::pvInt) + ->addArray("colB", pvd::pvString) + ->endNested() + ->add("alarm", pvd::getStandardField()->alarm()) + ->add("timeStamp", pvd::getStandardField()->timeStamp()) + ->createStructure()); +void showNTTable() +{ + testDiag("%s", CURRENT_FUNCTION); + pvd::PVStructurePtr input(pvd::getPVDataCreate()->createPVStructure(table)); + + testDiff(" \n" + "colA, colB\n" + , print(input->stream()), + "empty table"); + + + pvd::PVStringArray::svector sarr; + sarr.push_back("labelA"); + sarr.push_back("label B"); + input->getSubFieldT("labels")->replace(pvd::freeze(sarr)); + + pvd::PVIntArray::svector iarr; + iarr.push_back(1); + iarr.push_back(2); + iarr.push_back(3); + iarr.push_back(42); // will not be shown + input->getSubFieldT("value.colA")->replace(pvd::freeze(iarr)); + + sarr.push_back("one\x7f"); + sarr.push_back("two words"); + sarr.push_back("A '\"'"); + input->getSubFieldT("value.colB")->replace(pvd::freeze(sarr)); + + + testDiff(" \n" + "labelA, \"label B\"\n" + " 1, one\\x7F\n" + " 2, \"two words\"\n" + " 3, \"A \\'\"\"\\'\"\n" + , print(input->stream()), + "with data"); +} + static const pvd::StructureConstPtr everything(pvd::getFieldCreate()->createFieldBuilder() ->setId("omg") ->add("scalar", pvd::pvString) @@ -194,11 +249,18 @@ void testRaw() testDiag("%s", CURRENT_FUNCTION); pvd::PVStructurePtr input(pvd::getPVDataCreate()->createPVStructure(everything)); + { + pvd::PVStringArray::svector temp; + temp.push_back("hello"); + temp.push_back("world\x7f"); + input->getSubFieldT("scalarArray")->replace(pvd::freeze(temp)); + } + testDiff("omg \n" - " string scalar \n" - " string[] scalarArray []\n" + " string scalar \n" // bit 1 + " string[] scalarArray [\"hello\", \"world\\x7F\"]\n" " structure below\n" - " int A 0\n" + " int A 0\n" // bit 4 " union select\n" " (none)\n" " union[] arrselect\n" @@ -216,7 +278,7 @@ void testRaw() testDiff("omg \n" "\033[1m string scalar \n" - "\033[0m\033[1m string[] scalarArray []\n" + "\033[0m\033[1m string[] scalarArray [\"hello\", \"world\\x7F\"]\n" "\033[0m structure below\n" "\033[1m int A 0\n" "\033[0m union select\n" @@ -250,9 +312,10 @@ void testEscape() MAIN(testprinter) { - testPlan(14); + testPlan(16); showNTScalarNumeric(); showNTScalarString(); + showNTTable(); testRaw(); testEscape(); return testDone();