This is Unofficial EPICS BASE Doxygen Site
parseinto.cpp
Go to the documentation of this file.
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 
6 #include <vector>
7 #include <sstream>
8 
9 #define epicsExportSharedSymbols
10 #include <pv/pvdVersion.h>
11 #include <pv/pvData.h>
12 #include <pv/valueBuilder.h>
13 #include <pv/bitSet.h>
14 #include "pv/json.h"
15 
16 namespace pvd = epics::pvData;
19 
20 namespace {
21 struct context {
22 
23  std::string msg;
24 
25  struct frame {
26  pvd::PVFieldPtr fld;
27  pvd::BitSet *assigned;
28  frame(const pvd::PVFieldPtr& fld, pvd::BitSet *assigned)
29  :fld(fld), assigned(assigned)
30  {}
31  };
32 
33  typedef std::vector<frame> stack_t;
34  stack_t stack;
35 
36  context(const pvd::PVFieldPtr& root, pvd::BitSet *assigned)
37  {
38  stack.push_back(frame(root, assigned));
39  }
40 };
41 
42 #define TRY context *self = (context*)ctx; assert(!self->stack.empty()); try
43 
44 #define CATCH() catch(std::exception& e) { if(self->msg.empty()) self->msg = e.what(); return 0; }
45 
46 int jtree_null(void * ctx)
47 {
48  TRY {
49  self->msg = "NULL value not permitted";
50  return 0;
51  }CATCH()
52 }
53 
54 template<typename PVScalarT, typename PVArrayT>
55 void valueAssign(context *self, typename PVScalarT::value_type val)
56 {
57  assert(!self->stack.empty());
58  context::frame& back = self->stack.back();
59  pvd::Type type(back.fld->getField()->getType());
60  if(type==pvd::scalar) {
61  pvd::PVScalar* fld(static_cast<pvd::PVScalar*>(back.fld.get()));
62 
63  fld->putFrom(val);
64  if(back.assigned)
65  back.assigned->set(fld->getFieldOffset());
66  self->stack.pop_back();
67  // structure at the top of the stack
68 
69  } else if(type==pvd::scalarArray) {
70  pvd::PVScalarArray *fld(static_cast<pvd::PVScalarArray*>(back.fld.get()));
71 
73  fld->getAs(carr);
74 
75  switch(carr.original_type())
76  {
77 #define CASE_STRING
78 #define CASE_REAL_INT64
79 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case epics::pvData::pv##PVACODE: { \
80  pvd::shared_vector<const PVATYPE> arr(pvd::static_shared_vector_cast<const PVATYPE>(carr)); \
81  pvd::shared_vector<PVATYPE> tarr(pvd::thaw(arr)); \
82  tarr.push_back(pvd::castUnsafe<PVATYPE>(val)); \
83  carr = pvd::static_shared_vector_cast<const void>(pvd::freeze(tarr)); \
84  } break;
85 #include <pv/typemap.h>
86 #undef CASE
87 #undef CASE_REAL_INT64
88 #undef CASE_STRING
89  }
90 
91  fld->putFrom(carr);
92 
93  // leave array field at top of stack
94 
95  } else if(type==pvd::union_) {
96  pvd::PVUnion* fld(static_cast<pvd::PVUnion*>(back.fld.get()));
97  pvd::UnionConstPtr utype(fld->getUnion());
98 
99  if(utype->isVariant()) {
100  typename PVScalarT::shared_pointer elem(pvd::getPVDataCreate()->createPVScalar<PVScalarT>());
101 
102  elem->put(val);
103 
104  fld->set(elem);
105 
106  } else {
107  // attempt automagic assignment
108 
109  const pvd::StringArray& names = utype->getFieldNames();
110  const pvd::FieldConstPtrArray types = utype->getFields();
111  assert(names.size()==types.size());
112 
113  bool assigned = false;
114  for(size_t i=0, N=names.size(); i<N; i++) {
115  if(types[i]->getType()!=pvd::scalar) continue;
116 
117  pvd::PVScalarPtr ufld(fld->select<pvd::PVScalar>(i));
118  try{
119  ufld->putFrom(val);
120  assigned = true;
121  }catch(std::runtime_error&){
122  if(i==N-1)
123  throw;
124  continue;
125  }
126 
127  break;
128  }
129  if(!assigned)
130  throw std::runtime_error("Unable to select union member");
131  }
132  if(back.assigned)
133  back.assigned->set(fld->getFieldOffset());
134  self->stack.pop_back();
135  // structure back at the top of the stack
136 
137  } else {
138  throw std::invalid_argument("Can't assign value");
139  }
140 }
141 
142 int jtree_boolean(void * ctx, int boolVal)
143 {
144  TRY {
145  valueAssign<pvd::PVBoolean, pvd::PVBooleanArray>(self, !!boolVal);
146  return 1;
147  }CATCH()
148 }
149 
150 int jtree_integer(void * ctx, integer_arg integerVal)
151 {
152  TRY {
153  valueAssign<pvd::PVLong, pvd::PVLongArray>(self, integerVal);
154  return 1;
155  }CATCH()
156 }
157 
158 int jtree_double(void * ctx, double doubleVal)
159 {
160  TRY {
161  valueAssign<pvd::PVDouble, pvd::PVDoubleArray>(self, doubleVal);
162  return 1;
163  }CATCH()
164 }
165 
166 int jtree_string(void * ctx, const unsigned char * stringVal,
167  size_arg stringLen)
168 {
169  TRY {
170  std::string val((const char*)stringVal, stringLen);
171  valueAssign<pvd::PVString, pvd::PVStringArray>(self, val);
172  return 1;
173  }CATCH()
174 }
175 
176 int jtree_start_map(void * ctx)
177 {
178  TRY {
179  assert(!self->stack.empty());
180 
181  context::frame& back = self->stack.back();
182  pvd::Type type = back.fld->getField()->getType();
183  if(type==pvd::structure) {
184  // will fill in
185  } else if(type==pvd::structureArray) {
186  // starting new element in structure array
187  pvd::PVStructureArray* sarr(static_cast<pvd::PVStructureArray*>(back.fld.get()));
188 
189  pvd::PVStructurePtr elem(pvd::getPVDataCreate()->createPVStructure(sarr->getStructureArray()->getStructure()));
190 
191  self->stack.push_back(context::frame(elem, 0));
192  } else {
193  throw std::runtime_error("Can't map (sub)structure");
194  }
195 
196  assert(self->stack.back().fld->getField()->getType()==pvd::structure);
197  return 1;
198  }CATCH()
199 }
200 
201 int jtree_map_key(void * ctx, const unsigned char * key,
202  size_arg stringLen)
203 {
204  TRY {
205  assert(!self->stack.empty());
206  std::string name((const char*)key, stringLen);
207 
208  // start_map() ensures we have a structure at the top of the stack
209  pvd::PVStructure *fld = static_cast<pvd::PVStructure*>(self->stack.back().fld.get());
210 
211  try {
212  self->stack.push_back(context::frame(fld->getSubFieldT(name), self->stack.back().assigned));
213  }catch(std::runtime_error& e){
214  std::ostringstream strm;
215  strm<<"At "<<fld->getFullName()<<" : "<<e.what()<<"\n";
216  throw std::runtime_error(strm.str());
217  }
218 
219  return 1;
220  }CATCH()
221 }
222 
223 int jtree_end_map(void * ctx)
224 {
225  TRY {
226  assert(!self->stack.empty());
227  assert(self->stack.back().fld->getField()->getType()==pvd::structure);
228 
229  context::frame elem(self->stack.back());
230  self->stack.pop_back();
231 
232  if(!self->stack.empty() && self->stack.back().fld->getField()->getType()==pvd::structureArray) {
233  // append element to struct array
234  pvd::PVStructureArray *sarr = static_cast<pvd::PVStructureArray*>(self->stack.back().fld.get());
235 
237  sarr->swap(cval);
238 
239  pvd::PVStructureArray::svector val(pvd::thaw(cval));
240 
241  val.push_back(std::tr1::static_pointer_cast<pvd::PVStructure>(elem.fld));
242 
243  sarr->replace(pvd::freeze(val));
244  }
245 
246  return 1;
247  }CATCH()
248 }
249 
250 int jtree_start_array(void * ctx)
251 {
252  TRY {
253  assert(!self->stack.empty());
254  pvd::PVFieldPtr& back(self->stack.back().fld);
255  pvd::Type type = back->getField()->getType();
256  if(type!=pvd::structureArray && type!=pvd::scalarArray)
257  throw std::runtime_error("Can't assign array");
258 
259  return 1;
260  }CATCH()
261 }
262 int jtree_end_array(void * ctx)
263 {
264  TRY {
265  assert(!self->stack.empty());
266 
267  if(self->stack.back().assigned)
268  self->stack.back().assigned->set(self->stack.back().fld->getFieldOffset());
269  self->stack.pop_back();
270  return 1;
271  }CATCH()
272 }
273 
274 
275 yajl_callbacks jtree_cbs = {
276  &jtree_null,
277  &jtree_boolean,
278  &jtree_integer,
279  &jtree_double,
280  NULL, // number
281  &jtree_string,
282  &jtree_start_map,
283  &jtree_map_key,
284  &jtree_end_map,
285  &jtree_start_array,
286  &jtree_end_array,
287 };
288 
289 struct handler {
290  yajl_handle handle;
291  handler(yajl_handle handle) :handle(handle)
292  {
293  if(!handle)
294  throw std::runtime_error("Failed to allocate yajl handle");
295  }
296  ~handler() {
297  yajl_free(handle);
298  }
299  operator yajl_handle() { return handle; }
300 };
301 
302 struct noop {
303  void operator()(pvd::PVField*) {}
304 };
305 
306 } // namespace
307 
308 namespace epics{namespace pvData{
309 
311 void parseJSON(std::istream& strm,
312  PVField& dest,
313  BitSet *assigned)
314 {
315 #ifndef EPICS_YAJL_VERSION
316  yajl_parser_config conf;
317  memset(&conf, 0, sizeof(conf));
318  conf.allowComments = 1;
319  conf.checkUTF8 = 1;
320 #endif
321 
322  // we won't create refs to 'dest' which presist beyond this call.
323  // however, it is convienent to treat 'dest' in the same manner as
324  // any union/structureArray memebers it may contain.
325  PVFieldPtr fakedest(&dest, noop());
326 
327  context ctxt(fakedest, assigned);
328 
329 #ifndef EPICS_YAJL_VERSION
330  handler handle(yajl_alloc(&jtree_cbs, &conf, NULL, &ctxt));
331 #else
332  handler handle(yajl_alloc(&jtree_cbs, NULL, &ctxt));
333 
334  yajl_config(handle, yajl_allow_comments, 1);
335 #endif
336 
337 
338  if(!yajl_parse_helper(strm, handle))
339  throw std::runtime_error(ctxt.msg);
340 
341  if(!ctxt.stack.empty())
342  throw std::logic_error("field stack not empty");
343  assert(fakedest.use_count()==1);
344 }
345 
346 }} // namespace epics::pvData
PVScalar is the base class for each scalar field.
Definition: pvData.h:272
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
void yajl_free(yajl_handle handle)
Definition: yajl.c:109
int i
Definition: scan.c:967
StructureArrayConstPtr getStructureArray() const
Definition: pvData.h:1278
epicsShareFunc void parseJSON(std::istream &strm, PVField &dest, BitSet *assigned)
Definition: parseinto.cpp:311
::epics::pvData::shared_vector< PVStructurePtr > svector
Definition: pvData.h:1248
const UnionConstPtr & getUnion() const
Definition: pvData.h:962
virtual void replace(const const_svector &other) OVERRIDE FINAL
Definition: pvData.h:1299
pvd::StructureConstPtr type
#define epicsShareFunc
Definition: shareLib.h:209
virtual void swap(const_svector &other) OVERRIDE FINAL
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
int yajl_config(yajl_handle h, yajl_option opt,...)
Definition: yajl.c:85
::epics::pvData::shared_vector< const PVStructurePtr > const_svector
Definition: pvData.h:1249
#define NULL
Definition: catime.c:38
A vector of bits.
Definition: bitSet.h:56
void putFrom(T val)
Definition: pvData.h:324
PVField is the base class for each PVData field.
Definition: pvData.h:152
std::size_t getFieldOffset() const
Definition: PVField.cpp:44
unsigned size_arg
Definition: json.h:137
std::string getFullName() const
Definition: PVField.cpp:97
void getAs(shared_vector< const T > &out) const
Definition: pvData.h:647
pvData
Definition: monitor.h:428
std::tr1::shared_ptr< const Union > UnionConstPtr
Definition: pvIntrospect.h:170
Base class for a scalarArray.
Definition: pvData.h:618
std::tr1::shared_ptr< PVScalar > PVScalarPtr
Definition: pvData.h:77
PVUnion has a single subfield.
Definition: pvData.h:940
std::vector< FieldConstPtr > FieldConstPtrArray
Definition: pvIntrospect.h:146
Data interface for a structure,.
Definition: pvData.h:712
#define TRY
Definition: parseinto.cpp:42
void set(PVFieldPtr const &value)
Definition: pvData.h:1028
long integer_arg
Definition: json.h:136
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
PVFieldPtr select(int32 index)
Definition: PVUnion.cpp:54
Data class for a structureArray.
Definition: pvData.h:1236
FORCE_INLINE std::tr1::shared_ptr< PVField > getSubFieldT(A a)
Definition: pvData.h:786
yajl_handle yajl_alloc(const yajl_callbacks *callbacks, yajl_alloc_funcs *afs, void *ctx)
Definition: yajl.c:46
std::vector< std::string > StringArray
Definition: pvType.h:110
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
void putFrom(const shared_vector< const T > &inp)
Definition: pvData.h:666
bool yajl_parse_helper(std::istream &src, yajl_handle handle)
Definition: parsehelper.cpp:29
struct yajl_handle_t * yajl_handle
Definition: yajl_parse.h:46
#define CATCH()
Definition: parseinto.cpp:44
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648