Line data Source code
1 : // DUNE DAQ modification notice:
2 : // This file has been modified from the original ATLAS oks source for the DUNE DAQ project.
3 : // Fork baseline commit: oks-08-03-04 (2022-04-14).
4 : // Renamed since fork: no.
5 :
6 : #define _OksBuildDll_
7 :
8 : #include "oks/method.hpp"
9 : #include "oks/xml.hpp"
10 : #include "oks/class.hpp"
11 : #include "oks/cstring.hpp"
12 :
13 : #include <stdexcept>
14 : #include <sstream>
15 :
16 : namespace dunedaq {
17 : namespace oks {
18 :
19 : const char OksMethodImplementation::method_impl_xml_tag[] = "method-implementation";
20 : const char OksMethodImplementation::language_xml_attr[] = "language";
21 : const char OksMethodImplementation::prototype_xml_attr[] = "prototype";
22 : const char OksMethodImplementation::body_xml_attr[] = "body";
23 :
24 : const char OksMethod::method_xml_tag[] = "method";
25 : const char OksMethod::name_xml_attr[] = "name";
26 : const char OksMethod::description_xml_attr[] = "description";
27 :
28 :
29 0 : OksMethodImplementation::OksMethodImplementation(const std::string& language, const std::string& prototype, const std::string& body, OksMethod * p) :
30 0 : p_language (language),
31 0 : p_prototype (prototype),
32 0 : p_body (body),
33 0 : p_method (p)
34 : {
35 0 : oks::validate_not_empty(p_language, "method implementation language");
36 0 : oks::validate_not_empty(p_prototype, "method implementation prototype");
37 0 : }
38 :
39 : bool
40 0 : OksMethodImplementation::operator==(const class OksMethodImplementation &i) const
41 : {
42 0 : return (
43 0 : ( this == &i ) ||
44 0 : ( p_language == i.p_language && p_prototype == i.p_prototype && p_body == i.p_body )
45 0 : );
46 : }
47 :
48 : std::ostream&
49 0 : operator<<(std::ostream& s, const OksMethodImplementation& i)
50 : {
51 0 : s << " Method implementation:\n"
52 0 : " language: \"" << i.get_language() << "\"\n"
53 0 : " prototype: \"" << i.get_prototype() << "\"\n"
54 0 : " body: \"" << i.get_body() << "\"\n";
55 :
56 0 : return s;
57 : }
58 :
59 :
60 : void
61 0 : OksMethodImplementation::save(OksXmlOutputStream& s) const
62 : {
63 0 : s.put(" ");
64 :
65 0 : s.put_start_tag(method_impl_xml_tag, sizeof(method_impl_xml_tag)-1);
66 :
67 0 : s.put_attribute( language_xml_attr, sizeof(language_xml_attr)-1, get_language().c_str() );
68 0 : s.put_attribute( prototype_xml_attr, sizeof(prototype_xml_attr)-1, get_prototype().c_str() );
69 0 : s.put_attribute( body_xml_attr, sizeof(body_xml_attr)-1, get_body().c_str() );
70 :
71 0 : s.put_end_tag();
72 0 : }
73 :
74 :
75 3076 : OksMethodImplementation::OksMethodImplementation(OksXmlInputStream& s, OksMethod * parent) :
76 3076 : p_method (parent)
77 : {
78 12304 : try {
79 21532 : while(true) {
80 12304 : OksXmlAttribute attr(s);
81 :
82 : // check for close of tag
83 :
84 12304 : if(oks::cmp_str1(attr.name(), "/")) { break; }
85 :
86 : // check for known oks-method-implementation' attributes
87 :
88 9228 : else if( oks::cmp_str8(attr.name(), language_xml_attr) ) p_language.assign(attr.value(), attr.value_len());
89 6152 : else if( oks::cmp_str9(attr.name(), prototype_xml_attr) ) p_prototype.assign(attr.value(), attr.value_len());
90 3076 : else if( oks::cmp_str4(attr.name(), body_xml_attr) ) p_body.assign(attr.value(), attr.value_len());
91 : else {
92 0 : s.throw_unexpected_attribute(attr.name());
93 : }
94 9228 : }
95 : }
96 0 : catch(oks::exception & e) {
97 0 : throw oks::FailedRead("xml method implementation", e);
98 0 : }
99 0 : catch (std::exception & e) {
100 0 : throw oks::FailedRead("xml method implementation", e.what());
101 0 : }
102 :
103 3076 : try {
104 3076 : oks::validate_not_empty(p_language, "method implementation language");
105 3076 : oks::validate_not_empty(p_prototype, "method implementation prototype");
106 : }
107 0 : catch(std::exception& ex) {
108 0 : throw oks::FailedRead("oks method implementation", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
109 0 : }
110 3076 : }
111 :
112 :
113 0 : OksMethod::OksMethod(const std::string& nm, OksClass * p) :
114 0 : p_class (p),
115 0 : p_name (nm),
116 0 : p_implementations (nullptr)
117 : {
118 0 : try {
119 0 : oks::validate_not_empty(p_name, "method name");
120 : }
121 0 : catch(std::exception& ex) {
122 0 : Oks::error_msg("OksMethod::OksMethod()") << ex.what() << std::endl;
123 0 : }
124 0 : }
125 :
126 0 : OksMethod::OksMethod(const std::string& nm, const std::string& desc, OksClass * p) :
127 0 : p_class (p),
128 0 : p_name (nm),
129 0 : p_description (desc),
130 0 : p_implementations (nullptr)
131 : {
132 0 : oks::validate_not_empty(p_name, "method name");
133 0 : }
134 :
135 2833 : OksMethod::~OksMethod()
136 : {
137 2833 : if(p_implementations) {
138 5909 : while(!p_implementations->empty()) {
139 3076 : OksMethodImplementation * i = p_implementations->front();
140 3076 : p_implementations->pop_front();
141 3076 : delete i;
142 : }
143 :
144 2833 : delete p_implementations;
145 : }
146 2833 : }
147 :
148 :
149 : bool
150 0 : OksMethod::operator==(const class OksMethod &m) const
151 : {
152 : // check if compare with self
153 :
154 0 : if(this == &m) return true;
155 :
156 :
157 : // check if attributes are different
158 :
159 0 : if(p_name != m.p_name || p_description != m.p_description) return false;
160 :
161 :
162 : // check if methods have no implementations
163 :
164 0 : if(p_implementations == 0 && m.p_implementations == 0) return true;
165 :
166 :
167 : // check if only one method has implementation
168 :
169 0 : if(p_implementations == 0 || m.p_implementations == 0) return false;
170 :
171 :
172 : // check if numbers of implementations are different
173 :
174 0 : if(p_implementations->size() != m.p_implementations->size()) return false;
175 :
176 :
177 : // check implementations
178 :
179 0 : std::list<OksMethodImplementation *>::const_iterator i1 = p_implementations->begin();
180 0 : std::list<OksMethodImplementation *>::const_iterator i2 = m.p_implementations->begin();
181 :
182 0 : for(;i1 != p_implementations->end(); ++i1, ++i2) {
183 0 : if( !(*(*i1) == *(*i2)) ) return false;
184 : }
185 :
186 : return true;
187 : }
188 :
189 : std::ostream&
190 0 : operator<<(std::ostream& s, const OksMethod& m)
191 : {
192 0 : s << "Method name: \"" << m.p_name << "\"\n"
193 0 : " description: \"" << m.p_description << "\"\n";
194 :
195 0 : if(m.p_implementations) {
196 0 : s << " implementations:\n";
197 :
198 0 : for(std::list<OksMethodImplementation *>::const_iterator i = m.p_implementations->begin(); i != m.p_implementations->end(); ++i)
199 0 : s << *(*i);
200 : }
201 : else
202 0 : s << " there are no implementation(s)\n";
203 :
204 0 : return s;
205 : }
206 :
207 :
208 : void
209 0 : OksMethod::save(OksXmlOutputStream& s) const
210 : {
211 0 : s.put_raw(' ');
212 0 : s.put_raw(' ');
213 :
214 0 : s.put_start_tag(method_xml_tag, sizeof(method_xml_tag)-1);
215 :
216 0 : s.put_attribute(name_xml_attr, sizeof(name_xml_attr)-1, p_name.c_str());
217 0 : s.put_attribute(description_xml_attr, sizeof(description_xml_attr)-1, p_description.c_str());
218 :
219 0 : s.put_raw('>');
220 0 : s.put_raw('\n');
221 :
222 0 : if(p_implementations) {
223 0 : for(std::list<OksMethodImplementation *>::iterator i = p_implementations->begin(); i != p_implementations->end(); ++i)
224 0 : (*i)->save(s);
225 : }
226 :
227 0 : s.put_raw(' ');
228 0 : s.put_raw(' ');
229 :
230 0 : s.put_last_tag(method_xml_tag, sizeof(method_xml_tag)-1);
231 0 : }
232 :
233 :
234 2833 : OksMethod::OksMethod(OksXmlInputStream& s, OksClass * parent) :
235 2833 : p_class (parent),
236 2833 : p_implementations (0)
237 : {
238 8499 : try {
239 14165 : while(true) {
240 8499 : OksXmlAttribute attr(s);
241 :
242 : // check for close of tag
243 :
244 8499 : if(oks::cmp_str1(attr.name(), ">")) { break; }
245 :
246 : // check for known oks-relationship' attributes
247 :
248 5666 : else if(oks::cmp_str4(attr.name(), name_xml_attr)) p_name.assign(attr.value(), attr.value_len());
249 2833 : else if(oks::cmp_str11(attr.name(), description_xml_attr)) p_description.assign(attr.value(), attr.value_len());
250 : else {
251 0 : s.throw_unexpected_attribute(attr.name());
252 : }
253 5666 : }
254 : }
255 0 : catch(oks::exception & e) {
256 0 : throw oks::FailedRead("xml method", e);
257 0 : }
258 0 : catch (std::exception & e) {
259 0 : throw oks::FailedRead("xml method", e.what());
260 0 : }
261 :
262 : // check validity of read values
263 :
264 2833 : try {
265 2833 : oks::validate_not_empty(p_name, "method name");
266 : }
267 0 : catch(std::exception& ex) {
268 0 : throw oks::FailedRead("oks method", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
269 0 : }
270 :
271 :
272 : // read 'body' and 'method-actions'
273 :
274 5909 : {
275 8985 : while(true) try {
276 5909 : const char * tag_start = s.get_tag_start();
277 :
278 5909 : if(oks::cmp_str7(tag_start, "/method")) { break; }
279 :
280 3076 : else if(!strcmp(tag_start, "method-implementation")) {
281 3076 : if(!p_implementations) p_implementations = new std::list<OksMethodImplementation *>();
282 3076 : p_implementations->push_back(new OksMethodImplementation(s, this));
283 : }
284 :
285 : else {
286 0 : std::ostringstream text;
287 0 : text << "Unexpected tag \'" << tag_start << "\' inside method \'" << p_name << "\'\n";
288 0 : throw std::runtime_error( text.str().c_str() );
289 0 : }
290 :
291 : }
292 0 : catch (oks::exception & e) {
293 0 : throw oks::FailedRead("method tag", e);
294 0 : }
295 0 : catch (std::exception & e) {
296 0 : throw oks::FailedRead("method tag", e.what());
297 3076 : }
298 : }
299 2833 : }
300 :
301 :
302 : void
303 0 : OksMethod::set_name(const std::string& new_name)
304 : {
305 : // ignore when name is the same
306 :
307 0 : if(p_name == new_name) return;
308 :
309 :
310 : // additional checks are required,
311 : // if the method already belongs to some class
312 :
313 0 : if(p_class) {
314 :
315 : // check allowed length for attribute name
316 :
317 0 : try {
318 0 : oks::validate_not_empty(new_name, "name");
319 : }
320 0 : catch(std::exception& ex) {
321 0 : throw oks::SetOperationFailed("OksMethod::set_name", ex.what());
322 0 : }
323 :
324 :
325 : // having a direct method with the same name is an error
326 :
327 0 : if(p_class->find_direct_method(new_name) != 0) {
328 0 : std::ostringstream text;
329 0 : text << "Class \"" << p_class->get_name() << "\" already has direct method \"" << new_name << '\"';
330 0 : throw oks::SetOperationFailed("OksMethod::set_name", text.str());
331 0 : }
332 :
333 :
334 : // check that it is possible to lock the file
335 :
336 0 : p_class->lock_file("OksMethod::set_name");
337 :
338 :
339 : // probably a non-direct method already exists
340 :
341 0 : OksMethod * m = p_class->find_method(new_name);
342 :
343 :
344 : // change the name
345 :
346 0 : p_name = new_name;
347 :
348 :
349 : // registrate the change
350 :
351 0 : p_class->registrate_class_change(OksClass::ChangeMethodsList, (const void *)m);
352 : }
353 : else {
354 0 : p_name = new_name;
355 : }
356 : }
357 :
358 : OksMethodImplementation *
359 0 : OksMethod::find_implementation(const std::string& language) const
360 : {
361 0 : if(p_implementations) {
362 0 : for(std::list<OksMethodImplementation *>::iterator i = p_implementations->begin(); i != p_implementations->end(); ++i)
363 0 : if(language == (*i)->get_language()) return *i;
364 : }
365 :
366 : return 0;
367 : }
368 :
369 : void
370 0 : OksMethod::add_implementation(const std::string& language, const std::string& prototype, const std::string& body)
371 : {
372 0 : if(find_implementation(language)) {
373 0 : std::ostringstream text;
374 0 : text << "Cannot add implementation on language \"" << language << "\" since it already exists.";
375 0 : throw oks::SetOperationFailed("OksMethod::add_implementation", text.str());
376 0 : }
377 :
378 0 : if(p_class) p_class->lock_file("OksMethod::add_implementation");
379 :
380 0 : if(!p_implementations) {
381 0 : p_implementations = new std::list<OksMethodImplementation *>();
382 : }
383 :
384 0 : OksMethodImplementation * i = new OksMethodImplementation(language, prototype, body);
385 :
386 0 : p_implementations->push_back(i);
387 0 : i->p_method = this;
388 :
389 0 : if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
390 0 : }
391 :
392 : void
393 0 : OksMethod::remove_implementation(const std::string& language)
394 : {
395 0 : OksMethodImplementation * i = find_implementation(language);
396 :
397 0 : if(i == 0) {
398 0 : std::ostringstream text;
399 0 : text << "Cannot remove implementation on language \"" << language << "\" since it does not exist.";
400 0 : throw oks::SetOperationFailed("OksMethod::remove_implementation", text.str());
401 0 : }
402 :
403 0 : if(p_class) p_class->lock_file("OksMethod::remove_implementation");
404 :
405 0 : p_implementations->remove(i);
406 :
407 0 : if(p_implementations->empty()) {
408 0 : delete p_implementations;
409 0 : p_implementations = 0;
410 : }
411 :
412 0 : if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
413 0 : }
414 :
415 :
416 : void
417 0 : OksMethod::set_description(const std::string& desc)
418 : {
419 0 : if(p_description != desc) {
420 0 : if(p_class) p_class->lock_file("OksMethod::set_description");
421 :
422 0 : p_description = desc;
423 :
424 0 : if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodDescription, (const void *)this);
425 : }
426 0 : }
427 :
428 : void
429 0 : OksMethodImplementation::set_language(const std::string& s)
430 : {
431 0 : if(p_language != s) {
432 0 : if(p_method) {
433 0 : if(p_method->find_implementation(s) != 0) {
434 0 : std::ostringstream text;
435 0 : text << "cannot rename \"" << p_method->p_name << "\" method implementation to language \"" << s << "\" "
436 0 : "since the method already has implementation with such language.";
437 0 : throw oks::SetOperationFailed("OksMethodImplementation::set_language", text.str());
438 0 : }
439 :
440 0 : try {
441 0 : oks::validate_not_empty(s, "language");
442 : }
443 0 : catch(std::exception& ex) {
444 0 : throw oks::SetOperationFailed("OksMethodImplementation::set_language", ex.what());
445 0 : }
446 :
447 0 : if(p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_language");
448 : }
449 :
450 0 : p_language = s;
451 :
452 0 : if(p_method && p_method->p_class) {
453 0 : p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
454 : }
455 : }
456 0 : }
457 :
458 : void
459 0 : OksMethodImplementation::set_prototype(const std::string& s)
460 : {
461 0 : if(p_prototype != s) {
462 0 : try {
463 0 : oks::validate_not_empty(s, "prototype");
464 : }
465 0 : catch(std::exception& ex) {
466 0 : throw oks::SetOperationFailed("OksMethodImplementation::set_prototype", ex.what());
467 0 : }
468 :
469 0 : if(p_method && p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_prototype");
470 :
471 0 : p_prototype = s;
472 :
473 0 : if(p_method && p_method->p_class) {
474 0 : p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
475 : }
476 : }
477 0 : }
478 :
479 : void
480 0 : OksMethodImplementation::set_body(const std::string& s)
481 : {
482 0 : if(p_body != s) {
483 0 : if(p_method && p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_body");
484 :
485 0 : p_body = s;
486 :
487 0 : if(p_method && p_method->p_class) {
488 0 : p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
489 : }
490 : }
491 0 : }
492 :
493 : } // namespace oks
494 : } // namespace dunedaq
|