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