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/attribute.hpp"
9 : #include "oks/class.hpp"
10 : #include "oks/cstring.hpp"
11 : #include "oks/kernel.hpp"
12 : #include "oks/object.hpp"
13 : #include "oks/xml.hpp"
14 :
15 : #include "logging/Logging.hpp"
16 :
17 : #include <sstream>
18 : #include <stdexcept>
19 :
20 : #include <string.h>
21 :
22 : namespace dunedaq {
23 : namespace oks {
24 :
25 : const char* OksAttribute::bool_type = "bool";
26 : const char* OksAttribute::s8_int_type = "s8";
27 : const char* OksAttribute::u8_int_type = "u8";
28 : const char* OksAttribute::s16_int_type = "s16";
29 : const char* OksAttribute::u16_int_type = "u16";
30 : const char* OksAttribute::s32_int_type = "s32";
31 : const char* OksAttribute::u32_int_type = "u32";
32 : const char* OksAttribute::s64_int_type = "s64";
33 : const char* OksAttribute::u64_int_type = "u64";
34 : const char* OksAttribute::float_type = "float";
35 : const char* OksAttribute::double_type = "double";
36 : const char* OksAttribute::date_type = "date";
37 : const char* OksAttribute::time_type = "time";
38 : const char* OksAttribute::string_type = "string";
39 : const char* OksAttribute::uid_type = "uid";
40 : const char* OksAttribute::enum_type = "enum";
41 : const char* OksAttribute::class_type = "class";
42 :
43 : const char OksAttribute::attribute_xml_tag[] = "attribute";
44 : const char OksAttribute::name_xml_attr[] = "name";
45 : const char OksAttribute::description_xml_attr[] = "description";
46 : const char OksAttribute::type_xml_attr[] = "type";
47 : const char OksAttribute::range_xml_attr[] = "range";
48 : const char OksAttribute::format_xml_attr[] = "format";
49 : const char OksAttribute::is_multi_value_xml_attr[] = "is-multi-value";
50 : const char OksAttribute::init_value_xml_attr[] = "init-value";
51 : const char OksAttribute::is_not_null_xml_attr[] = "is-not-null";
52 : const char OksAttribute::ordered_xml_attr[] = "ordered";
53 :
54 : OksAttribute::Format
55 45 : OksAttribute::str2format(const char* s) noexcept
56 : {
57 45 : return (cmp_str3(s, "dec") ? Dec : cmp_str3(s, "hex") ? Hex : Oct);
58 : }
59 :
60 : const char*
61 0 : OksAttribute::format2str(Format f) noexcept
62 : {
63 0 : return (f == Dec ? "dec" : f == Hex ? "hex" : "oct");
64 : }
65 :
66 : bool
67 19743 : OksAttribute::is_integer() const noexcept
68 : {
69 19743 : return (p_data_type >= OksData::s8_int_type && p_data_type <= OksData::u64_int_type);
70 : }
71 :
72 : bool
73 0 : OksAttribute::is_number() const noexcept
74 : {
75 0 : return (p_data_type >= OksData::s8_int_type && p_data_type <= OksData::bool_type);
76 : }
77 :
78 : void
79 11955 : OksAttribute::init_enum()
80 : {
81 11955 : if (p_data_type == OksData::enum_type) {
82 898 : if (p_enumerators) {
83 0 : p_enumerators->clear();
84 : } else {
85 898 : p_enumerators = new std::vector<std::string>();
86 : }
87 :
88 898 : Oks::Tokenizer t(p_range, ",");
89 898 : std::string token;
90 :
91 4932 : while (t.next(token)) {
92 3136 : p_enumerators->push_back(token);
93 : }
94 :
95 898 : if (p_enumerators->empty()) {
96 0 : std::ostringstream text;
97 0 : text << "range of enumeration attribute \"" << p_name << "\" is empty";
98 0 : throw std::runtime_error(text.str().c_str());
99 0 : }
100 898 : }
101 11955 : }
102 :
103 : void
104 11955 : OksAttribute::init_range()
105 : {
106 11955 : clean_range();
107 :
108 11955 : if (p_range.empty() == false) {
109 1094 : p_range_obj = new OksRange(p_range, this);
110 1094 : if (p_range_obj->is_empty()) {
111 0 : clean_range();
112 : }
113 : }
114 11955 : }
115 :
116 : int
117 0 : OksAttribute::get_enum_index(const char* s, size_t length) const noexcept
118 : {
119 0 : if (p_data_type == OksData::enum_type) {
120 0 : for (int i = 0; i < (int)p_enumerators->size(); ++i) {
121 0 : const std::string* x = &((*p_enumerators)[i]);
122 0 : if (x->length() == length) {
123 0 : if (memcmp(s, x->data(), length) == 0) {
124 : return i;
125 : }
126 : }
127 : }
128 :
129 : return (-1);
130 : }
131 :
132 : return (-2);
133 : }
134 :
135 : const std::string*
136 5667 : OksAttribute::get_enum_value(const char* s, size_t length) const
137 : {
138 5667 : if (p_data_type == OksData::enum_type) {
139 16191 : for (unsigned int i = 0; i < p_enumerators->size(); ++i) {
140 16191 : const std::string* x = &((*p_enumerators)[i]);
141 16191 : if (x->length() == length) {
142 7319 : if (memcmp(s, x->data(), length) == 0) {
143 5667 : return x;
144 : }
145 : }
146 : }
147 :
148 0 : std::ostringstream text;
149 0 : text << "value \'" << s << "\' is out of range \'" << get_range() << '\'';
150 0 : throw std::runtime_error(text.str().c_str());
151 0 : }
152 :
153 0 : throw std::runtime_error("attribute is not enumeration");
154 : }
155 :
156 : uint16_t
157 0 : OksAttribute::get_enum_value(const OksData& d) const noexcept
158 : {
159 0 : const std::string* p_enumerators_first(&((*p_enumerators)[0]));
160 0 : return (d.data.ENUMERATION - p_enumerators_first);
161 : }
162 :
163 : void
164 11955 : validate_init2range(const OksAttribute* a)
165 : {
166 11955 : if (!a->get_range().empty() && a->get_data_type() != OksData::class_type) {
167 1094 : try {
168 1094 : OksData d;
169 1094 : d.set_init_value(a, false);
170 1094 : d.check_range(a);
171 1094 : } catch (std::exception& ex) {
172 0 : std::ostringstream text;
173 0 : text << "failed to set initial value \'" << a->get_init_value() << "\' of attribute \'" << a->get_name()
174 : << "\':\n"
175 0 : << ex.what();
176 0 : throw std::runtime_error(text.str().c_str());
177 0 : }
178 : }
179 11955 : }
180 :
181 0 : OksAttribute::OksAttribute(const std::string& nm, OksClass* p)
182 0 : : p_name(nm)
183 0 : , p_data_type(OksData::string_type)
184 0 : , p_multi_values(false)
185 0 : , p_no_null(false)
186 0 : , p_format(OksAttribute::Dec)
187 0 : , p_class(p)
188 0 : , p_enumerators(nullptr)
189 0 : , p_range_obj(nullptr)
190 0 : , p_ordered(false)
191 :
192 : {
193 0 : validate_not_empty(p_name, "attribute name");
194 0 : }
195 :
196 0 : OksAttribute::OksAttribute(const std::string& nm,
197 : const std::string& t,
198 : bool is_mv,
199 : const std::string& r,
200 : const std::string& init_v,
201 : const std::string& ds,
202 : bool no_null,
203 : Format f,
204 0 : OksClass* p)
205 0 : : p_name(nm)
206 0 : , p_range(r)
207 0 : , p_data_type(get_data_type(t))
208 0 : , p_multi_values(is_mv)
209 0 : , p_no_null(no_null)
210 0 : , p_init_value(init_v)
211 0 : , p_format(f)
212 0 : , p_description(ds)
213 0 : , p_class(p)
214 0 : , p_enumerators(nullptr)
215 0 : , p_range_obj(nullptr)
216 0 : , p_ordered(false)
217 : {
218 0 : set_type(t, true);
219 0 : validate_not_empty(p_name, "attribute name");
220 0 : init_enum();
221 0 : init_range();
222 : // cannot call set_init_data() because of the CLASS data type, since other class may not be known yet;
223 : // initialize the init_data in the register_all_classes() call
224 0 : }
225 :
226 : bool
227 530 : OksAttribute::operator==(const class OksAttribute& a) const
228 : {
229 530 : return ((this == &a) ||
230 0 : ((p_name == a.p_name) && (p_range == a.p_range) && (p_data_type == a.p_data_type) &&
231 0 : (p_multi_values == a.p_multi_values) && (p_init_value == a.p_init_value) &&
232 0 : (p_description == a.p_description) && (p_no_null == a.p_no_null) && (p_ordered == a.p_ordered)));
233 : }
234 :
235 : std::ostream&
236 0 : operator<<(std::ostream& s, const OksAttribute& a)
237 : {
238 0 : s << "Attribute name: \"" << a.p_name
239 : << "\"\n"
240 : " type: \""
241 0 : << a.get_type()
242 : << "\"\n"
243 : " range: \""
244 0 : << a.p_range << "\"\n";
245 :
246 0 : if (a.is_integer()) {
247 0 : s << " format: \"" << OksAttribute::format2str(a.p_format) << "\"\n";
248 : }
249 :
250 0 : if (a.p_multi_values == true) {
251 0 : s << " is \'multi values\'\n";
252 : } else {
253 0 : s << " is \'single value\'\n";
254 : }
255 :
256 0 : s << " initial value: \"" << a.p_init_value
257 : << "\"\n"
258 : " has description: \""
259 0 : << a.p_description << "\"\n"
260 0 : << (a.p_no_null == true ? " can not be null\n" : " can be null\n") << " is "
261 0 : << (a.p_ordered == true ? "ordered" : "unordered") << std::endl;
262 :
263 0 : return s;
264 : }
265 :
266 : void
267 0 : OksAttribute::save(OksXmlOutputStream& s) const
268 : {
269 0 : if (p_data_type == OksData::class_type && p_init_value.empty() && p_multi_values == false) {
270 0 : std::ostringstream text;
271 0 : text << "single-value attribute \"" << p_name << "\" is of \"class_type\" and has empty init value";
272 0 : throw std::runtime_error(text.str().c_str());
273 0 : }
274 :
275 0 : validate_init2range(this);
276 :
277 0 : s.put(" ");
278 0 : s.put_start_tag(attribute_xml_tag, sizeof(attribute_xml_tag) - 1);
279 :
280 0 : s.put_attribute(name_xml_attr, sizeof(name_xml_attr) - 1, p_name.c_str());
281 :
282 0 : if (!p_description.empty())
283 0 : s.put_attribute(description_xml_attr, sizeof(description_xml_attr) - 1, p_description.c_str());
284 :
285 0 : s.put_attribute(type_xml_attr, sizeof(type_xml_attr) - 1, get_type().c_str());
286 :
287 0 : if (!p_range.empty())
288 0 : s.put_attribute(range_xml_attr, sizeof(range_xml_attr) - 1, p_range.c_str());
289 :
290 0 : if (is_integer() && p_format != OksAttribute::Dec)
291 0 : s.put_attribute(format_xml_attr, sizeof(format_xml_attr) - 1, format2str(p_format));
292 :
293 0 : if (p_multi_values)
294 0 : s.put_attribute(is_multi_value_xml_attr, sizeof(is_multi_value_xml_attr) - 1, xml::bool2str(p_multi_values));
295 :
296 0 : if (!p_init_value.empty())
297 0 : s.put_attribute(init_value_xml_attr, sizeof(init_value_xml_attr) - 1, p_init_value.c_str());
298 :
299 0 : if (p_no_null)
300 0 : s.put_attribute(is_not_null_xml_attr, sizeof(is_not_null_xml_attr) - 1, xml::bool2str(p_no_null));
301 :
302 0 : if (p_ordered)
303 0 : s.put_attribute(ordered_xml_attr, sizeof(ordered_xml_attr) - 1, xml::bool2str(p_ordered));
304 :
305 0 : s.put_end_tag();
306 0 : }
307 :
308 11955 : OksAttribute::OksAttribute(OksXmlInputStream& s, OksClass* parent)
309 11955 : : p_data_type(OksData::unknown_type)
310 11955 : , p_multi_values(false)
311 11955 : , p_no_null(false)
312 11955 : , p_format(OksAttribute::Dec)
313 11955 : , p_class(parent)
314 11955 : , p_enumerators(nullptr)
315 11955 : , p_range_obj(nullptr)
316 11955 : , p_ordered(false)
317 : {
318 : // read attributes of OksAttribute from xml
319 :
320 60261 : try {
321 108567 : while (true) {
322 60261 : OksXmlAttribute attr(s);
323 :
324 : // check for close of tag
325 :
326 60261 : if (cmp_str1(attr.name(), "/")) {
327 : break;
328 : }
329 :
330 : // check for known oks-attribute' attributes
331 :
332 48306 : else if (cmp_str4(attr.name(), name_xml_attr))
333 11955 : p_name.assign(attr.value(), attr.value_len());
334 36351 : else if (cmp_str11(attr.name(), description_xml_attr))
335 6533 : p_description.assign(attr.value(), attr.value_len());
336 29818 : else if (cmp_str4(attr.name(), type_xml_attr)) {
337 11955 : __set_data_type(attr.value(), attr.value_len());
338 11955 : if (p_data_type == OksData::unknown_type) {
339 0 : throw BadFileData(std::string("Value \'") + attr.value() + "\' is not a valid attribute type",
340 : s.get_line_no(),
341 0 : s.get_line_pos());
342 : }
343 17863 : } else if (cmp_str5(attr.name(), range_xml_attr))
344 1094 : p_range.assign(attr.value(), attr.value_len());
345 16769 : else if (cmp_str6(attr.name(), format_xml_attr))
346 45 : p_format = str2format(attr.value());
347 16724 : else if (cmp_str14(attr.name(), is_multi_value_xml_attr))
348 919 : p_multi_values = xml::str2bool(attr.value());
349 15805 : else if (cmp_str10(attr.name(), init_value_xml_attr))
350 7816 : p_init_value.assign(attr.value(), attr.value_len());
351 7989 : else if (cmp_str11(attr.name(), is_not_null_xml_attr))
352 7989 : p_no_null = xml::str2bool(attr.value());
353 0 : else if (cmp_str7(attr.name(), ordered_xml_attr))
354 0 : p_ordered = xml::str2bool(attr.value());
355 0 : else if (!strcmp(attr.name(), "multi-value-implementation"))
356 0 : s.error_msg("OksAttribute::OksAttribute(OksXmlInputStream&)")
357 0 : << "Obsolete oks-attribute\'s attribute \'" << attr.name() << "\'\n";
358 : else
359 0 : s.throw_unexpected_attribute(attr.name());
360 48306 : }
361 0 : } catch (exception& e) {
362 0 : throw FailedRead("xml attribute", e);
363 0 : } catch (std::exception& e) {
364 0 : throw FailedRead("xml attribute", e.what());
365 0 : }
366 :
367 : // check validity of read values
368 :
369 11955 : if (p_data_type == OksData::unknown_type) {
370 0 : throw FailedRead("oks attribute", BadFileData("attribute type is not set", s.get_line_no(), s.get_line_pos()));
371 : }
372 :
373 11955 : try {
374 11955 : validate_not_empty(p_name, "attribute name");
375 11955 : init_enum();
376 11955 : init_range();
377 0 : } catch (std::exception& ex) {
378 0 : throw FailedRead("oks attribute", BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
379 0 : }
380 :
381 11955 : if (p_init_value.empty()) {
382 4139 : if (p_data_type == OksData::class_type && p_multi_values == false) {
383 0 : std::ostringstream text;
384 0 : text << "single-value attribute \"" << p_name << "\" is of \"class_type\" and has empty init value";
385 0 : throw FailedRead("oks attribute", BadFileData(text.str(), s.get_line_no(), s.get_line_pos()));
386 0 : }
387 : } else {
388 7816 : if (p_data_type == OksData::date_type || p_data_type == OksData::time_type) {
389 0 : try {
390 0 : OksData _d;
391 0 : if (p_multi_values) {
392 0 : _d.SetValues(p_init_value.c_str(), this);
393 : } else {
394 0 : _d.type = p_data_type;
395 0 : _d.SetValue(p_init_value.c_str(), 0);
396 : }
397 0 : } catch (exception& ex) {
398 0 : std::ostringstream text;
399 0 : text << "attribute \"" << p_name << "\" has bad init value:\n" << ex.what();
400 0 : throw FailedRead("oks attribute", BadFileData(text.str(), s.get_line_no(), s.get_line_pos()));
401 0 : }
402 : }
403 : }
404 :
405 11955 : try {
406 11955 : validate_init2range(this);
407 0 : } catch (std::exception& ex) {
408 0 : std::ostringstream text;
409 0 : text << "attribute \"" << p_name << "\" has mismatch between init value and range:\n" << ex.what();
410 0 : throw FailedRead("oks attribute", BadFileData(text.str(), s.get_line_no(), s.get_line_pos()));
411 0 : }
412 :
413 : // set_init_data();
414 11955 : }
415 :
416 : OksData::Type
417 0 : OksAttribute::get_data_type(const std::string& t) noexcept
418 : {
419 0 : return get_data_type(t.c_str(), t.size());
420 : }
421 :
422 : OksData::Type
423 22361 : OksAttribute::get_data_type(const char* t, size_t len) noexcept
424 : {
425 22361 : switch (len) {
426 8386 : case 3:
427 8386 : if (cmp_str3n(t, uid_type))
428 : return OksData::uid2_type; // "uid"
429 8386 : else if (cmp_str3n(t, u32_int_type))
430 : return OksData::u32_int_type; // "u32"
431 1965 : else if (cmp_str3n(t, s32_int_type))
432 : return OksData::s32_int_type; // "s32"
433 1328 : else if (cmp_str3n(t, u16_int_type))
434 : return OksData::u16_int_type; // "u16"
435 368 : else if (cmp_str3n(t, s16_int_type))
436 : return OksData::s16_int_type; // "s16"
437 272 : else if (cmp_str3n(t, s64_int_type))
438 : return OksData::s64_int_type; // "s64"
439 218 : else if (cmp_str3n(t, u64_int_type))
440 218 : return OksData::u64_int_type; // "u64"
441 : break;
442 :
443 9831 : case 6:
444 9831 : if (cmp_str6n(t, string_type))
445 : return OksData::string_type; // "string"
446 23 : else if (cmp_str6n(t, double_type))
447 23 : return OksData::double_type; // "double"
448 : break;
449 :
450 3359 : case 4:
451 3359 : if (cmp_str4n(t, bool_type))
452 : return OksData::bool_type; // "bool"
453 1693 : else if (cmp_str4n(t, enum_type))
454 : return OksData::enum_type; // "enum"
455 0 : else if (cmp_str4n(t, date_type))
456 : return OksData::date_type; // "date"
457 0 : else if (cmp_str4n(t, time_type))
458 0 : return OksData::time_type; // "time"
459 : break;
460 :
461 491 : case 5:
462 491 : if (cmp_str5n(t, float_type))
463 : return OksData::float_type; // "float"
464 320 : else if (cmp_str5n(t, class_type))
465 320 : return OksData::class_type; // "class"
466 : break;
467 :
468 294 : case 2:
469 294 : if (cmp_str2n(t, s8_int_type))
470 : return OksData::s8_int_type; // "s8"
471 294 : else if (cmp_str2n(t, u8_int_type))
472 294 : return OksData::u8_int_type; // "u8"
473 : break;
474 : }
475 :
476 : return OksData::unknown_type;
477 : }
478 :
479 : const std::string&
480 0 : OksAttribute::get_type() const throw()
481 : {
482 0 : static std::string __types[] = {
483 : "unknown", // unknown_type = 0
484 : "s8", // s8_int_type = 1
485 : "u8", // u8_int_type = 2
486 : "s16", // s16_int_type = 3,
487 : "u16", // u16_int_type = 4,
488 : "s32", // s32_int_type = 5,
489 : "u32", // u32_int_type = 6,
490 : "s64", // s64_int_type = 7,
491 : "u64", // u64_int_type = 8,
492 : "float", // float_type = 9,
493 : "double", // double_type = 10,
494 : "bool", // bool_type = 11,
495 : "class", // class_type = 12,
496 : "object", // object_type = 13,
497 : "date", // date_type = 14,
498 : "time", // time_type = 15,
499 : "string", // string_type = 16,
500 : "list", // list_type = 17,
501 : "uid", // uid_type = 18,
502 : "uid2", // uid2_type = 19,
503 : "enum" // enum_type = 20
504 0 : };
505 :
506 0 : return __types[(int)p_data_type];
507 : }
508 :
509 : void
510 0 : OksAttribute::set_type(const std::string& t, bool skip_init)
511 : {
512 0 : OksData::Type p_dt = get_data_type(t);
513 :
514 0 : if (p_dt == OksData::unknown_type) {
515 0 : std::ostringstream text;
516 0 : text << "the type \'" << t << "\' is not valid";
517 0 : throw SetOperationFailed("OksAttribute::set_type", text.str());
518 0 : }
519 :
520 0 : if (p_data_type == p_dt)
521 : return;
522 :
523 0 : if (p_class)
524 0 : p_class->lock_file("OksAttribute::set_type");
525 :
526 0 : p_data_type = p_dt;
527 :
528 0 : if (skip_init == false) {
529 0 : try {
530 0 : init_enum();
531 0 : init_range();
532 0 : } catch (std::exception& ex) {
533 0 : throw SetOperationFailed("OksAttribute::set_type", ex.what());
534 0 : }
535 : }
536 :
537 0 : if (p_class) {
538 0 : p_class->registrate_attribute_change(this);
539 0 : p_class->registrate_class_change(OksClass::ChangeAttributeType, (const void*)this);
540 : }
541 : }
542 :
543 : void
544 0 : OksAttribute::set_name(const std::string& new_name)
545 : {
546 : // ignore when name is the same
547 :
548 0 : if (p_name == new_name)
549 : return;
550 :
551 : // additional checks are required,
552 : // if the attribute already belongs to some class
553 :
554 0 : if (p_class) {
555 : // check allowed length for attribute name
556 :
557 0 : try {
558 0 : validate_not_empty(new_name, "name");
559 0 : } catch (std::exception& ex) {
560 0 : throw SetOperationFailed("OksAttribute::set_name", ex.what());
561 0 : }
562 :
563 : // having a direct attribute with the same name is an error
564 :
565 0 : if (p_class->find_direct_attribute(new_name) != 0) {
566 0 : std::ostringstream text;
567 0 : text << "Class \"" << p_class->get_name() << "\" already has direct attribute \"" << new_name << '\"';
568 0 : throw SetOperationFailed("OksAttribute::set_name", text.str());
569 0 : }
570 :
571 : // check that the file can be updated
572 :
573 0 : p_class->lock_file("OksAttribute::set_name");
574 :
575 : // probably a non-direct attribute already exists
576 :
577 0 : OksAttribute* a = p_class->find_attribute(new_name);
578 :
579 : // change the name
580 :
581 0 : p_name = new_name;
582 :
583 : // registrate the change
584 :
585 0 : p_class->registrate_class_change(OksClass::ChangeAttributesList, (const void*)a);
586 : } else {
587 0 : p_name = new_name;
588 : }
589 : }
590 :
591 : void
592 0 : OksAttribute::set_is_multi_values(bool is_mv)
593 : {
594 0 : if (p_multi_values != is_mv) {
595 0 : if (p_class)
596 0 : p_class->lock_file("OksAttribute::set_is_multi_values");
597 :
598 0 : p_multi_values = is_mv;
599 :
600 0 : if (p_class) {
601 0 : p_class->registrate_class_change(OksClass::ChangeAttributeMultiValueCardinality, (const void*)this);
602 0 : p_class->registrate_attribute_change(this);
603 : }
604 : }
605 0 : }
606 :
607 : void
608 0 : OksAttribute::set_init_value(const std::string& init_v)
609 : {
610 0 : if (p_init_value != init_v) {
611 0 : std::string old_value = p_init_value;
612 :
613 0 : if (p_class)
614 0 : p_class->lock_file("OksAttribute::set_init_value");
615 :
616 0 : p_init_value = init_v;
617 :
618 0 : try {
619 0 : validate_init2range(this);
620 0 : } catch (...) {
621 0 : p_init_value = old_value;
622 0 : throw;
623 0 : }
624 :
625 0 : if (p_class)
626 0 : p_class->registrate_class_change(OksClass::ChangeAttributeInitValue, (const void*)this);
627 0 : }
628 0 : }
629 :
630 : void
631 0 : OksAttribute::set_description(const std::string& ds)
632 : {
633 0 : if (p_description != ds) {
634 0 : if (p_class)
635 0 : p_class->lock_file("OksAttribute::set_description");
636 :
637 0 : p_description = ds;
638 :
639 0 : if (p_class)
640 0 : p_class->registrate_class_change(OksClass::ChangeAttributeDescription, (const void*)this);
641 : }
642 0 : }
643 :
644 : void
645 0 : OksAttribute::set_is_no_null(bool no_null)
646 : {
647 0 : if (p_no_null != no_null) {
648 0 : if (p_class)
649 0 : p_class->lock_file("OksAttribute::set_is_no_null");
650 :
651 0 : p_no_null = no_null;
652 :
653 0 : if (p_class)
654 0 : p_class->registrate_class_change(OksClass::ChangeAttributeIsNoNull, (const void*)this);
655 : }
656 0 : }
657 :
658 : void
659 0 : OksAttribute::set_format(Format f)
660 : {
661 0 : if (f != p_format) {
662 0 : if (p_class)
663 0 : p_class->lock_file("OksAttribute::set_format");
664 :
665 0 : p_format = f;
666 :
667 0 : if (p_class)
668 0 : p_class->registrate_class_change(OksClass::ChangeAttributeFormat, (const void*)this);
669 : }
670 0 : }
671 :
672 : void
673 0 : OksAttribute::set_range(const std::string& s)
674 : {
675 0 : if (s != p_range) {
676 0 : std::string old_value = p_range;
677 :
678 0 : if (p_class)
679 0 : p_class->lock_file("OksAttribute::set_range");
680 :
681 0 : p_range.erase();
682 0 : int count = 0;
683 0 : Oks::Tokenizer t(s, ", \t");
684 0 : std::string token;
685 :
686 0 : while (t.next(token)) {
687 0 : if (count++ != 0) {
688 0 : p_range += ',';
689 : }
690 :
691 0 : p_range += token;
692 : }
693 :
694 0 : if (count != 0) {
695 0 : if (p_data_type == OksData::bool_type) {
696 0 : p_range.erase();
697 0 : throw SetOperationFailed("OksAttribute::set_range", "boolean type can't have user-defined range!");
698 : }
699 : }
700 :
701 0 : try {
702 0 : init_enum();
703 0 : init_range();
704 0 : validate_init2range(this);
705 0 : } catch (std::exception& ex) {
706 0 : p_range = old_value;
707 :
708 0 : try {
709 0 : init_enum();
710 0 : } catch (...) {
711 0 : ;
712 0 : }
713 :
714 0 : try {
715 0 : init_range();
716 0 : } catch (...) {
717 0 : ;
718 0 : }
719 :
720 0 : throw SetOperationFailed("OksAttribute::set_range", ex.what());
721 0 : }
722 :
723 0 : if (p_class)
724 0 : p_class->registrate_class_change(OksClass::ChangeAttributeRange, (const void*)this);
725 0 : }
726 0 : }
727 :
728 : bool
729 0 : OksAttribute::find_token(const char* token, const char* range) noexcept
730 : {
731 0 : const char* p;
732 :
733 0 : if (token && (p = strstr(range, token)) != 0) {
734 0 : int len = strlen(token);
735 :
736 0 : do {
737 0 : if (((p != range) && (p[-1] != ',')) || ((p[len] != ',') && (p[len] != '\0'))) {
738 0 : p = strstr(p + 1, token);
739 : } else {
740 : return true;
741 : }
742 :
743 0 : } while (p != 0);
744 : }
745 :
746 : return false;
747 : }
748 :
749 : inline bool
750 6779 : is_star(const std::string& s)
751 : {
752 6779 : return (s.size() == 1 && s[0] == '*');
753 : }
754 :
755 : void
756 1094 : OksRange::reset(const std::string& range, OksAttribute* a)
757 : {
758 1094 : clear();
759 :
760 1094 : if (a->get_data_type() != OksData::string_type) {
761 1067 : if (!range.empty()) {
762 1067 : Oks::Tokenizer t(range, ",");
763 1067 : std::string token, token1, token2;
764 :
765 5439 : while (t.next(token)) {
766 3305 : if (is_star(token)) {
767 0 : TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' allows any value";
768 0 : clear();
769 0 : return;
770 : }
771 :
772 3305 : static const char __dot_dot_str[] = "..";
773 3305 : std::string::size_type p = token.find(__dot_dot_str, 0, (sizeof(__dot_dot_str) - 1));
774 :
775 3305 : bool pi; // if true, then it is plus infinity, i.e. x..*
776 :
777 3305 : if (p != std::string::npos) {
778 169 : token1.assign(token, 0, p);
779 169 : token2.assign(token, p + 2, std::string::npos);
780 169 : pi = (is_star(token2));
781 : } else {
782 3136 : token1.assign(token);
783 3136 : token2.clear();
784 3136 : pi = false;
785 : }
786 :
787 3305 : bool mi = (is_star(token1)); // if true, then it is minus infinity, i.e. *..x
788 :
789 3305 : if (mi && pi) {
790 0 : TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' allows any value";
791 0 : clear();
792 0 : return;
793 : }
794 :
795 3305 : OksData d1, d2;
796 :
797 3305 : if (!mi) {
798 3305 : d1.type = a->get_data_type();
799 3305 : d1.ReadFrom(token1, a);
800 : }
801 :
802 3305 : if (token2.empty()) {
803 3136 : TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines equality condition";
804 3136 : m_equal.emplace_back(d1);
805 : } else {
806 169 : if (!pi) {
807 169 : d2.type = a->get_data_type();
808 169 : d2.ReadFrom(token2, a);
809 : }
810 :
811 169 : if (mi) {
812 0 : TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines smaller condition";
813 0 : m_less.emplace_back(d2);
814 169 : } else if (pi) {
815 0 : TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines greater condition";
816 0 : m_great.emplace_back(d1);
817 : } else {
818 169 : TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines interval condition";
819 169 : m_interval.emplace_back(d1, d2);
820 : }
821 : }
822 3305 : }
823 1067 : }
824 : } else {
825 27 : try {
826 27 : m_like.emplace_back(range);
827 0 : } catch (std::exception& ex) {
828 0 : throw BadReqExp(range, ex.what());
829 0 : }
830 : }
831 : }
832 :
833 : bool
834 1975 : OksRange::validate(const OksData& d) const
835 : {
836 1975 : for (const auto& x : m_less) {
837 0 : if (d <= x)
838 0 : return true;
839 : }
840 :
841 1975 : for (const auto& x : m_great) {
842 0 : if (d >= x)
843 0 : return true;
844 : }
845 :
846 3412 : for (const auto& x : m_equal) {
847 3123 : if (d == x)
848 1686 : return true;
849 : }
850 :
851 289 : for (const auto& x : m_interval) {
852 253 : if (d >= x.first && d <= x.second)
853 253 : return true;
854 : }
855 :
856 36 : for (const auto& x : m_like) {
857 36 : if (OksKernel::get_skip_string_range())
858 36 : return true;
859 :
860 36 : if (boost::regex_match(d.str(), x))
861 : return true;
862 : }
863 :
864 0 : return false;
865 : }
866 :
867 : } // namespace oks
868 : } // namespace dunedaq
|