This is Unofficial EPICS BASE Doxygen Site
configparse.cpp
Go to the documentation of this file.
1 
2 #include <sstream>
3 
4 #include <dbAccess.h>
5 
6 #include <dbAccess.h>
7 #include <dbChannel.h>
8 #include <dbStaticLib.h>
9 #include <dbEvent.h>
10 #include <dbLock.h>
11 
12 #include <pv/pvIntrospect.h>
13 #include <pv/pvAccess.h>
14 #include <pv/configuration.h>
15 #include <pv/json.h>
16 
17 #include "pdbgroup.h"
18 
19 namespace {
20 
21 namespace pvd = epics::pvData;
24 
25 typedef std::map<std::string, pvd::AnyScalar> options_t;
26 typedef std::map<std::string, options_t> config_t;
27 
28 struct context {
29  std::string msg;
30  std::string group, field, key;
31  unsigned depth; // number of '{'s
32  // depth 0 - invalid
33  // depth 1 - top Object
34  // depth 2 - Group
35  // depth 3 - field
36 
37  context() :depth(0u) {}
38 
39  GroupConfig conf;
40 
41  void can_assign()
42  {
43  if(depth<2 || depth>3)
44  throw std::runtime_error("Can't assign value in this context");
45  }
46 
47  void assign(const pvd::AnyScalar& value) {
48  can_assign();
49  GroupConfig::Group& grp = conf.groups[group];
50 
51  if(depth==2) {
52  if(field=="+atomic") {
53  grp.atomic = value.as<pvd::boolean>();
54  grp.atomic_set = true;
55 
56  } else if(field=="+id") {
57  grp.id = value.as<std::string>();
58 
59  } else {
60  conf.warning += "Unknown group option ";
61  conf.warning += field;
62  }
63  field.clear();
64 
65  } else if(depth==3) {
66  GroupConfig::Field& fld = grp.fields[field];
67 
68  if(key=="+type") {
69  fld.type = value.ref<std::string>();
70 
71  } else if(key=="+channel") {
72  fld.channel = value.ref<std::string>();
73 
74  } else if(key=="+id") {
75  fld.id = value.ref<std::string>();
76 
77  } else if(key=="+trigger") {
78  fld.trigger = value.ref<std::string>();
79 
80  } else if(key=="+putorder") {
81  fld.putorder = value.as<pvd::int32>();
82 
83  } else {
84  conf.warning += "Unknown group field option ";
85  conf.warning += field;
86  }
87  key.clear();
88  }
89  }
90 };
91 
92 #define TRY context *self = (context*)ctx; try
93 
94 #define CATCH() catch(std::exception& e) { if(self->msg.empty()) self->msg = e.what(); return 0; }
95 
96 int conf_null(void * ctx)
97 {
98  TRY {
99  self->assign(pvd::AnyScalar());
100  return 1;
101  }CATCH()
102 }
103 
104 
105 int conf_boolean(void * ctx, int boolVal)
106 {
107  TRY {
108  self->assign(pvd::AnyScalar(pvd::boolean(boolVal)));
109  return 1;
110  }CATCH()
111 }
112 
113 int conf_integer(void * ctx, integer_arg integerVal)
114 {
115  TRY {
116  self->assign(pvd::AnyScalar(pvd::int64(integerVal)));
117  return 1;
118  }CATCH()
119 }
120 
121 int conf_double(void * ctx, double doubleVal)
122 {
123  TRY {
124  self->assign(pvd::AnyScalar(doubleVal));
125  return 1;
126  }CATCH()
127 }
128 
129 int conf_string(void * ctx, const unsigned char * stringVal,
130  size_arg stringLen)
131 {
132  TRY {
133  std::string val((const char*)stringVal, stringLen);
134  self->assign(pvd::AnyScalar(val));
135  return 1;
136  }CATCH()
137 }
138 
139 int conf_start_map(void * ctx)
140 {
141  TRY {
142  self->depth++;
143  if(self->depth>3)
144  throw std::runtime_error("Group field def. can't contain Object (too deep)");
145  return 1;
146  }CATCH()
147 }
148 
149 int conf_map_key(void * ctx, const unsigned char * key,
150  size_arg stringLen)
151 {
152  TRY {
153  if(stringLen==0 && self->depth!=2)
154  throw std::runtime_error("empty group or key name not allowed");
155 
156  std::string name((const char*)key, stringLen);
157 
158  if(self->depth==1)
159  self->group.swap(name);
160  else if(self->depth==2)
161  self->field.swap(name);
162  else if(self->depth==3)
163  self->key.swap(name);
164  else
165  throw std::logic_error("Too deep!!");
166 
167  return 1;
168  }CATCH()
169 }
170 
171 int conf_end_map(void * ctx)
172 {
173  TRY {
174  assert(self->key.empty()); // cleared in assign()
175 
176  if(self->depth==3)
177  self->key.clear();
178  else if(self->depth==2)
179  self->field.clear();
180  else if(self->depth==1)
181  self->group.clear();
182  else
183  throw std::logic_error("Invalid depth");
184  self->depth--;
185 
186  return 1;
187  }CATCH()
188 }
189 
190 yajl_callbacks conf_cbs = {
191  &conf_null,
192  &conf_boolean,
193  &conf_integer,
194  &conf_double,
195  NULL, // number
196  &conf_string,
197  &conf_start_map,
198  &conf_map_key,
199  &conf_end_map,
200  NULL, // start_array,
201  NULL, // end_array,
202 };
203 
204 struct handler {
205  yajl_handle handle;
206  handler(yajl_handle handle) :handle(handle)
207  {
208  if(!handle)
209  throw std::runtime_error("Failed to allocate yajl handle");
210  }
211  ~handler() {
212  yajl_free(handle);
213  }
214  operator yajl_handle() { return handle; }
215 };
216 
217 }// namespace
218 
219 void GroupConfig::parse(const char *txt,
221 {
222 #ifndef EPICS_YAJL_VERSION
223  yajl_parser_config conf;
224  memset(&conf, 0, sizeof(conf));
225  conf.allowComments = 1;
226  conf.checkUTF8 = 1;
227 #endif
228 
229  std::istringstream strm(txt);
230 
231  context ctxt;
232 
233 #ifndef EPICS_YAJL_VERSION
234  handler handle(yajl_alloc(&conf_cbs, &conf, NULL, &ctxt));
235 #else
236  handler handle(yajl_alloc(&conf_cbs, NULL, &ctxt));
237 
238  yajl_config(handle, yajl_allow_comments, 1);
239 #endif
240 
241  if(!pvd::yajl_parse_helper(strm, handle))
242  throw std::runtime_error(ctxt.msg);
243 
244  ctxt.conf.swap(result);
245 }
Definition: link.h:174
pvac::PutEvent result
Definition: clientSync.cpp:117
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
void yajl_free(yajl_handle handle)
Definition: yajl.c:109
std::string id
Definition: pdbgroup.h:25
#define CATCH()
Definition: configparse.cpp:94
int yajl_config(yajl_handle h, yajl_option opt,...)
Definition: yajl.c:85
#define NULL
Definition: catime.c:38
std::string channel
Definition: pdbgroup.h:25
std::string type
Definition: pdbgroup.h:25
unsigned size_arg
Definition: json.h:137
std::string warning
Definition: pdbgroup.h:57
#define TRY
Definition: configparse.cpp:92
pvData
Definition: monitor.h:428
groups_t groups
Definition: pdbgroup.h:56
long integer_arg
Definition: json.h:136
int64_t int64
Definition: pvType.h:87
std::string trigger
Definition: pdbgroup.h:25
yajl_handle yajl_alloc(const yajl_callbacks *callbacks, yajl_alloc_funcs *afs, void *ctx)
Definition: yajl.c:46
bool yajl_parse_helper(std::istream &src, yajl_handle handle)
Definition: parsehelper.cpp:29
static void parse(const char *txt, GroupConfig &result)
std::string id
Definition: pdbgroup.h:43
detail::pick_type< int8_t, signed char, detail::pick_type< uint8_t, char, unsigned char >::type >::type boolean
Definition: pvType.h:71
struct yajl_handle_t * yajl_handle
Definition: yajl_parse.h:46
fields_t fields
Definition: pdbgroup.h:41
detail::any_storage_type< typename meta::strip_const< T >::type >::type & ref()
Definition: anyscalar.h:194
int32_t int32
Definition: pvType.h:83