pva2pva 1.4.2
Loading...
Searching...
No Matches
configparse.cpp
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
19namespace {
20
21namespace pvd = epics::pvData;
22using pvd::yajl::integer_arg;
23using pvd::yajl::size_arg;
24
25typedef std::map<std::string, pvd::AnyScalar> options_t;
26typedef std::map<std::string, options_t> config_t;
27
28struct context {
29 const std::string chanprefix;
30 std::string msg;
31 std::string group, field, key;
32 unsigned depth; // number of '{'s
33 // depth 0 - invalid
34 // depth 1 - top Object
35 // depth 2 - Group
36 // depth 3 - field
37
38 context(const std::string& chanprefix, GroupConfig& conf)
39 :chanprefix(chanprefix)
40 ,depth(0u)
41 ,conf(conf)
42 {}
43
44 GroupConfig& conf;
45
46 void can_assign()
47 {
48 if(depth<2 || depth>3)
49 throw std::runtime_error("Can't assign value in this context");
50 }
51
52 void assign(const pvd::AnyScalar& value) {
53 can_assign();
54 GroupConfig::Group& grp = conf.groups[group];
55
56 if(depth==2) {
57 if(field=="+atomic") {
58 grp.atomic = value.as<pvd::boolean>();
59 grp.atomic_set = true;
60
61 } else if(field=="+id") {
62 grp.id = value.as<std::string>();
63
64 } else {
65 conf.warning += "Unknown group option ";
66 conf.warning += field;
67 }
68 field.clear();
69
70 } else if(depth==3) {
71 GroupConfig::Field& fld = grp.fields[field];
72
73 if(key=="+type") {
74 fld.type = value.ref<std::string>();
75
76 } else if(key=="+channel") {
77 fld.channel = chanprefix + value.ref<std::string>();
78
79 } else if(key=="+id") {
80 fld.id = value.ref<std::string>();
81
82 } else if(key=="+trigger") {
83 fld.trigger = value.ref<std::string>();
84
85 } else if(key=="+putorder") {
86 fld.putorder = value.as<pvd::int32>();
87
88 } else {
89 conf.warning += "Unknown group field option ";
90 conf.warning += field;
91 }
92 key.clear();
93 }
94 }
95};
96
97#define TRY context *self = (context*)ctx; try
98
99#define CATCH() catch(std::exception& e) { if(self->msg.empty()) self->msg = e.what(); return 0; }
100
101int conf_null(void * ctx)
102{
103 TRY {
104 self->assign(pvd::AnyScalar());
105 return 1;
106 }CATCH()
107}
108
109
110int conf_boolean(void * ctx, int boolVal)
111{
112 TRY {
113 self->assign(pvd::AnyScalar(pvd::boolean(boolVal)));
114 return 1;
115 }CATCH()
116}
117
118int conf_integer(void * ctx, integer_arg integerVal)
119{
120 TRY {
121 self->assign(pvd::AnyScalar(pvd::int64(integerVal)));
122 return 1;
123 }CATCH()
124}
125
126int conf_double(void * ctx, double doubleVal)
127{
128 TRY {
129 self->assign(pvd::AnyScalar(doubleVal));
130 return 1;
131 }CATCH()
132}
133
134int conf_string(void * ctx, const unsigned char * stringVal,
135 size_arg stringLen)
136{
137 TRY {
138 std::string val((const char*)stringVal, stringLen);
139 self->assign(pvd::AnyScalar(val));
140 return 1;
141 }CATCH()
142}
143
144int conf_start_map(void * ctx)
145{
146 TRY {
147 self->depth++;
148 if(self->depth>3)
149 throw std::runtime_error("Group field def. can't contain Object (too deep)");
150 return 1;
151 }CATCH()
152}
153
154int conf_map_key(void * ctx, const unsigned char * key,
155 size_arg stringLen)
156{
157 TRY {
158 if(stringLen==0 && self->depth!=2)
159 throw std::runtime_error("empty group or key name not allowed");
160
161 std::string name((const char*)key, stringLen);
162
163 if(self->depth==1)
164 self->group.swap(name);
165 else if(self->depth==2)
166 self->field.swap(name);
167 else if(self->depth==3)
168 self->key.swap(name);
169 else
170 throw std::logic_error("Too deep!!");
171
172 return 1;
173 }CATCH()
174}
175
176int conf_end_map(void * ctx)
177{
178 TRY {
179 assert(self->key.empty()); // cleared in assign()
180
181 if(self->depth==3)
182 self->key.clear();
183 else if(self->depth==2)
184 self->field.clear();
185 else if(self->depth==1)
186 self->group.clear();
187 else
188 throw std::logic_error("Invalid depth");
189 self->depth--;
190
191 return 1;
192 }CATCH()
193}
194
195yajl_callbacks conf_cbs = {
196 &conf_null,
197 &conf_boolean,
198 &conf_integer,
199 &conf_double,
200 NULL, // number
201 &conf_string,
202 &conf_start_map,
203 &conf_map_key,
204 &conf_end_map,
205 NULL, // start_array,
206 NULL, // end_array,
207};
208
209struct handler {
210 yajl_handle handle;
211 handler(yajl_handle handle) :handle(handle)
212 {
213 if(!handle)
214 throw std::runtime_error("Failed to allocate yajl handle");
215 }
216 ~handler() {
217 yajl_free(handle);
218 }
219 operator yajl_handle() { return handle; }
220};
221
222}// namespace
223
224void GroupConfig::parse(const char *txt,
225 const char *recname,
226 GroupConfig& result)
227{
228#ifndef EPICS_YAJL_VERSION
229 yajl_parser_config conf;
230 memset(&conf, 0, sizeof(conf));
231 conf.allowComments = 1;
232 conf.checkUTF8 = 1;
233#endif
234
235 std::istringstream strm(txt);
236
237 std::string chanprefix;
238 if(recname) {
239 chanprefix = recname;
240 chanprefix += '.';
241 }
242 context ctxt(chanprefix, result);
243
244#ifndef EPICS_YAJL_VERSION
245 handler handle(yajl_alloc(&conf_cbs, &conf, NULL, &ctxt));
246#else
247 handler handle(yajl_alloc(&conf_cbs, NULL, &ctxt));
248
249 yajl_config(handle, yajl_allow_comments, 1);
250#endif
251
252 if(!pvd::yajl_parse_helper(strm, handle))
253 throw std::runtime_error(ctxt.msg);
254}