MIDAS
Loading...
Searching...
No Matches
odbxx.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: odbxx.cxx
4 Created by: Stefan Ritt
5
6 Contents: Object oriented interface to ODB implementation file
7
8\********************************************************************/
9
10#include <string>
11#include <iostream>
12#include <fstream>
13#include <sstream>
14#include <map>
15#include <stdexcept>
16#include <algorithm>
17#include <initializer_list>
18#include <cstring>
19#include <bitset>
20#include <functional>
21
22#include "midas.h"
23#include "odbxx.h"
24#include "mexcept.h"
25#include "mstrlcpy.h"
26#include "mjson.h"
27
28// #include "mleak.hxx" // un-comment for memory leak debugging
29
30/*------------------------------------------------------------------*/
31
32namespace midas {
33
34 //----------------------------------------------------------------
35
36 // initialize static variables
37 HNDLE odb::s_hDB = 0;
38 bool odb::s_debug = false;
39 bool odb::s_connected_odb = false;
40 std::vector<midas::odb *> g_watchlist = {};
41
42 //---- static initializers ---------------------------------------
44 std::string odb::s_odb_source_str = std::string("");
45
46 // static functions ----------------------------------------------
47
48 // initialize s_hDB, internal use only
51 mthrow("Operation only possible if connected to an online ODB");
52
53 if (s_hDB == 0)
55 if (s_hDB == 0)
56 mthrow("Please call cm_connect_experiment() before accessing the ODB");
57 s_connected_odb = true;
58 }
59
60 // search for a key with a specific hKey, needed for callbacks
62 if (po->m_hKey == hKey)
63 return po;
64 if (po->m_tid == TID_KEY) {
65 for (int i = 0; i < po->m_num_values; i++) {
66 midas::odb *pot = search_hkey(po->m_data[i].get_podb(), hKey);
67 if (pot != nullptr)
68 return pot;
69 }
70 }
71 return nullptr;
72 }
73
74 // check if a key exists in the ODB
75 bool odb::exists(const std::string &name) {
76 init_hdb();
78 return false;
79 HNDLE hkey;
80 return db_find_key(s_hDB, 0, name.c_str(), &hkey) == DB_SUCCESS;
81 }
82
83 // delete a key in the ODB
84 int odb::delete_key(const std::string &name) {
85 init_hdb();
87 return false;
88 HNDLE hkey;
89 auto status = db_find_key(s_hDB, 0, name.c_str(), &hkey);
90 if (status != DB_SUCCESS) {
91 if (s_debug)
92 std::cout << "Delete key " + name << " not found in ODB" << std::endl;
93 return status;
94 }
95 if (s_debug)
96 std::cout << "Delete ODB key " + name << std::endl;
97 return db_delete_key(s_hDB, hkey, false);
98 }
99
100 // load file into ODB
101 void odb::load(const std::string &filename, const std::string &odb_path) {
102 init_hdb();
104 mthrow("Cannot connect to ODB");
105
106 HNDLE hkey;
107 auto status = db_find_key(s_hDB, 0, odb_path.c_str(), &hkey);
108 if (status == DB_NO_KEY)
109 db_create_key(s_hDB, 0, odb_path.c_str(), TID_KEY);
110 status = db_find_key(s_hDB, 0, odb_path.c_str(), &hkey);
111 if (status != DB_SUCCESS)
112 mthrow("ODB path " + odb_path + " not found in ODB");
113
114 KEY key;
116 if (key.type != TID_KEY)
117 mthrow("ODB path " + odb_path + " does not point to a directory");
118
119 db_load(s_hDB, hkey, filename.c_str(), false);
120 }
121
122 // global callback function for db_watch()
123 void odb::watch_callback(int hDB, int hKey, int index, void *info) {
124 midas::odb *po = static_cast<midas::odb *>(info);
125 if (po->m_data == nullptr)
126 mthrow("Callback received for a midas::odb object which went out of scope");
128 if (poh == nullptr) {
129 auto s = db_get_path(hDB, hKey);
130 mthrow("New key \"" + s + "\" has been created in ODB after calling watch()");
131 }
132
133 poh->m_last_index = index;
134 po->m_watch_callback(*poh);
135 poh->m_last_index = -1;
136 }
137
138 // create ODB key
139 int odb::create(const char *name, int type) {
140 init_hdb();
141 int status = -1;
142 if (is_connected_odb())
145 mthrow("Cannot create key " + std::string(name) + ", db_create_key() status = " + std::to_string(status));
146 return status;
147 }
148
149 // private functions ---------------------------------------------
150
152 m_flags = f;
153 if (m_tid == TID_KEY) {
154 for (int i = 0; i < m_num_values; i++)
155 m_data[i].get_odb().set_flags_recursively(f);
156 }
157 }
158
159 void odb::odb_from_xml_remote(const std::string &str) {
160 init_hdb();
161
162 HNDLE hKey;
163 int status = db_find_key(s_hDB, 0, str.c_str(), &hKey);
164 if (status != DB_SUCCESS)
165 mthrow("ODB key \"" + str + "\" not found in ODB");
166
167 int bsize = 1000000;
168 char *buffer = (char *)malloc(bsize);
169 do {
170 int size = bsize;
171 status = db_copy_xml(s_hDB, hKey, buffer, &size, false);
172 if (status == DB_TRUNCATED) {
173 bsize *= 2;
174 buffer = (char *)realloc(buffer, bsize);
175 }
176 } while (status == DB_TRUNCATED);
177
178 if (status != DB_SUCCESS)
179 mthrow("Cannot retrieve XML data, status = " + std::to_string(status));
180
181 if (s_debug)
182 std::cout << "Retrieved XML tree for \"" + str + "\"" << std::endl;
183
184 char error[256] = "";
185 PMXML_NODE tree = mxml_parse_buffer(buffer, error, sizeof(error), NULL);
186 if (error[0]) {
187 std::cout << "MXML error, buffer =\n" << buffer << std::endl;
188 mthrow("MXML error: " + std::string(error));
189 }
190 free(buffer);
191
192 odb_from_xml(&tree->child[2], this);
193 m_hKey = hKey;
194
196 }
197
198 void odb::odb_from_xml_string(const std::string &str, const std::string &subkey) {
199 char error[256] = "";
200 PMXML_NODE tree = mxml_parse_buffer(str.c_str(), error, sizeof(error), NULL);
201 if (error[0]) {
202 std::cout << "MXML error, buffer =\n" << str << std::endl;
203 mthrow("MXML error: " + std::string(error));
204 }
205
207 if (subkey == "/")
208 root = &tree->child[2];
209 else {
210 // convert ODB path to XPATH
211 std::stringstream ss(subkey);
212 std::string dir, xpath;
213 while (std::getline(ss, dir, '/'))
214 if (!dir.empty())
215 xpath += "/dir[@name=\"" + dir + "\"]";
216
217 // std::string query("/dir[@name=\"Buffer sizes\"]");
218 root = mxml_find_node(&tree->child[2], xpath.c_str());
219 if (root == nullptr) {
220 // try with last element being a key
221 size_t pos = xpath.rfind("dir");
222 if (pos != std::string::npos)
223 xpath.replace(pos, 3, "key");
224 root = mxml_find_node(&tree->child[2], xpath.c_str());
225 if (root == nullptr)
226 mthrow("ODB key \"" + subkey + "\" not found in ODB");
227 }
228 }
229
230 odb_from_xml(root, this);
232
233 this->set_auto_create(false);
234 this->set_auto_refresh_read(false);
235 this->set_auto_refresh_write(false);
236 this->set_auto_enlarge_array(false);
237 this->set_write_protect(true);
238 this->set_trigger_hotlink(false);
239 }
240
241 void odb::odb_from_json_string(const std::string &str, const std::string &subkey) {
242
243 MJsonNode* node = MJsonNode::Parse(str.c_str());
244 node->Dump();
245
246 odb_from_json(node, "root", this);
247
248 this->set_auto_create(false);
249 this->set_auto_refresh_read(false);
250 this->set_auto_refresh_write(false);
251 this->set_auto_enlarge_array(false);
252 this->set_write_protect(true);
253 this->set_trigger_hotlink(false);
254 }
255
256 // resize internal m_data array, keeping old values
257 void odb::resize_mdata(int size) {
258 auto new_array = new u_odb[size]{};
259 int i;
260 for (i = 0; i < m_num_values && i < size; i++) {
261 new_array[i] = m_data[i];
262 if (m_tid == TID_KEY)
263 m_data[i].set_odb(nullptr); // move odb*
264 if (m_tid == TID_STRING || m_tid == TID_LINK)
265 m_data[i].set_string_ptr(nullptr); // move std::string*
266 }
267 for (; i < size; i++) {
268 if (m_tid == TID_STRING || m_tid == TID_LINK)
269 new_array[i].set_string(""); // allocates new string
270 }
271 delete[] m_data;
274 for (i = 0; i < m_num_values; i++) {
276 m_data[i].set_parent(this);
277 }
278 }
279
280 // get function for strings
281 void odb::get(std::string &s, bool quotes, bool refresh) {
282 if (refresh && is_auto_refresh_read())
283 read();
284
285 // put value into quotes
286 s = "";
287 std::string sd;
288 for (int i = 0; i < m_num_values; i++) {
289 m_data[i].get(sd);
290 if (quotes)
291 s += "\"";
292 s += sd;
293 if (quotes)
294 s += "\"";
295 if (i < m_num_values - 1)
296 s += ",";
297 }
298 }
299
300 // public functions ----------------------------------------------
301
302 // Deep copy constructor
303 odb::odb(const odb &o) : odb() {
304 m_tid = o.m_tid;
305 m_name = o.m_name;
306 m_num_values = o.m_num_values;
307 m_hKey = o.m_hKey;
308 m_watch_callback = o.m_watch_callback;
310 for (int i = 0; i < m_num_values; i++) {
312 m_data[i].set_parent(this);
313 if (m_tid == TID_STRING || m_tid == TID_LINK) {
314 // set_string() creates a copy of our string
315 m_data[i].set_string(o.m_data[i]);
316 } else if (m_tid == TID_KEY) {
317 // recursive call to create a copy of the odb object
319 midas::odb *pc = new midas::odb(*po);
320 pc->set_parent(this);
321 m_data[i].set(pc);
322 } else {
323 // simply pass basic types
324 m_data[i] = o.m_data[i];
325 m_data[i].set_parent(this);
326 }
327 }
328 }
329
330 void odb::deep_copy(odb &d, const odb &s) {
331 d.m_tid = s.m_tid;
332 d.m_name = s.m_name;
333 d.m_num_values = s.m_num_values;
334 d.m_hKey = s.m_hKey;
335 d.m_watch_callback = s.m_watch_callback;
336 d.m_data = new midas::u_odb[d.m_num_values]{};
337 for (int i = 0; i < d.m_num_values; i++) {
338 d.m_data[i].set_tid(d.m_tid);
339 d.m_data[i].set_parent(&d);
340 if (d.m_tid == TID_STRING || d.m_tid == TID_LINK) {
341 // set_string() creates a copy of our string
342 d.m_data[i].set_string(s.m_data[i]);
343 } else if (d.m_tid == TID_KEY) {
344 // recursive call to create a copy of the odb object
346 midas::odb *pc = new midas::odb(*po);
347 pc->set_parent(&d);
348 d.m_data[i].set(pc);
349 } else {
350 // simply pass basic types
351 d.m_data[i] = s.m_data[i];
352 d.m_data[i].set_parent(this);
353 }
354 }
355 }
356
357 // return full path from ODB
358 std::string odb::get_full_path() {
359 if (m_name[0] == '/')
360 return m_name;
361 if (m_parent)
362 return m_parent->get_full_path() + "/" + m_name;
363
364 if (!is_connected_odb() || m_hKey == -1)
365 return m_name;
366
367 std::string str = db_get_path(s_hDB, m_hKey);
368 if (str == "/") // change "/" to ""
369 str = "";
370 return str;
371 }
372
373 // return parent object
374 std::string odb::get_parent_path() {
375 std::string s = get_full_path();
376 std::size_t i = s.find_last_of("/");
377 s = s.substr(0, i);
378 return s;
379 }
380
381 // return size of ODB key
382 int odb::size() {
383 return m_num_values;
384 }
385
386 // Resize an ODB key
387 void odb::resize(int size) {
389 if (this->is_auto_refresh_write()) {
390 int status = db_set_num_values(s_hDB, m_hKey, size);
391 if (status != DB_SUCCESS)
392 mthrow("db_set_num_values for ODB key \"" + get_full_path() +
393 "\" failed with status " + std::to_string(status));
394 }
395 }
396
397 // Resize an ODB key with default value
398 void odb::resize(int size, bool b) {
401 if (this->is_auto_refresh_write()) {
402 int status = db_set_num_values(s_hDB, m_hKey, size);
403 if (status != DB_SUCCESS)
404 mthrow("db_set_num_values for ODB key \"" + get_full_path() +
405 "\" failed with status " + std::to_string(status));
406 }
407 if (size > old_size) {
408 for (int i=old_size ; i<size ; i++)
409 m_data[i] = b;
410 if (this->is_auto_refresh_write())
411 write();
412 }
413 }
414
415 std::string odb::print() {
416 std::string s;
417 s = "{\n";
418 print(s, 1);
419 s += "\n}";
420 return s;
421 }
422
423 std::string odb::dump() {
424 std::string s;
425 s = "{\n";
426 dump(s, 1);
427 s += "\n}";
428 return s;
429 }
430
431 // print current object with all sub-objects nicely indented
432 void odb::print(std::string &s, int indent) {
433 for (int i = 0; i < indent; i++)
434 s += " ";
435 if (m_tid == TID_KEY) {
436 s += "\"" + m_name + "\": {\n";
437 for (int i = 0; i < m_num_values; i++) {
438 std::string v;
439 // recursive call
440 m_data[i].get_odb().print(v, indent + 1);
441 s += v;
442 if (i < m_num_values - 1)
443 s += ",\n";
444 else
445 s += "\n";
446 }
447 for (int i = 0; i < indent; i++)
448 s += " ";
449 s += "}";
450 } else {
451 s += "\"" + m_name + "\": ";
452 if (m_num_values > 1)
453 s += "[";
454 std::string v;
455 get(v, m_tid == TID_STRING || m_tid == TID_LINK);
456 if (m_tid == TID_LINK)
457 s += " -> ";
458 s += v;
459 if (m_num_values > 1)
460 s += "]";
461 }
462 }
463
464 // dump current object in the same way as odbedit saves as json
465 void odb::dump(std::string &s, int indent) {
466 for (int i = 0; i < indent; i++)
467 s += " ";
468 if (m_tid == TID_KEY) {
469 s += "\"" + m_name + "\": {\n";
470 for (int i = 0; i < m_num_values; i++) {
471 std::string v;
472 m_data[i].get_odb().dump(v, indent + 1);
473 s += v;
474 if (i < m_num_values - 1)
475 s += ",\n";
476 else
477 s += "\n";
478 }
479 for (int i = 0; i < indent; i++)
480 s += " ";
481 s += "}";
482 } else {
483 KEY key;
485 s += "\"" + m_name + "/key\": ";
486 s += "{ \"type\": " + std::to_string(m_tid) + ", ";
487 s += "\"access_mode\": " + std::to_string(key.access_mode) + ", ";
488 s += "\"last_written\": " + std::to_string(key.last_written) + "},\n";
489 for (int i = 0; i < indent; i++)
490 s += " ";
491 s += "\"" + m_name + "\": ";
492 if (m_num_values > 1)
493 s += "[";
494 std::string v;
495 get(v, m_tid == TID_STRING || m_tid == TID_LINK);
496 s += v;
497 if (m_num_values > 1)
498 s += "]";
499 }
500 }
501
502 // save ODB tree into file in JSON format
503 void odb::save(const std::string &filename) {
504 std::string buffer;
505
506 std::string header = "{\n";
507 header += " \"/MIDAS version\" : \"2.1\",\n";
508 header += " \"/filename\" : \"" + filename + "\",\n";
509 header += " \"/ODB path\" : \"" + get_full_path() + "\",\n\n";
510
511 odb::dump(buffer, 1);
512
513 buffer += "\n}\n";
514
515 std::ofstream f(filename);
516 if (!f.is_open())
517 mthrow("Cannot open file \"" + filename);
518
519 f << header << buffer;
520 f.close();
521 }
522
523
524 // check if key contains a certain subkey
525 bool odb::is_subkey(std::string str) {
526 if (m_tid != TID_KEY)
527 return false;
528
529 std::string first = str;
530 std::string tail{};
531 if (str.find('/') != std::string::npos) {
532 first = str.substr(0, str.find('/'));
533 tail = str.substr(str.find('/') + 1);
534 }
535
536 int i;
537 for (i = 0; i < m_num_values; i++)
538 if (m_data[i].get_odb().get_name() == first)
539 break;
540 if (i == m_num_values)
541 return false;
542
543 if (!tail.empty())
544 return m_data[i].get_odb().is_subkey(tail);
545
546 return true;
547 }
548
549 odb &odb::get_subkey(std::string str) {
550 if (m_tid == 0) {
551 if (is_auto_create()) {
552 m_tid = TID_KEY;
553 int status = db_create_key(s_hDB, 0, m_name.c_str(), m_tid);
555 mthrow("Cannot create ODB key \"" + m_name + "\", status" + std::to_string(status));
556 db_find_key(s_hDB, 0, m_name.c_str(), &m_hKey);
557 if (s_debug) {
558 if (m_name[0] == '/')
559 std::cout << "Created ODB key \"" + m_name + "\"" << std::endl;
560 else
561 std::cout << "Created ODB key \"" + get_full_path() + "\"" << std::endl;
562 }
563 // strip path from name
564 if (m_name.find_last_of('/') != std::string::npos)
565 m_name = m_name.substr(m_name.find_last_of('/') + 1);
566 } else
567 mthrow("Invalid key \"" + m_name + "\" does not have subkeys");
568
569 }
570 if (m_tid != TID_KEY)
571 mthrow("ODB key \"" + get_full_path() + "\" does not have subkeys");
572
573 std::string first = str;
574 std::string tail{};
575 if (str.find('/') != std::string::npos) {
576 first = str.substr(0, str.find('/'));
577 tail = str.substr(str.find('/') + 1);
578 }
579
580 int i;
581 for (i = 0; i < m_num_values; i++)
582 if (equal_ustring(first.c_str(), m_data[i].get_odb().get_name().c_str()))
583 break;
584 if (i == m_num_values) {
585 if (is_auto_create()) {
586 if (m_num_values == 0) {
587 m_num_values = 1;
588 m_data = new u_odb[1]{};
589 i = 0;
590 } else {
591 // resize array
593 i = m_num_values - 1;
594 }
595 midas::odb *o = new midas::odb();
597 m_data[i].set_parent(this);
598 o->set_name(get_full_path() + "/" + str);
599 o->set_tid(0); // tid is currently undefined
600 o->set_flags(get_flags());
601 o->set_parent(this);
602 m_data[i].set(o);
603 } else
604 mthrow("ODB key \"" + get_full_path() + "\" does not contain subkey \"" + first + "\"");
605 }
606 if (!tail.empty())
607 return m_data[i].get_odb().get_subkey(tail);
608
609 return *m_data[i].get_podb();
610 }
611
612 // get number of subkeys in ODB, return number and vector of names
613 int odb::get_subkeys(std::vector<std::string> &name) {
614 if (m_tid != TID_KEY)
615 return 0;
616 if (m_hKey == 0 || m_hKey == -1)
617 mthrow("get_sub-keys called with invalid m_hKey for ODB key \"" + m_name + "\"");
618
619 // count number of subkeys in ODB
620 std::vector<HNDLE> hlist;
621 int n = 0;
622 for (int i = 0;; i++) {
623 HNDLE h;
624 int status = db_enum_key(s_hDB, m_hKey, i, &h);
625 if (status != DB_SUCCESS)
626 break;
627 KEY key;
628 db_get_key(s_hDB, h, &key);
629 hlist.push_back(h);
630 name.push_back(key.name);
631 n = i + 1;
632 }
633
634 return n;
635 }
636
637 // obtain key definition from ODB and allocate local data array
638 bool odb::read_key(const std::string &path) {
639 init_hdb();
640
641 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
642 if (status != DB_SUCCESS)
643 return false;
644
645 KEY key;
647 if (status != DB_SUCCESS)
648 mthrow("db_get_key for ODB key \"" + path +
649 "\" failed with status " + std::to_string(status));
650
651 // check for correct type if given as parameter
652 if (m_tid > 0 && m_tid != (int) key.type)
653 mthrow("ODB key \"" + get_full_path() +
654 "\" has different type than specified");
655
656 if (s_debug)
657 std::cout << "Get definition for ODB key \"" + get_full_path() + "\"" << std::endl;
658
659 m_tid = key.type;
660 m_name = key.name;
661 if (m_tid == TID_KEY) {
662
663 // merge ODB keys with local keys
664 for (int i = 0; i < m_num_values; i++) {
665 std::string p(path);
666 if (p.back() != '/')
667 p += "/";
668 p += m_data[i].get_odb().get_name();
669 HNDLE h;
670 status = db_find_key(s_hDB, 0, p.c_str(), &h);
671 if (status != DB_SUCCESS) {
672 // if key does not exist in ODB write it
673 m_data[i].get_odb().write_key(p, true);
674 m_data[i].get_odb().write();
675 } else {
676 // check key type
677 KEY key;
678 status = db_get_key(s_hDB, h, &key);
679 if (status != DB_SUCCESS)
680 mthrow("db_get_key for ODB key \"" + get_full_path() +
681 "\" failed with status " + std::to_string(status));
682 if (m_data[i].get_odb().get_tid() != (int)key.type) {
683 // write key if different
684 m_data[i].get_odb().write_key(p, true);
685 m_data[i].get_odb().write();
686 }
687 if (m_data[i].get_odb().get_tid() == TID_KEY) {
688 // update subkey structure
689 m_data[i].get_odb().read_key(p);
690 }
691 }
692 }
693
694 // read back everything from ODB
695 std::vector<std::string> name;
697 delete[] m_data;
699 for (int i = 0; i < m_num_values; i++) {
700 std::string p(path);
701 if (p.back() != '/')
702 p += "/";
703 p += name[i];
704 midas::odb *o = new midas::odb(p.c_str());
705 o->set_parent(this);
707 m_data[i].set_parent(this);
708 m_data[i].set(o);
709 }
710 } else {
712 delete[] m_data;
714 for (int i = 0; i < m_num_values; i++) {
716 m_data[i].set_parent(this);
717 }
718 }
719
720 return true;
721 }
722
723 // create key in ODB if it does not exist, otherwise check key type
724 bool odb::write_key(std::string &path, bool force_write) {
725 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
726 if (status != DB_SUCCESS) {
727 if (m_tid == 0) // auto-create subdir
728 m_tid = TID_KEY;
729 if (m_tid > 0 && m_tid < TID_LAST) {
730 status = db_create_key(s_hDB, 0, path.c_str(), m_tid);
731 if (status != DB_SUCCESS)
732 mthrow("ODB key \"" + path + "\" cannot be created");
733 status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
734 if (status != DB_SUCCESS)
735 mthrow("ODB key \"" + path + "\" not found after creation");
736 if (s_debug) {
737 if (path[0] == '/')
738 std::cout << "Created ODB key \"" + path + "\"" << std::endl;
739 else
740 std::cout << "Created ODB key \"" + get_full_path() + "\"" << std::endl;
741 }
742 } else
743 mthrow("ODB key \"" + path + "\" cannot be found");
744 return true;
745 } else {
746 KEY key;
748 if (status != DB_SUCCESS)
749 mthrow("db_get_key for ODB key \"" + path +
750 "\" failed with status " + std::to_string(status));
751 if (m_tid == 0)
752 m_tid = key.type;
753
754 // check for correct type
755 if (m_tid > 0 && m_tid != (int) key.type) {
756 if (force_write) {
757 // delete and recreate key
758 status = db_delete_key(s_hDB, m_hKey, false);
759 if (status != DB_SUCCESS)
760 mthrow("db_delete_key for ODB key \"" + path +
761 "\" failed with status " + std::to_string(status));
762 status = db_create_key(s_hDB, 0, path.c_str(), m_tid);
763 if (status != DB_SUCCESS)
764 mthrow("ODB key \"" + path + "\" cannot be created");
765 status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
766 if (status != DB_SUCCESS)
767 mthrow("ODB key \"" + path + "\" not found after creation");
768 if (s_debug)
769 std::cout << "Re-created ODB key \"" + get_full_path() << "\" with different type" << std::endl;
770 } else
771 // abort
772 mthrow("ODB key \"" + get_full_path() +
773 "\" has differnt type than specified");
774 } else if (s_debug)
775 std::cout << "Validated ODB key \"" + get_full_path() + "\"" << std::endl;
776
777 return false;
778 }
779 }
780
781
782 // retrieve data from ODB and assign it to this object
783 void odb::read() {
784 if (!is_connected_odb())
785 return;
786
787 // check if deleted
788 if (is_deleted())
789 mthrow("ODB key \"" + m_name + "\" cannot be pulled because it has been deleted");
790
791 if (m_hKey == 0)
792 return; // needed to print un-connected objects
793
794 if (m_tid == 0)
795 mthrow("Read of invalid ODB key \"" + m_name + "\"");
796
797 if (m_hKey == -1) {
798 // connect un-connected object (crated via XML)
799 std::string path = get_full_path();
800
801 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
802 if (status != DB_SUCCESS)
803 mthrow("Cannot connect key \"" + path + "\" to ODB");
804 }
805
806 int status{};
807 if (m_tid == TID_STRING) {
808 KEY key;
810 char *str = (char *) malloc(key.total_size);
811 int size = key.total_size;
813 for (int i = 0; i < m_num_values; i++)
814 m_data[i].set(str + i * key.item_size);
815 free(str);
816 } else if (m_tid == TID_KEY) {
817 std::vector<std::string> name;
818 int n = get_subkeys(name);
819 if (n != m_num_values) {
820 // if subdirs have changed, rebuild it
821 delete[] m_data;
822 m_num_values = n;
824 for (int i = 0; i < m_num_values; i++) {
825 std::string k(get_full_path());
826 k += "/" + name[i];
827 midas::odb *o = new midas::odb(k.c_str());
828 o->set_parent(this);
830 m_data[i].set_parent(this);
831 m_data[i].set(o);
832 }
833 }
834 for (int i = 0; i < m_num_values; i++)
835 m_data[i].get_odb().read();
837 } else {
838 // resize local array if number of values has changed
839 KEY key;
841 if (key.num_values != m_num_values) {
842 delete[] m_data;
845 for (int i = 0; i < m_num_values; i++) {
847 m_data[i].set_parent(this);
848 }
849 }
850
852 void *buffer = malloc(size);
853 void *p = buffer;
855 for (int i = 0; i < m_num_values; i++) {
856 if (m_tid == TID_UINT8)
857 m_data[i].set(*static_cast<uint8_t *>(p));
858 else if (m_tid == TID_INT8)
859 m_data[i].set(*static_cast<int8_t *>(p));
860 else if (m_tid == TID_UINT16)
861 m_data[i].set(*static_cast<uint16_t *>(p));
862 else if (m_tid == TID_INT16)
863 m_data[i].set(*static_cast<int16_t *>(p));
864 else if (m_tid == TID_UINT32)
865 m_data[i].set(*static_cast<uint32_t *>(p));
866 else if (m_tid == TID_INT32)
867 m_data[i].set(*static_cast<int32_t *>(p));
868 else if (m_tid == TID_UINT64)
869 m_data[i].set(*static_cast<uint64_t *>(p));
870 else if (m_tid == TID_INT64)
871 m_data[i].set(*static_cast<int64_t *>(p));
872 else if (m_tid == TID_BOOL)
873 m_data[i].set(*static_cast<bool *>(p));
874 else if (m_tid == TID_FLOAT)
875 m_data[i].set(*static_cast<float *>(p));
876 else if (m_tid == TID_DOUBLE)
877 m_data[i].set(*static_cast<double *>(p));
878 else if (m_tid == TID_STRING)
879 m_data[i].set(std::string(static_cast<const char *>(p)));
880 else if (m_tid == TID_LINK)
881 m_data[i].set(std::string(static_cast<const char *>(p)));
882 else
883 mthrow("Invalid type ID " + std::to_string(m_tid));
884
885 p = static_cast<char *>(p) + rpc_tid_size(m_tid);
886 }
887 free(buffer);
888 }
889
890 if (status != DB_SUCCESS)
891 mthrow("db_get_data for ODB key \"" + get_full_path() +
892 "\" failed with status " + std::to_string(status));
893 if (s_debug) {
894 if (m_tid == TID_KEY) {
895 std::cout << "Get ODB key \"" + get_full_path() + "[0..." +
896 std::to_string(m_num_values - 1) + "]\"" << std::endl;
897 } else {
898 std::string s;
899 get(s, false, false);
900 if (m_num_values > 1) {
901 if (m_tid == TID_STRING || m_tid == TID_LINK)
902 std::cout << "Get ODB key \"" + get_full_path() + "[0..." +
903 std::to_string(m_num_values - 1) + "]\": [\"" + s + "\"]" << std::endl;
904 else
905 std::cout << "Get ODB key \"" + get_full_path() + "[0..." +
906 std::to_string(m_num_values - 1) + "]\": [" + s + "]" << std::endl;
907 } else {
908 if (m_tid == TID_STRING || m_tid == TID_LINK)
909 std::cout << "Get ODB key \"" + get_full_path() + "\": \"" + s + "\"" << std::endl;
910 else
911 std::cout << "Get ODB key \"" + get_full_path() + "\": " + s << std::endl;
912 }
913 }
914 }
915 }
916
917 // retrieve individual member of array
918 void odb::read(int index) {
919 if (!is_connected_odb())
920 return;
921
922 if (m_hKey == 0 || m_hKey == -1)
923 return; // needed to print un-connected objects
924
925 if (m_tid == 0)
926 mthrow("Pull of invalid ODB key \"" + m_name + "\"");
927
928 int status{};
929 if (m_tid == TID_STRING || m_tid == TID_LINK) {
930 KEY key;
932 char *str = (char *) malloc(key.item_size);
933 int size = key.item_size;
936 free(str);
937 } else if (m_tid == TID_KEY) {
940 } else {
941 int size = rpc_tid_size(m_tid);
942 void *buffer = malloc(size);
943 void *p = buffer;
945 if (m_tid == TID_UINT8)
946 m_data[index].set(*static_cast<uint8_t *>(p));
947 else if (m_tid == TID_INT8)
948 m_data[index].set(*static_cast<int8_t *>(p));
949 else if (m_tid == TID_UINT16)
950 m_data[index].set(*static_cast<uint16_t *>(p));
951 else if (m_tid == TID_INT16)
952 m_data[index].set(*static_cast<int16_t *>(p));
953 else if (m_tid == TID_UINT32)
954 m_data[index].set(*static_cast<uint32_t *>(p));
955 else if (m_tid == TID_INT32)
956 m_data[index].set(*static_cast<int32_t *>(p));
957 else if (m_tid == TID_UINT64)
958 m_data[index].set(*static_cast<uint64_t *>(p));
959 else if (m_tid == TID_INT64)
960 m_data[index].set(*static_cast<int64_t *>(p));
961 else if (m_tid == TID_BOOL)
962 m_data[index].set(*static_cast<bool *>(p));
963 else if (m_tid == TID_FLOAT)
964 m_data[index].set(*static_cast<float *>(p));
965 else if (m_tid == TID_DOUBLE)
966 m_data[index].set(*static_cast<double *>(p));
967 else if (m_tid == TID_STRING)
968 m_data[index].set(std::string(static_cast<const char *>(p)));
969 else if (m_tid == TID_LINK)
970 m_data[index].set(std::string(static_cast<const char *>(p)));
971 else
972 mthrow("Invalid type ID " + std::to_string(m_tid));
973
974 free(buffer);
975 }
976
977 if (status != DB_SUCCESS)
978 mthrow("db_get_data for ODB key \"" + get_full_path() +
979 "\" failed with status " + std::to_string(status));
980 if (s_debug) {
981 std::string s;
982 m_data[index].get(s);
983 if (m_tid == TID_STRING || m_tid == TID_LINK)
984 std::cout << "Get ODB key \"" + get_full_path() + "[" +
985 std::to_string(index) + "]\": [\"" + s + "\"]" << std::endl;
986 else
987 std::cout << "Get ODB key \"" + get_full_path() + "[" +
988 std::to_string(index) + "]\": [" + s + "]" << std::endl;
989 }
990 }
991
992 // push individual member of an array
993 void odb::write(int index, int str_size) {
994 if (!is_connected_odb())
995 return;
996
997 if (m_hKey == -1) {
998 // connect un-connected object (crated via XML)
999 std::string path = get_full_path();
1000
1001 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
1002 if (status != DB_SUCCESS)
1003 mthrow("Cannot connect key \"" + path + "\" to ODB");
1004
1005 } else if (m_hKey == 0) {
1006 if (is_auto_create()) {
1007 std::string to_create = m_name[0] == '/' ? m_name : get_full_path();
1008 int status = db_create_key(s_hDB, 0, to_create.c_str(), m_tid);
1010 mthrow("Cannot create ODB key \"" + to_create + "\", status =" + std::to_string(status));
1011 db_find_key(s_hDB, 0, to_create.c_str(), &m_hKey);
1012 if (s_debug) {
1013 std::cout << "Created ODB key \"" + to_create + "\"" << std::endl;
1014 }
1015 // strip path from name
1016 if (m_name.find_last_of('/') != std::string::npos)
1017 m_name = m_name.substr(m_name.find_last_of('/') + 1);
1018 } else
1019 mthrow("Write of un-connected ODB key \"" + m_name + "\" not possible");
1020 }
1021
1022 // don't write keys
1023 if (m_tid == TID_KEY)
1024 return;
1025
1026 int status{};
1027 if (m_tid == TID_STRING || m_tid == TID_LINK) {
1028 KEY key;
1030 std::string s;
1031 m_data[index].get(s);
1032 if (m_num_values == 1) {
1033 int size = key.item_size;
1034 if (key.item_size == 0 || !is_preserve_string_size())
1035 size = s.size() + 1;
1036 if (str_size > 0)
1037 size = str_size;
1038 char *ss = (char *)malloc(size+1);
1039 mstrlcpy(ss, s.c_str(), size);
1040 if (is_trigger_hotlink())
1042 else
1044 free(ss);
1045 } else {
1046 if (key.item_size == 0)
1047 key.item_size = s.size() + 1;
1048 if (str_size > 0) {
1049 if (key.item_size > 0 && key.item_size != str_size) {
1050 std::cout << "ODB string size mismatch for \"" << get_full_path() <<
1051 "\" (" << key.item_size << " vs " << str_size << "). ODB key recreated."
1052 << std::endl;
1053 if (is_trigger_hotlink())
1054 status = db_set_data(s_hDB, m_hKey, s.c_str(), str_size, 1, m_tid);
1055 else
1056 status = db_set_data1(s_hDB, m_hKey, s.c_str(), str_size, 1, m_tid);
1057 }
1059 }
1061 }
1062 if (s_debug) {
1063 if (m_num_values > 1)
1064 std::cout << "Set ODB key \"" + get_full_path() + "[" + std::to_string(index) + "]\" = \"" + s
1065 + "\"" << std::endl;
1066 else
1067 std::cout << "Set ODB key \"" + get_full_path() + "\" = \"" + s + "\""<< std::endl;
1068 }
1069 } else {
1070 u_odb u = m_data[index];
1071 if (m_tid == TID_BOOL) {
1072 u.set_parent(nullptr);
1073 BOOL b = static_cast<bool>(u); // "bool" is only 1 Byte, BOOL is 4 Bytes
1075 } else {
1077 }
1078 if (s_debug) {
1079 std::string s;
1080 u.get(s);
1081 if (m_num_values > 1)
1082 std::cout << "Set ODB key \"" + get_full_path() + "[" + std::to_string(index) + "]\" = " + s
1083 << std::endl;
1084 else
1085 std::cout << "Set ODB key \"" + get_full_path() + "\" = " + s << std::endl;
1086 }
1087 }
1088 if (status != DB_SUCCESS)
1089 mthrow("db_set_data_index for ODB key \"" + get_full_path() +
1090 "\" failed with status " + std::to_string(status));
1091 }
1092
1093 // write all members of an array to the ODB
1095
1096 // check if deleted
1097 if (is_deleted())
1098 mthrow("ODB key \"" + m_name + "\" cannot be written because it has been deleted");
1099
1100 // write subkeys
1101 if (m_tid == TID_KEY) {
1102 for (int i = 0; i < m_num_values; i++)
1103 m_data[i].get_odb().write();
1104 return;
1105 }
1106
1107 if (m_tid == 0 && m_data[0].get_tid() != 0)
1108 m_tid = m_data[0].get_tid();
1109
1111 mthrow("Invalid TID for ODB key \"" + get_full_path() + "\"");
1112
1113 if ((m_hKey == 0 || m_hKey == -1) && !is_auto_create())
1114 mthrow("Writing ODB key \"" + m_name +
1115 "\" is not possible because of invalid key handle");
1116
1117 // if index operator [] returned previously a certain index, write only this one
1118 if (m_last_index != -1) {
1120 m_last_index = -1;
1121 return;
1122 }
1123
1124 if (m_num_values == 1) {
1125 write(0, str_size);
1126 return;
1127 }
1128
1129 if (m_hKey == -1) {
1130 // connect un-connected object (crated via XML)
1131 std::string path = get_full_path();
1132
1133 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
1134 if (status != DB_SUCCESS)
1135 mthrow("Cannot connect key \"" + path + "\" to ODB");
1136
1137 } else if (m_hKey == 0) {
1138 if (is_auto_create()) {
1139 std::string to_create = m_name[0] == '/' ? m_name : get_full_path();
1140 int status = db_create_key(s_hDB, 0, to_create.c_str(), m_tid);
1142 mthrow("Cannot create ODB key \"" + to_create + "\", status" + std::to_string(status));
1143 db_find_key(s_hDB, 0, to_create.c_str(), &m_hKey);
1144 if (s_debug) {
1145 std::cout << "Created ODB key \"" + to_create + "\"" << std::endl;
1146 }
1147 // strip path from name
1148 if (m_name.find_last_of('/') != std::string::npos)
1149 m_name = m_name.substr(m_name.find_last_of('/') + 1);
1150 } else
1151 mthrow("Write of un-connected ODB key \"" + m_name + "\" not possible");
1152 }
1153
1154 int status{};
1155 if (m_tid == TID_STRING || m_tid == TID_LINK) {
1157 KEY key;
1159 if (key.item_size == 0 || key.total_size == 0) {
1160 int size = 1;
1161 for (int i = 0; i < m_num_values; i++) {
1162 std::string d;
1163 m_data[i].get(d);
1164 if ((int) d.size() + 1 > size)
1165 size = d.size() + 1;
1166 }
1167 // round up to multiples of 32
1168 size = (((size - 1) / 32) + 1) * 32;
1169 key.item_size = size;
1171 }
1172 char *str = (char *) calloc(m_num_values, key.item_size);
1173 for (int i = 0; i < m_num_values; i++) {
1174 std::string d;
1175 m_data[i].get(d);
1176 strncpy(str + i * key.item_size, d.c_str(), key.item_size);
1177 }
1178 if (is_trigger_hotlink())
1180 else
1182 free(str);
1183 if (s_debug) {
1184 std::string s;
1185 get(s, true, false);
1186 std::cout << "Set ODB key \"" + get_full_path() +
1187 "[0..." + std::to_string(m_num_values - 1) + "]\" = [" + s + "]" << std::endl;
1188 }
1189 } else {
1190 std::string s;
1191 m_data[0].get(s);
1192 if (is_trigger_hotlink())
1193 status = db_set_data(s_hDB, m_hKey, s.c_str(), s.length() + 1, 1, m_tid);
1194 else
1195 status = db_set_data1(s_hDB, m_hKey, s.c_str(), s.length() + 1, 1, m_tid);
1196 if (s_debug)
1197 std::cout << "Set ODB key \"" + get_full_path() + "\" = " + s << std::endl;
1198 }
1199 } else {
1201 uint8_t *buffer = (uint8_t *) malloc(size);
1202 uint8_t *p = buffer;
1203 for (int i = 0; i < m_num_values; i++) {
1204 if (m_tid == TID_BOOL) {
1205 // bool has 1 Byte, BOOL has 4 Bytes
1206 BOOL b = static_cast<bool>(m_data[i]);
1207 memcpy(p, &b, rpc_tid_size(m_tid));
1208 } else {
1209 memcpy(p, (void*)&m_data[i], rpc_tid_size(m_tid));
1210 }
1211 p += rpc_tid_size(m_tid);
1212 }
1213 if (is_trigger_hotlink())
1215 else
1217 free(buffer);
1218 if (s_debug) {
1219 std::string s;
1220 get(s, false, false);
1221 if (m_num_values > 1)
1222 std::cout << "Set ODB key \"" + get_full_path() + "[0..." + std::to_string(m_num_values - 1) +
1223 "]\" = [" + s + "]" << std::endl;
1224 else
1225 std::cout << "Set ODB key \"" + get_full_path() + "\" = " + s << std::endl;
1226 }
1227 }
1228
1229 if (status != DB_SUCCESS)
1230 mthrow("db_set_data for ODB key \"" + get_full_path() +
1231 "\" failed with status " + std::to_string(status));
1232 }
1233
1235 // Delete any subkeys that are not in the list of defaults.
1236 KEY key;
1237 db_get_key(hDB, hKey, &key);
1238
1239 if (key.type == TID_KEY) {
1240 std::vector<std::string> to_delete;
1241
1242 for (int i = 0;; i++) {
1243 HNDLE hSubKey;
1244 int status = db_enum_key(hDB, hKey, i, &hSubKey);
1245 if (status != DB_SUCCESS)
1246 break;
1247
1248 KEY subKey;
1250 std::string full_path = path + "/" + subKey.name;
1251
1252 if (!default_odb.is_subkey(subKey.name)) {
1253 to_delete.push_back(subKey.name);
1254
1255 if (default_odb.get_debug()) {
1256 std::cout << "Deleting " << full_path << " as not in list of defaults" << std::endl;
1257 }
1258 } else if (key.type == TID_KEY) {
1260 }
1261 }
1262
1263 for (auto name : to_delete) {
1264 HNDLE hSubKey;
1265 db_find_key(hDB, hKey, name.c_str(), &hSubKey);
1267 }
1268 }
1269 }
1270
1271 void recurse_get_defaults_order(std::string path, midas::odb& default_odb, std::map<std::string, std::vector<std::string> >& retval) {
1272 for (midas::odb& sub : default_odb) {
1273 if (sub.get_tid() == TID_KEY) {
1274 recurse_get_defaults_order(path + "/" + sub.get_name(), sub, retval);
1275 }
1276
1277 retval[path].push_back(sub.get_name());
1278 }
1279 }
1280
1281 void recurse_fix_order(midas::odb& default_odb, std::map<std::string, std::vector<std::string> >& user_order) {
1282 std::string path = default_odb.get_full_path();
1283
1284 if (user_order.find(path) != user_order.end()) {
1285 default_odb.fix_order(user_order[path]);
1286 }
1287
1288 for (midas::odb& it : default_odb) {
1289 if (it.get_tid() == TID_KEY) {
1291 }
1292 }
1293 }
1294
1295 void odb::fix_order(std::vector<std::string> target_order) {
1296 // Fix the order of ODB keys to match that specified in target_order.
1297 // The in-ODB representation is simple, as we can just use db_reorder_key()
1298 // on anything that's in the wrong place.
1299 // The in-memory representation is a little trickier, but we just copy raw
1300 // memory into a temporary array, so we don't have to delete/recreate the
1301 // u_odb objects.
1302 std::vector<std::string> curr_order;
1303
1304 if (get_subkeys(curr_order) <= 0) {
1305 // Not a TID_KEY (or no keys)
1306 return;
1307 }
1308
1309 if (target_order.size() != curr_order.size() || (int)target_order.size() != m_num_values) {
1310 return;
1311 }
1312
1313 HNDLE hKey = get_hkey();
1314 bool force_order = false;
1315
1316 // Temporary location where we'll store in-memory u_odb objects in th
1317 // correct order.
1319
1320 for (int i = 0; i < m_num_values; i++) {
1321 if (force_order || curr_order[i] != target_order[i]) {
1322 force_order = true;
1323 HNDLE hSubKey;
1324
1325 // Fix the order in the ODB
1328 }
1329
1330 // Fix the order in memory
1331 auto curr_it = std::find(curr_order.begin(), curr_order.end(), target_order[i]);
1332
1333 if (curr_it == curr_order.end()) {
1334 // Logic error - bail to avoid doing any damage to the in-memory version.
1335 delete[] new_m_data;
1336 return;
1337 }
1338
1339 int curr_idx = curr_it - curr_order.begin();
1341 }
1342
1343 // Final update of the in-memory version so they are in the correct order
1344 for (int i = 0; i < m_num_values; i++) {
1345 m_data[i] = new_m_data[i];
1346
1347 // Nullify pointers that point to the same object in
1348 // m_data and new_m_data, so the underlying object doesn't
1349 // get destroyed when we delete new_m_data.
1350 new_m_data[i].set_string_ptr(nullptr);
1351 new_m_data[i].set_odb(nullptr);
1352 }
1353
1354 delete[] new_m_data;
1355 }
1356
1357 // connect function with separated path and key name
1358 void odb::connect(const std::string &p, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults) {
1359 init_hdb();
1360
1361 if (!name.empty())
1362 m_name = name;
1363 std::string path(p);
1364
1365 if (path.empty())
1366 mthrow("odb::connect() cannot be called with an empty ODB path");
1367
1368 if (path[0] != '/')
1369 mthrow("odb::connect(\"" + path + "\"): path must start with leading \"/\"");
1370
1371 if (path.back() != '/')
1372 path += "/";
1373
1374 path += m_name;
1375
1376 HNDLE hKey;
1377 int status = db_find_key(s_hDB, 0, path.c_str(), &hKey);
1378 bool key_exists = (status == DB_SUCCESS);
1379 bool created = false;
1380
1382 // Recurse down to delete keys as needed.
1383 // We need to do this recursively BEFORE calling read/read_key for the first time
1384 // to ensure that subdirectories get handled correctly.
1386 }
1387
1388 if (!key_exists || write_defaults) {
1390 } else {
1391 read_key(path);
1392 }
1393
1394 // correct wrong parent ODB from initializer_list
1395 for (int i = 0; i < m_num_values; i++)
1396 m_data[i].set_parent(this);
1397
1398 if (m_tid == TID_KEY) {
1399 for (int i = 0; i < m_num_values; i++)
1400 m_data[i].get_odb().connect(get_full_path(), m_data[i].get_odb().get_name(), write_defaults);
1401 } else if (created || write_defaults) {
1402 write();
1403 } else {
1404 read();
1405 }
1406 }
1407
1408 // send key definitions and data with optional subkeys to certain path in ODB
1410
1411 if (str.empty())
1412 mthrow("odb::connect() cannot be called with an empty ODB path");
1413
1414 if (str[0] != '/')
1415 mthrow("odb::connect(\"" + str + "\"): path must start with leading \"/\"");
1416
1417 if (str == "/")
1418 mthrow("odb::connect(\"" + str + "\"): root ODB tree is not allowed");
1419
1420 if (str.back() == '/')
1421 str = str.substr(0, str.size()-1);
1422
1423 // separate ODB path and key nam
1424 std::string name;
1425 std::string path;
1426 name = str.substr(str.find_last_of('/') + 1);
1427 path = str.substr(0, str.find_last_of('/') + 1);
1428
1430 }
1431
1432 // shorthand for the same behavior as db_check_record:
1433 // - keep values of keys that already exist with the correct type
1434 // - add keys that user provided but aren't in ODB already
1435 // - delete keys that are in ODB but not in user's settings
1436 // - re-order ODB keys to match user's order
1437 void odb::connect_and_fix_structure(std::string path) {
1438 // Store the order the user specified.
1439 // Need to do this recursively before calling connect(), as the first
1440 // read() in that function merges user keys and existing keys.
1441 std::map<std::string, std::vector<std::string> > user_order;
1443
1444 // Main connect() that adds/deletes/updates keys as needed.
1445 connect(path, false, true);
1446
1447 // Fix order in ODB (and memory)
1449 }
1450
1452 init_hdb();
1453
1455
1456 if (this->is_write_protect())
1457 mthrow("Cannot modify write protected key \"" + m_name + "\"");
1458
1459
1460 // delete key in ODB
1462 if (status != DB_SUCCESS && status != DB_INVALID_HANDLE)
1463 mthrow("db_delete_key for ODB key \"" + m_name +
1464 "\" returnd error code " + std::to_string(status));
1465
1466 if (s_debug)
1467 std::cout << "Deleted ODB key \"" + m_name + "\"" << std::endl;
1468
1469 // invalidate this object
1470 delete[] m_data;
1471 m_data = nullptr;
1472 m_num_values = 0;
1473 m_tid = 0;
1474 m_hKey = 0;
1475
1476 // set flag that this object has been deleted
1477 set_deleted(true);
1478 }
1479
1481 // set mode of ODB key
1482 // default is MODE_READ | MODE_WRITE | MODE_DELETE
1483
1484 init_hdb();
1485
1486 // set mode in ODB
1488
1490 mthrow("db_set_mode for ODB key \"" + get_full_path() +
1491 "\" returnd error code " + std::to_string(status));
1492
1493 if (s_debug)
1494 std::cout << "Set mode of ODB key \"" + get_full_path() + "\" to " << mode << std::endl;
1495 }
1496
1498 init_hdb();
1499
1500 // set mode in ODB
1501 KEY key;
1502 int status = db_get_key(s_hDB, m_hKey, &key);
1503
1505 mthrow("db_get_key for ODB key \"" + get_full_path() +
1506 "\" returnd error code " + std::to_string(status));
1507
1508 return key.access_mode;
1509 }
1510
1511 unsigned int odb::get_last_written() {
1512 init_hdb();
1513
1514 // set mode in ODB
1515 KEY key;
1516 int status = db_get_key(s_hDB, m_hKey, &key);
1517
1519 mthrow("db_get_key for ODB key \"" + get_full_path() +
1520 "\" returnd error code " + std::to_string(status));
1521
1522 return (unsigned int) (key.last_written);
1523 }
1524
1525 void odb::watch(std::function<void(midas::odb &)> f) {
1526 if (m_hKey == 0 || m_hKey == -1)
1527 mthrow("watch() called for ODB key \"" + m_name +
1528 "\" which is not connected to ODB");
1529
1530 // create a deep copy of current object in case it
1531 // goes out of scope
1532 midas::odb* ow = new midas::odb(*this);
1533
1534 ow->m_watch_callback = f;
1536
1537 // put object into watchlist
1538 g_watchlist.push_back(ow);
1539 }
1540
1542 {
1543 for (int i=0 ; i<(int) g_watchlist.size() ; i++) {
1544 if (g_watchlist[i]->get_hkey() == this->get_hkey()) {
1545 db_unwatch(s_hDB, g_watchlist[i]->get_hkey());
1546 delete g_watchlist[i];
1547 g_watchlist.erase(g_watchlist.begin() + i);
1548 i--;
1549 }
1550 }
1551 }
1552
1554 {
1555 for (int i=0 ; i<(int) g_watchlist.size() ; i++) {
1557 delete g_watchlist[i];
1558 }
1559 g_watchlist.clear();
1560 }
1561
1562 void odb::set(std::string s)
1563 {
1564 if (this->is_write_protect())
1565 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1566
1567 if (m_tid == TID_BOOL)
1568 s = (s == "y" || s == "1") ? "1" : "0";
1569
1570 m_num_values = 1;
1571 m_data = new u_odb[1];
1572 m_data[0].set_parent(this);
1573 m_data[0].set_tid(m_tid);
1574 m_data[0].set(s);
1575 }
1576
1577 void odb::set(std::string s, int i)
1578 {
1579 if (this->is_write_protect())
1580 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1581
1582 if (m_tid == TID_BOOL)
1583 s = (s == "y" || s == "1") ? "1" : "0";
1584
1585 if (m_data == nullptr)
1586 m_data = new u_odb[m_num_values];
1587 m_data[i].set_parent(this);
1589 m_data[i].set(s);
1590 }
1591
1592 void odb::set_string_size(std::string s, int size)
1593 {
1594 if (this->is_write_protect())
1595 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1596
1597 m_num_values = 1;
1598 m_tid = TID_STRING;
1599 m_data = new u_odb[1];
1600 m_data[0].set_parent(this);
1601 m_data[0].set_tid(m_tid);
1604 }
1605
1606 void odb::set_odb(odb *o, int i)
1607 {
1608 if (this->is_write_protect())
1609 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1610
1611 if (m_data == nullptr)
1612 m_data = new u_odb[m_num_values];
1613 m_data[i].set_parent(this);
1615 m_data[i].set_odb(o);
1616 }
1617
1618 //-----------------------------------------------
1619
1620 //---- u_odb implementations calling functions from odb
1621
1623 if (m_tid == TID_STRING || m_tid == TID_LINK)
1624 delete m_string;
1625 else if (m_tid == TID_KEY)
1626 delete m_odb;
1627 }
1628
1629 // get function for strings
1630 void u_odb::get(std::string &s) {
1631 if (m_tid == TID_UINT8)
1632 s = std::to_string(m_uint8);
1633 else if (m_tid == TID_INT8)
1634 s = std::to_string(m_int8);
1635 else if (m_tid == TID_UINT16)
1636 s = std::to_string(m_uint16);
1637 else if (m_tid == TID_INT16)
1638 s = std::to_string(m_int16);
1639 else if (m_tid == TID_UINT32)
1640 s = std::to_string(m_uint32);
1641 else if (m_tid == TID_INT32)
1642 s = std::to_string(m_int32);
1643 else if (m_tid == TID_UINT64)
1644 s = std::to_string(m_uint64);
1645 else if (m_tid == TID_INT64)
1646 s = std::to_string(m_int64);
1647 else if (m_tid == TID_BOOL)
1648 s = std::string(m_bool ? "true" : "false");
1649 else if (m_tid == TID_FLOAT)
1650 s = std::to_string(m_float);
1651 else if (m_tid == TID_DOUBLE)
1652 s = std::to_string(m_double);
1653 else if (m_tid == TID_STRING)
1654 s = *m_string;
1655 else if (m_tid == TID_LINK)
1656 s = *m_string;
1657 else if (m_tid == TID_KEY)
1658 m_odb->print(s, 0);
1659 else if (m_tid == 0)
1660 mthrow("Subkey \"" + m_parent_odb->get_name() + "\" not found");
1661 else
1662 mthrow("Invalid type ID " + std::to_string(m_tid));
1663 }
1664
1665 //---- u_odb assignment and arithmetic operators overloads which call odb::write()
1666
1667 // overload assignment operators
1669 if (m_tid == 0)
1670 m_tid = TID_UINT8;
1671 set(v);
1674 return v;
1675 }
1677 if (m_tid == 0)
1678 m_tid = TID_INT8;
1679 set(v);
1682 return v;
1683 }
1685 if (m_tid == 0)
1686 m_tid = TID_UINT16;
1687 set(v);
1690 return v;
1691 }
1693 if (m_tid == 0)
1694 m_tid = TID_INT16;
1695 set(v);
1698 return v;
1699 }
1701 if (m_tid == 0)
1702 m_tid = TID_UINT32;
1703 set(v);
1706 return v;
1707 }
1709 if (m_tid == 0)
1710 m_tid = TID_INT32;
1711 set(v);
1714 return v;
1715 }
1717 if (m_tid == 0)
1718 m_tid = TID_UINT64;
1719 set(v);
1722 return v;
1723 }
1725 if (m_tid == 0)
1726 m_tid = TID_INT64;
1727 set(v);
1730 return v;
1731 }
1732 bool u_odb::operator=(bool v) {
1733 if (m_tid == 0)
1734 m_tid = TID_BOOL;
1735 set(v);
1738 return v;
1739 }
1740 float u_odb::operator=(float v) {
1741 if (m_tid == 0)
1742 m_tid = TID_FLOAT;
1743 set(v);
1746 return v;
1747 }
1748 double u_odb::operator=(double v) {
1749 if (m_tid == 0)
1750 m_tid = TID_DOUBLE;
1751 set(v);
1754 return v;
1755 }
1756 const char * u_odb::operator=(const char * v) {
1757 if (m_tid == 0)
1758 m_tid = TID_STRING;
1759 set(v);
1762 return v;
1763 }
1764
1765 std::string * u_odb::operator=(std::string * v){
1766 if (m_tid == 0)
1767 m_tid = TID_STRING;
1768 set(*v);
1771 return v;
1772 }
1773
1774 std::string u_odb::operator=(std::string v){
1775 if (m_tid == 0)
1776 m_tid = TID_STRING;
1777 set(v);
1780 return v;
1781 }
1782
1783 void u_odb::set_string_size(std::string v, int size) {
1784 m_tid = TID_STRING;
1785 set(v);
1787 m_parent_odb->write(size);
1788 }
1789
1790 // overload all standard conversion operators
1791 u_odb::operator uint8_t() {
1792 if (m_parent_odb)
1793 m_parent_odb->set_last_index(-1);
1794 return get<uint8_t>();
1795 }
1796 u_odb::operator int8_t() {
1797 if (m_parent_odb)
1798 m_parent_odb->set_last_index(-1);
1799 return get<int8_t>();
1800 }
1801 u_odb::operator uint16_t() {
1802 if (m_parent_odb)
1803 m_parent_odb->set_last_index(-1);
1804 return get<uint16_t>();
1805 }
1806 u_odb::operator int16_t() {
1807 if (m_parent_odb)
1808 m_parent_odb->set_last_index(-1);
1809 return get<int16_t>();
1810 }
1811 u_odb::operator uint32_t() {
1812 if (m_parent_odb)
1813 m_parent_odb->set_last_index(-1);
1814 return get<uint32_t>();
1815 }
1816 u_odb::operator int32_t() {
1817 if (m_parent_odb)
1818 m_parent_odb->set_last_index(-1);
1819 return get<int32_t>();
1820 }
1821 u_odb::operator uint64_t() {
1822 if (m_parent_odb)
1823 m_parent_odb->set_last_index(-1);
1824 return get<uint64_t>();
1825 }
1826 u_odb::operator int64_t() {
1827 if (m_parent_odb)
1828 m_parent_odb->set_last_index(-1);
1829 return get<int64_t>();
1830 }
1831 u_odb::operator bool() {
1832 if (m_parent_odb)
1833 m_parent_odb->set_last_index(-1);
1834 return get<bool>();
1835 }
1836 u_odb::operator float() {
1837 if (m_parent_odb)
1838 m_parent_odb->set_last_index(-1);
1839 return get<float>();
1840 }
1841 u_odb::operator double() {
1842 if (m_parent_odb)
1843 m_parent_odb->set_last_index(-1);
1844 return get<double>();
1845 }
1846 u_odb::operator std::string() {
1847 if (m_parent_odb)
1848 m_parent_odb->set_last_index(-1);
1849 std::string s;
1850 get(s);
1851 return s;
1852 }
1853 u_odb::operator const char *() {
1854 if (m_parent_odb)
1855 m_parent_odb->set_last_index(-1);
1856 if (m_tid != TID_STRING && m_tid != TID_LINK)
1857 mthrow("Only ODB string keys can be converted to \"const char *\"");
1858 return m_string->c_str();
1859 }
1860 u_odb::operator midas::odb&() {
1861 if (m_parent_odb)
1862 m_parent_odb->set_last_index(-1);
1863 if (m_tid != TID_KEY)
1864 mthrow("Only ODB directories can be converted to \"midas::odb &\"");
1865 return *m_odb;
1866 }
1867
1868
1869 void u_odb::add(double inc, bool write) {
1870 if (m_tid == TID_UINT8)
1871 m_uint8 += inc;
1872 else if (m_tid == TID_INT8)
1873 m_int8 += inc;
1874 else if (m_tid == TID_UINT16)
1875 m_uint16 += inc;
1876 else if (m_tid == TID_INT16)
1877 m_int16 += inc;
1878 else if (m_tid == TID_UINT32)
1879 m_uint32 += inc;
1880 else if (m_tid == TID_INT32)
1881 m_int32 += inc;
1882 else if (m_tid == TID_FLOAT)
1883 m_float += static_cast<float>(inc);
1884 else if (m_tid == TID_DOUBLE)
1885 m_double += inc;
1886 else
1887 mthrow("Invalid arithmetic operation for ODB key \"" +
1888 m_parent_odb->get_full_path() + "\"");
1891 }
1892
1893 void u_odb::mult(double f, bool write) {
1894 int tid = m_parent_odb->get_tid();
1895 if (tid == TID_UINT8)
1896 m_uint8 *= f;
1897 else if (tid == TID_INT8)
1898 m_int8 *= f;
1899 else if (tid == TID_UINT16)
1900 m_uint16 *= f;
1901 else if (tid == TID_INT16)
1902 m_int16 *= f;
1903 else if (tid == TID_UINT32)
1904 m_uint32 *= f;
1905 else if (tid == TID_INT32)
1906 m_int32 *= f;
1907 else if (tid == TID_FLOAT)
1908 m_float *= f;
1909 else if (tid == TID_DOUBLE)
1910 m_double *= f;
1911 else
1912 mthrow("Invalid operation for ODB key \"" +
1913 m_parent_odb->get_full_path() + "\"");
1916 }
1917
1918}; // namespace midas
#define FALSE
Definition cfortran.h:309
void set_string_size(std::string s, int size)
Definition odbxx.cxx:1592
std::string get_parent_path()
Definition odbxx.cxx:374
std::string get_full_path()
Definition odbxx.cxx:358
void set(std::string str)
Definition odbxx.cxx:1562
int m_num_values
Definition odbxx.h:467
static bool exists(const std::string &name)
Definition odbxx.cxx:75
std::string get_name()
Definition odbxx.h:1422
void write(int str_size=0)
Definition odbxx.cxx:1094
int m_tid
Definition odbxx.h:461
void set_mode(int mode)
Definition odbxx.cxx:1480
void set_auto_refresh_read(bool f)
Definition odbxx.h:1328
void set_auto_enlarge_array(bool f)
Definition odbxx.h:1349
void delete_key()
Definition odbxx.cxx:1451
void set_odb(odb *o, int i)
Definition odbxx.cxx:1606
u_odb * m_data
Definition odbxx.h:463
void deep_copy(odb &d, const odb &s)
Definition odbxx.cxx:330
bool is_deleted() const
Definition odbxx.h:528
bool is_auto_refresh_read() const
Definition odbxx.h:1327
static void unwatch_all()
Definition odbxx.cxx:1553
static HNDLE s_hDB
Definition odbxx.h:450
HNDLE get_hkey()
Definition odbxx.h:1417
std::function< void(midas::odb &)> m_watch_callback
Definition odbxx.h:473
bool is_auto_create() const
Definition odbxx.h:1342
bool is_preserve_string_size() const
Definition odbxx.h:1321
static void watch_callback(int hDB, int hKey, int index, void *info)
Definition odbxx.cxx:123
void unwatch()
Definition odbxx.cxx:1541
T get()
Definition odbxx.h:492
int get_tid()
Definition odbxx.h:1420
bool is_auto_refresh_write() const
Definition odbxx.h:1333
midas::odb * odb_from_json(const MJsonNode *node, std::string name, odb *o)
Definition odbxx.h:1238
bool read_key(const std::string &path)
Definition odbxx.cxx:638
static std::string s_odb_source_str
Definition odbxx.h:448
void resize(int size)
Definition odbxx.cxx:387
void set_preserve_string_size(bool f)
Definition odbxx.h:1322
void set_trigger_hotlink(bool f)
Definition odbxx.h:1361
int size()
Definition odbxx.cxx:382
void set_auto_refresh_write(bool f)
Definition odbxx.h:1334
int get_mode()
Definition odbxx.cxx:1497
void odb_from_xml_remote(const std::string &str)
Definition odbxx.cxx:159
void set_auto_create(bool f)
Definition odbxx.h:1343
void odb_from_xml_string(const std::string &str, const std::string &subkey)
Definition odbxx.cxx:198
void read()
Definition odbxx.cxx:783
void resize_mdata(int size)
Definition odbxx.cxx:257
odb & get_subkey(std::string str)
Definition odbxx.cxx:549
void odb_from_json_string(const std::string &str, const std::string &subkey)
Definition odbxx.cxx:241
void set_flags_recursively(uint32_t f)
Definition odbxx.cxx:151
unsigned int get_last_written()
Definition odbxx.cxx:1511
int get_subkeys(std::vector< std::string > &name)
Definition odbxx.cxx:613
void watch(std::function< void(midas::odb &)> f)
Definition odbxx.cxx:1525
std::string s()
Definition odbxx.h:1425
void save(const std::string &filename)
Definition odbxx.cxx:503
void set_last_index(int i)
Definition odbxx.h:999
static int create(const char *name, int type=TID_KEY)
Definition odbxx.cxx:139
bool is_subkey(std::string str)
Definition odbxx.cxx:525
static bool s_debug
Definition odbxx.h:452
void fix_order(std::vector< std::string > target_subkey_order)
Definition odbxx.cxx:1295
static odb_source s_odb_source
Definition odbxx.h:447
std::string dump()
Definition odbxx.cxx:423
int m_last_index
Definition odbxx.h:469
void connect_and_fix_structure(std::string path)
Definition odbxx.cxx:1437
static bool s_connected_odb
Definition odbxx.h:454
static void init_hdb()
Definition odbxx.cxx:49
uint32_t get_flags()
Definition odbxx.h:526
bool is_trigger_hotlink() const
Definition odbxx.h:1360
bool write_key(std::string &path, bool write_defaults)
Definition odbxx.cxx:724
std::string print()
Definition odbxx.cxx:415
static midas::odb * search_hkey(midas::odb *po, int hKey)
Definition odbxx.cxx:61
static bool is_connected_odb()
Definition odbxx.h:1394
std::bitset< 9 > m_flags
Definition odbxx.h:459
void set_deleted(bool f)
Definition odbxx.h:529
static void load(const std::string &filename, const std::string &odb_path)
Definition odbxx.cxx:101
midas::odb * odb_from_xml(PMXML_NODE node, odb *o)
Definition odbxx.h:1185
void set_parent(midas::odb *p)
Definition odbxx.h:536
HNDLE m_hKey
Definition odbxx.h:471
void set_write_protect(bool f)
Definition odbxx.h:1355
std::string m_name
Definition odbxx.h:465
bool is_write_protect() const
Definition odbxx.h:1354
void connect(const std::string &path, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults=false)
Definition odbxx.cxx:1358
midas::odb * m_parent
Definition odbxx.h:475
uint8_t m_uint8
Definition odbxx.h:52
bool m_bool
Definition odbxx.h:60
uint8_t operator=(uint8_t v)
Definition odbxx.cxx:1668
void set_tid(int tid)
Definition odbxx.h:105
void mult(double f, bool push=true)
Definition odbxx.cxx:1893
void set_string(std::string s)
Definition odbxx.h:172
int8_t m_int8
Definition odbxx.h:53
uint64_t m_uint64
Definition odbxx.h:58
int32_t m_int32
Definition odbxx.h:57
int64_t m_int64
Definition odbxx.h:59
void set(T v)
Definition odbxx.h:142
double m_double
Definition odbxx.h:62
odb * m_parent_odb
Definition odbxx.h:68
void set_odb(odb *v)
Definition odbxx.h:189
int m_tid
Definition odbxx.h:67
void add(double inc, bool push=true)
Definition odbxx.cxx:1869
void set_parent(odb *o)
Definition odbxx.h:102
uint16_t m_uint16
Definition odbxx.h:54
odb * get_podb()
Definition odbxx.h:369
void set_string_size(std::string s, int size)
Definition odbxx.cxx:1783
int16_t m_int16
Definition odbxx.h:55
odb & get_odb()
Definition odbxx.h:375
std::string s()
Definition odbxx.h:361
std::string * m_string
Definition odbxx.h:63
void set_string_ptr(std::string *s)
Definition odbxx.h:179
odb * m_odb
Definition odbxx.h:64
float m_float
Definition odbxx.h:61
uint32_t m_uint32
Definition odbxx.h:56
int get_tid()
Definition odbxx.h:107
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
#define DB_KEY_EXIST
Definition midas.h:641
#define DB_INVALID_HANDLE
Definition midas.h:635
#define DB_SUCCESS
Definition midas.h:631
#define DB_NO_KEY
Definition midas.h:642
#define DB_CREATED
Definition midas.h:632
#define DB_TRUNCATED
Definition midas.h:644
#define TID_DOUBLE
Definition midas.h:343
#define TID_KEY
Definition midas.h:349
#define TID_BOOL
Definition midas.h:340
#define TID_UINT64
Definition midas.h:352
#define TID_INT64
Definition midas.h:351
#define TID_INT32
Definition midas.h:339
#define TID_UINT8
Definition midas.h:328
#define TID_LINK
Definition midas.h:350
#define TID_STRING
Definition midas.h:346
#define TID_INT8
Definition midas.h:330
#define TID_UINT32
Definition midas.h:337
#define TID_UINT16
Definition midas.h:333
#define TID_INT16
Definition midas.h:335
#define TID_FLOAT
Definition midas.h:341
#define TID_LAST
Definition midas.h:354
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3201
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6893
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3856
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
Definition odb.cxx:6361
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4990
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6539
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9037
INT db_unwatch(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13887
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8027
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6019
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
Definition odb.cxx:8126
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13813
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7215
INT db_set_data1(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7313
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
Definition odb.cxx:7828
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7502
INT rpc_tid_size(INT id)
Definition midas.cxx:11757
void ** info
Definition fesimdaq.cxx:41
HNDLE hKey
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
INT type
Definition mana.cxx:269
HNDLE hDB
main ODB handle
Definition mana.cxx:207
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
#define mthrow(arg)
Definition mexcept.h:24
INT HNDLE
Definition midas.h:132
DWORD BOOL
Definition midas.h:105
#define TRUE
Definition midas.h:182
#define write(n, a, f, d)
#define name(x)
Definition midas_macro.h:24
#define set(var, value)
static std::string indent(int x, const char *p=" ")
void recurse_fix_order(midas::odb &default_odb, std::map< std::string, std::vector< std::string > > &user_order)
Definition odbxx.cxx:1281
void recurse_get_defaults_order(std::string path, midas::odb &default_odb, std::map< std::string, std::vector< std::string > > &retval)
Definition odbxx.cxx:1271
std::vector< midas::odb * > g_watchlist
Definition odbxx.cxx:40
void recurse_del_keys_not_in_defaults(std::string path, HNDLE hDB, HNDLE hKey, midas::odb &default_odb)
Definition odbxx.cxx:1234
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
DWORD status
Definition odbhist.cxx:39
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
Definition midas.h:1026
INT num_values
Definition midas.h:1028
DWORD type
Definition midas.h:1027
INT total_size
Definition midas.h:1031
WORD access_mode
Definition midas.h:1033
INT last_written
Definition midas.h:1037
char name[NAME_LENGTH]
Definition midas.h:1029
INT item_size
Definition midas.h:1032
double d
Definition system.cxx:1311
static double sub(double a, double b)
Definition tinyexpr.c:244