This is Unofficial EPICS BASE Doxygen Site
createRequest.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 <string>
7 #include <sstream>
8 
9 #include <epicsMutex.h>
10 
11 #define epicsExportSharedSymbols
12 
13 #include <pv/pvData.h>
14 #include <pv/lock.h>
15 #include <pv/createRequest.h>
16 
17 using namespace epics::pvData;
18 using std::ostringstream;
20 using std::cout;
21 using std::endl;
22 using std::string;
23 using std::vector;
24 
25 namespace {
26 using namespace epics::pvData;
27 
28 static PVDataCreatePtr pvDataCreate = getPVDataCreate();
29 static FieldCreatePtr fieldCreate = getFieldCreate();
30 
31 struct CreateRequestImpl {
32 
33  struct Node
34  {
35  string name;
36  vector<Node> nodes;
37  Node(string name)
38  : name(name)
39  {}
40  };
41 
42  struct OptionPair
43  {
44  string name;
45  string value;
46  OptionPair(string name,string value)
47  : name(name),
48  value(value)
49  {}
50  };
51 
52 
53  vector<OptionPair> optionList;
54  string fullFieldName;
55 
56 
57  CreateRequestImpl() {}
58 
59 
60  void removeBlanks(string& str)
61  {
62  while(true) {
63  string::size_type pos = str.find_first_of(' ');
64  if(pos==string::npos) return;
65  str.erase(pos,1);
66  }
67  }
68 
69  size_t findMatchingBrace(string& request, size_t index, int numOpen) {
70  size_t openBrace = request.find('{', index+1);
71  size_t closeBrace = request.find('}', index+1);
72  if(openBrace == string::npos && closeBrace == string::npos){
73  throw std::runtime_error(request + " mismatched {}");
74  }
75  if (openBrace != string::npos && openBrace!=0) {
76  if(openBrace<closeBrace) return findMatchingBrace(request,openBrace,numOpen+1);
77  if(numOpen==1) return closeBrace;
78  return findMatchingBrace(request,closeBrace,numOpen-1);
79  }
80  if(numOpen==1) return closeBrace;
81  return findMatchingBrace(request,closeBrace,numOpen-1);
82  }
83 
84  size_t findMatchingBracket(string& request, size_t index) {
85  for(size_t i=index+1; i< request.size(); ++i) {
86  if(request[i] == ']') {
87  if(i==index+1) {
88  throw std::runtime_error(request + " mismatched []");
89  }
90  return i;
91  }
92  }
93  throw std::runtime_error(request + " missing ]");
94  }
95 
96  size_t findEndField(string& request) {
97  size_t ind = 0;
98  size_t maxind = request.size() -1;
99  while(true) {
100  if(request[ind]==',') return ind;
101  if(request[ind]=='[') {
102  size_t closeBracket = findMatchingBracket(request,ind);
103  if(closeBracket==string::npos) return closeBracket;
104  ind = closeBracket;
105  continue;
106  }
107  if(request[ind]=='{') {
108  size_t closeBrace = findMatchingBrace(request,ind,1);
109  if(closeBrace==string::npos) return closeBrace;
110  if(ind>=request.size()) return request.size();
111  ind = closeBrace;
112  continue;
113  }
114  if(request[ind]=='.') {
115  ++ind;
116  continue;
117  }
118  if(ind>=maxind) break;
119  ++ind;
120  }
121  return request.size();
122  }
123 
124  vector<string> split(string const & commaSeparatedList) {
125  string::size_type numValues = 1;
126  string::size_type index=0;
127  while(true) {
128  string::size_type pos = commaSeparatedList.find(',',index);
129  if(pos==string::npos) break;
130  numValues++;
131  index = pos +1;
132  }
133  vector<string> valueList(numValues,"");
134  index=0;
135  for(size_t i=0; i<numValues; i++) {
136  size_t pos = commaSeparatedList.find(',',index);
137  string value = commaSeparatedList.substr(index,pos-index);
138  valueList[i] = value;
139  index = pos +1;
140  }
141  return valueList;
142  }
143 
144  Node createRequestOptions(
145  string const & request)
146  {
147  if(request.length()<=1) {
148  throw std::runtime_error("logic error empty options");
149  }
150  vector<Node> top;
151  vector<string> items = split(request);
152 
153  size_t nitems = items.size();
154  for(size_t j=0; j<nitems; j++) {
155  string item = items[j];
156  size_t equals = item.find('=');
157  if(equals==string::npos || equals==0) {
158  throw std::runtime_error(item + " illegal option " + request);
159  }
160  top.push_back(Node(item.substr(0,equals)));
161  string name = fullFieldName + "._options." + item.substr(0,equals);
162  string value = item.substr(equals+1);
163  optionList.push_back(OptionPair(name,value));
164  }
165  Node node("_options");
166  node.nodes = top;
167  return node;
168  }
169 
170 
171  void createSubNode(Node &node,string const & crequest)
172  {
173  string request = crequest;
174  size_t end = 0;
175  for(size_t i=0; i<request.size(); ++i) {
176  if(request[i]=='[') { end = i; break;}
177  if(request[i]=='.') { end = i; break;}
178  if(request[i]=='{') { end = i; break;}
179  if(request[i]==',') { end = i; break;}
180  }
181  char chr = request[end];
182  Node optionNode("");
183  if(chr=='[') {
184  string saveFullName = fullFieldName;
185  fullFieldName += "." + request.substr(0,end);
186  size_t endBracket = findMatchingBracket(request,end);
187  string options = request.substr(end+1,endBracket -end -1);
188  optionNode = createRequestOptions(options);
189  fullFieldName = saveFullName;
190  size_t next = endBracket+1;
191  if(next<request.size()) {
192  request = request.substr(0, end) + request.substr(endBracket+1);
193  } else {
194  request = request.substr(0, end);
195  }
196  end = 0;
197  for(size_t i=0; i<request.size(); ++i) {
198  if(request[i]=='.') { end = i; break;}
199  if(request[i]=='{') { end = i; break;}
200  if(request[i]==',') { end = i; break;}
201  }
202  chr = request[end];
203  }
204  if(end==0) end = request.size();
205  string name = request.substr(0,end);
206  if(name.size()<1) {
207  throw std::runtime_error("null field name " + request);
208  }
209  string saveFullName = fullFieldName;
210  fullFieldName += "." + name;
211  if(end==request.size()) {
212  Node subNode(name);
213  if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
214  node.nodes.push_back(subNode);
215  fullFieldName = saveFullName;
216  return;
217  }
218  if(chr==',') {
219  Node subNode(name);
220  if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
221  node.nodes.push_back(subNode);
222  string rest = request.substr(end+1);
223  fullFieldName = saveFullName;
224  createSubNode(node,rest);
225  return;
226  }
227  if(chr=='.') {
228  request = request.substr(end+1);
229  if(request.size()==string::npos || request.size()<1) {
230  throw std::runtime_error("null field name " + request);
231  }
232  Node subNode(name);
233  if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
234  size_t endField = findEndField(request);
235  string subRequest = request.substr(0, endField);
236  createSubNode(subNode,subRequest);
237  node.nodes.push_back(subNode);
238  size_t next = endField+1;
239  if(next>=request.size()) {
240  fullFieldName = saveFullName;
241  return;
242  }
243  request = request.substr(next);
244  fullFieldName = saveFullName;
245  createSubNode(node,request);
246  return;
247  }
248  if(chr=='{') {
249  size_t endBrace = findEndField(request);
250  if((end+1)>=(endBrace-1)) {
251  throw std::runtime_error("illegal syntax " + request);
252  }
253  string subRequest = request.substr(end+1,endBrace-1 -end -1);
254  if(subRequest.size()<1) {
255  throw std::runtime_error("empty {} " + request);
256  }
257  Node subNode(name);
258  if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
259  createSubNode(subNode,subRequest);
260  node.nodes.push_back(subNode);
261  size_t next = endBrace + 1;
262  if(next>=request.size()) {
263  fullFieldName = saveFullName;
264  return;
265  }
266  request = request.substr(next);
267  fullFieldName = saveFullName;
268  createSubNode(node,request);
269  return;
270  }
271  throw std::runtime_error("logic error");
272  }
273 
274  FieldConstPtr createSubStructure(vector<Node> & nodes)
275  {
276  size_t num = nodes.size();
277  StringArray names(num);
278  FieldConstPtrArray fields(num);
279  for(size_t i=0; i<num; ++i) {
280  Node node = nodes[i];
281  names[i] = node.name;
282  if(node.name.compare("_options")==0) {
283  fields[i] = createOptions(node.nodes);
284  } else {
285  vector<Node> subNode = node.nodes;
286  if(subNode.empty()) {
287  fields[i] = fieldCreate->createStructure();
288  } else {
289  fields[i] = createSubStructure(subNode);
290  }
291  }
292  }
293  StructureConstPtr structure = fieldCreate->createStructure(
294  names, fields);
295  return structure;
296  }
297 
298  StructureConstPtr createOptions(vector<Node> &nodes)
299  {
300  size_t num = nodes.size();
301  StringArray names(num);
302  FieldConstPtrArray fields(num);
303  for(size_t i=0; i<num; ++i) {
304  Node node = nodes[i];
305  names[i] = node.name;
306  fields[i] = fieldCreate->createScalar(pvString);
307  }
308  StructureConstPtr structure = fieldCreate->createStructure(names, fields);
309  return structure;
310  }
311 
312 
314  string const & crequest)
315  {
316  {
317  string request = crequest;
318  if (!request.empty()) removeBlanks(request);
319  if (request.empty())
320  {
321  return fieldCreate->createStructure()->build();
322  }
323  size_t offsetRecord = request.find("record[");
324  size_t offsetField = request.find("field(");
325  size_t offsetPutField = request.find("putField(");
326  size_t offsetGetField = request.find("getField(");
327  if(offsetRecord==string::npos
328  && offsetField==string::npos
329  && offsetPutField==string::npos
330  && offsetGetField==string::npos)
331  {
332  request = "field(" + request + ")";
333  offsetField = request.find("field(");
334  }
335  int numParan = 0;
336  int numBrace = 0;
337  int numBracket = 0;
338  for(size_t i=0; i< request.length() ; ++i) {
339  char chr = request[i];
340  if(chr=='(') numParan++;
341  if(chr==')') numParan--;
342  if(chr=='{') numBrace++;
343  if(chr=='}') numBrace--;
344  if(chr=='[') numBracket++;
345  if(chr==']') numBracket--;
346  }
347  if(numParan!=0) {
348  ostringstream oss;
349  oss << "mismatched () " << numParan;
350  throw std::runtime_error(oss.str());
351  }
352  if(numBrace!=0) {
353  ostringstream oss;
354  oss << "mismatched {} " << numBrace;
355  throw std::runtime_error(oss.str());
356  }
357  if(numBracket!=0) {
358  ostringstream oss;
359  oss << "mismatched [] " << numBracket;
360  throw std::runtime_error(oss.str());
361  }
362  vector<Node> top;
363  try {
364  if(offsetRecord!=string::npos) {
365  fullFieldName = "record";
366  size_t openBracket = request.find('[', offsetRecord);
367  size_t closeBracket = request.find(']', openBracket);
368  if(closeBracket==string::npos) {
369  throw std::runtime_error(request.substr(offsetRecord) +
370  "record[ does not have matching ]");
371  }
372  if(closeBracket-openBracket > 3) {
373  Node node("record");
374  Node optNode = createRequestOptions(
375  request.substr(openBracket+1,closeBracket-openBracket-1));
376  node.nodes.push_back(optNode);
377  top.push_back(node);
378  }
379  }
380  if(offsetField!=string::npos) {
381  fullFieldName = "field";
382  Node node("field");
383  size_t openParan = request.find('(', offsetField);
384  size_t closeParan = request.find(')', openParan);
385  if(closeParan==string::npos) {
386  throw std::runtime_error(request.substr(offsetField)
387  + " field( does not have matching )");
388  }
389  if(closeParan>openParan+1) {
390  createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
391  }
392  top.push_back(node);
393  }
394  if(offsetGetField!=string::npos) {
395  fullFieldName = "getField";
396  Node node("getField");
397  size_t openParan = request.find('(', offsetGetField);
398  size_t closeParan = request.find(')', openParan);
399  if(closeParan==string::npos) {
400  throw std::runtime_error(request.substr(offsetField)
401  + " getField( does not have matching )");
402  }
403  if(closeParan>openParan+1) {
404  createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
405  }
406  top.push_back(node);
407  }
408  if(offsetPutField!=string::npos) {
409  fullFieldName = "putField";
410  Node node("putField");
411  size_t openParan = request.find('(', offsetPutField);
412  size_t closeParan = request.find(')', openParan);
413  if(closeParan==string::npos) {
414  throw std::runtime_error(request.substr(offsetField)
415  + " putField( does not have matching )");
416  }
417  if(closeParan>openParan+1) {
418  createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
419  }
420  top.push_back(node);
421  }
422  } catch (std::exception &e) {
423  throw std::runtime_error(std::string("while creating Structure exception ")+e.what());
424  }
425  size_t num = top.size();
426  StringArray names(num);
427  FieldConstPtrArray fields(num);
428  for(size_t i=0; i<num; ++i) {
429  Node node = top[i];
430  names[i] = node.name;
431  vector<Node> subNode = node.nodes;
432  if(subNode.empty()) {
433  fields[i] = fieldCreate->createStructure();
434  } else {
435  fields[i] = createSubStructure(subNode);
436  }
437  }
438  StructureConstPtr structure = fieldCreate->createStructure(names, fields);
439  if(!structure) throw std::invalid_argument("bad request " + crequest);
440  PVStructurePtr pvStructure = structure->build();
441  for(size_t i=0; i<optionList.size(); ++i) {
442  OptionPair pair = optionList[i];
443  string name = pair.name;
444  string value = pair.value;
445  PVStringPtr pvField = pvStructure->getSubField<PVString>(name);
446  if(!pvField) throw std::invalid_argument("bad request " + crequest);
447  pvField->put(value);
448  }
449  optionList.clear();
450  return pvStructure;
451  }
452  }
453 
454 
455 };
456 
457 } // namespace
458 
459 namespace epics {namespace pvData {
460 
461 CreateRequest::shared_pointer CreateRequest::create()
462 {
463  CreateRequest::shared_pointer createRequest(new CreateRequest());
464  return createRequest;
465 }
466 
467 PVStructure::shared_pointer CreateRequest::createRequest(std::string const & request)
468 {
469  message.clear();
470  try {
471  return ::createRequest(request);
472  } catch(std::exception& e) {
473  message = e.what();
474  return PVStructure::shared_pointer();
475  }
476 }
477 
478 PVStructure::shared_pointer createRequest(std::string const & request)
479 {
480  CreateRequestImpl I;
481  return I.createRequest(request);
482 }
483 
484 
485 }} // namespace
Definition: link.h:174
std::string request
PVStructure::shared_pointer createRequest(std::string const &request)
static CreateRequest::shared_pointer create()
int i
Definition: scan.c:967
Internal: bucket item structure.
Definition: bucketLib.h:40
Create pvRequest structure for Channel methods.
Definition: createRequest.h:31
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:788
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
#define str(v)
PVStructure::shared_pointer createRequest(std::string const &request)
int nitems
Definition: antelope.c:55
std::tr1::shared_ptr< PVDataCreate > PVDataCreatePtr
Definition: pvData.h:124
PVString is special case, since it implements SerializableArray.
Definition: pvData.h:521
pvData
Definition: monitor.h:428
APIs for the epicsMutex mutual exclusion semaphore.
std::vector< FieldConstPtr > FieldConstPtrArray
Definition: pvIntrospect.h:146
std::tr1::shared_ptr< const Field > FieldConstPtr
Definition: pvIntrospect.h:137
FORCE_INLINE const FieldCreatePtr & getFieldCreate()
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
std::tr1::shared_ptr< PVString > PVStringPtr
Definition: pvData.h:540
std::vector< std::string > StringArray
Definition: pvType.h:110
std::tr1::shared_ptr< FieldCreate > FieldCreatePtr
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648