From 2d0ce8df36933036fdd6cf80cfd04403c6a5979f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 7 Sep 2017 18:40:23 -0500 Subject: [PATCH] pvput 3.14 compat --- pvtoolsSrc/pvput.cpp | 162 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 21 deletions(-) diff --git a/pvtoolsSrc/pvput.cpp b/pvtoolsSrc/pvput.cpp index 50da0a8..d86d004 100644 --- a/pvtoolsSrc/pvput.cpp +++ b/pvtoolsSrc/pvput.cpp @@ -1,31 +1,36 @@ #include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - #include #include #include #include #include -#include -#include +#include #include -#include "pvutils.cpp" +#include +#include +#include + +#include +#include +#include +#include + +#include + +#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1) +# include +# define USE_JSON +#endif + +#include +#include #include +#include "pvutils.cpp" + using namespace std; namespace TR1 = std::tr1; using namespace epics::pvData; @@ -72,17 +77,33 @@ void usage (bool details=false) " -n: Force enum interpretation of values as numbers\n" " -s: Force enum interpretation of values as strings\n" , DEFAULT_REQUEST, DEFAULT_TIMEOUT, DEFAULT_PROVIDER); - if(details) + if(details) { + fprintf (stderr, +#ifdef USE_JSON + " JSON support is present\n" +#else + " no JSON support (needs EPICS Base >=3.15.0.1)\n"; +#endif + ); fprintf (stderr, "\nExamples:\n" "\n" - " pvput double01 1.234\n\n" + " pvput double01 1.234\n" "equivalent to:\n" - " pvput double01 value=1.234\n\n" + " pvput double01 value=1.234\n" ); +#ifdef USE_JSON + fprintf (stderr, + "\n" + "Field values may be given with JSON syntax. eg. and array:\n" + "\n" + " pvput arr:pv \"[1.0, 2.0]\"\n" + "equivalent to:\n" + " pvput arr:pv value=\"[1.0, 2.0]\"\n"); +#endif + } } - void printValue(std::string const & channelName, PVStructure::const_shared_pointer const & pv) { if (mode == ValueOnlyMode) @@ -141,6 +162,78 @@ void printValue(std::string const & channelName, PVStructure::const_shared_point std::cout << std::endl << *(pv.get()) << std::endl << std::endl; } +void early(const char *inp, unsigned pos) +{ + fprintf(stderr, "Unexpected end of input: %s\n", inp); + throw std::runtime_error("Unexpected end of input"); +} + +// rudimentory parser for json array +// needed as long as Base < 3.15 is supported. +// for consistency, used with all version +void jarray(shared_vector& out, const char *inp) +{ + assert(inp[0]=='['); + const char * const orig = inp; + inp++; + + while(true) { + // starting a new token + + for(; *inp==' '; inp++) {} // skip leading whitespace + + if(*inp=='\0') early(inp, inp-orig); + + if(isalnum(*inp) || *inp=='+' || *inp=='-') { + // number + + const char *start = inp; + + while(isalnum(*inp) || *inp=='.' || *inp=='+' || *inp=='-') + inp++; + + if(*inp=='\0') early(inp, inp-orig); + + // inp points to first char after token + + out.push_back(std::string(start, inp-start)); + + } else if(*inp=='"') { + // quoted string + + const char *start = ++inp; // skip quote + + while(*inp!='\0' && *inp!='"') + inp++; + + if(*inp=='\0') early(inp, inp-orig); + + // inp points to trailing " + + out.push_back(std::string(start, inp-start)); + + inp++; // skip trailing " + + } else if(*inp==']') { + // no-op + } else { + fprintf(stderr, "Unknown token '%c' in \"%s\"", *inp, inp); + throw std::runtime_error("Unknown token"); + } + + for(; *inp==' '; inp++) {} // skip trailing whitespace + + if(*inp==',') inp++; + else if(*inp==']') break; + else { + fprintf(stderr, "Unknown token '%c' in \"%s\"", *inp, inp); + throw std::runtime_error("Unknown token"); + } + } + + std::cerr<<"jarray "< pairs_t; pairs_t pairs; + shared_vector jarr; + virtual void putBuild(const epics::pvData::StructureConstPtr& build, Args& args) { PVStructurePtr root(getPVDataCreate()->createPVStructure(build)); @@ -164,12 +259,27 @@ struct Putter : public pvac::ClientChannel::PutCallback if(pairs.empty()) { std::istringstream strm(jblob); parseJSON(strm, root, &args.tosend); + } else { for(pairs_t::const_iterator it=pairs.begin(), end=pairs.end(); it!=end; ++it) { PVFieldPtr fld(root->getSubField(it->first)); if(!fld) { - fprintf(stderr, "%s : Error: no such field\n", it->first.c_str()); + fprintf(stderr, "%s : Warning: no such field\n", it->first.c_str()); + // ignore + + } else if(it->second[0]=='[') { + shared_vector arr; + jarray(arr, it->second.c_str()); + + PVScalarArray* afld(dynamic_cast(fld.get())); + if(!afld) { + fprintf(stderr, "%s : Error not a scalar array field\n", it->first.c_str()); + throw std::runtime_error("Not a scalar array field"); + } + afld->putFrom(freeze(arr)); + args.tosend.set(afld->getFieldOffset()); + } else if(it->second[0]=='{' || it->second[0]=='[') { std::istringstream strm(it->second); parseJSON(strm, fld, &args.tosend); @@ -374,6 +484,10 @@ int main (int argc, char *argv[]) return 1; } else if(values[0][0]=='{') { // write entire blob +#ifndef USE_JSON + fprintf(stderr, "JSON syntax not supported by this build.\n"); + return 1; +#endif thework.jblob = values[0]; } else { for(size_t i=0, N=values.size(); i