YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Property.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <yarp/os/Property.h>
8
10#include <yarp/conf/string.h>
11
12#include <yarp/os/Bottle.h>
13#include <yarp/os/NetType.h>
19
20#include <algorithm>
21#include <cctype>
22#include <cstdio>
23#include <cstring>
24#include <map>
25#include <memory>
26
27using namespace yarp::os::impl;
28using namespace yarp::os;
29
30namespace {
31YARP_OS_LOG_COMPONENT(PROPERTY, "yarp.os.Property" )
32}
33
35{
36public:
38 std::unique_ptr<Property> backing;
39
40 PropertyItem() = default;
41
43 bot(rhs.bot),
44 backing(nullptr)
45 {
46 if (rhs.backing) {
47 backing = std::make_unique<Property>(*(rhs.backing));
48 }
49 }
50
52 {
53 if (&rhs != this) {
54 bot = rhs.bot;
55 if (rhs.backing) {
56 backing = std::make_unique<Property>(*(rhs.backing));
57 }
58 }
59 return *this;
60 }
61
62 PropertyItem(PropertyItem&& rhs) noexcept = default;
63 PropertyItem& operator=(PropertyItem&& rhs) noexcept = default;
64
65 ~PropertyItem() = default;
66
67 void clear()
68 {
69 backing.reset();
70 }
71
72 /*
73 * The const version of the processBuffered() method performs a const_cast,
74 * and calls the non-const version. This allows to call it in const methods.
75 * Conceptually this is not completely wrong because it does not modify
76 * the external state of the class, but just some internal representation.
77 */
78 void flush() const
79 {
80 const_cast<PropertyItem*>(this)->flush();
81 }
82
83 void flush()
84 {
85 if (backing) {
86 Bottle flatten(backing->toString());
88 clear();
89 }
90 }
91
92 std::string toString() const
93 {
94 flush();
95 return bot.toString();
96 }
97};
98
100{
101public:
102 std::map<std::string, PropertyItem> data;
104
105 explicit Private(Property* owner) :
106 owner(owner)
107 {
108 }
109
110 PropertyItem* getPropNoCreate(const std::string& key) const
111 {
112 auto it = data.find(key);
113 if (it == data.end()) {
114 return nullptr;
115 }
116 return const_cast<PropertyItem*>(&(it->second));
117 }
118
119 PropertyItem* getProp(const std::string& key, bool create = true)
120 {
121 auto entry = data.find(key);
122 if (entry == data.end()) {
123 if (!create) {
124 return nullptr;
125 }
126 data[key] = PropertyItem();
127 entry = data.find(key);
128 }
129 yCAssert(PROPERTY, entry != data.end());
130 return &(entry->second);
131 }
132
133 void put(const std::string& key, const std::string& val)
134 {
135 PropertyItem* p = getProp(key, true);
136 p->clear();
137 p->bot.clear();
138 p->bot.addString(key);
139 p->bot.addString(val);
140 }
141
142 void put(const std::string& key, const Value& bit)
143 {
144 PropertyItem* p = getProp(key, true);
145 p->clear();
146 p->bot.clear();
147 p->bot.addString(key);
148 p->bot.add(bit);
149 }
150
151 void put(const std::string& key, Value* bit)
152 {
153 PropertyItem* p = getProp(key, true);
154 p->clear();
155 p->bot.clear();
156 p->bot.addString(key);
157 p->bot.add(bit);
158 }
159
160 Property& addGroup(const std::string& key)
161 {
162 PropertyItem* p = getProp(key, true);
163 p->clear();
164 p->bot.clear();
165 p->bot.addString(key);
166 p->backing = std::make_unique<Property>();
167 return *(p->backing);
168 }
169
170 void unput(const std::string& key)
171 {
172 data.erase(key);
173 }
174
175 bool check(const std::string& key) const
176 {
178 return p != nullptr;
179 }
180
181 Value& get(const std::string& key) const
182 {
184 if (p != nullptr) {
185 p->flush();
186 return p->bot.get(1);
187 }
188 return Value::getNullValue();
189 }
190
191 Bottle& putBottleCompat(const char* key, const Bottle& val)
192 {
193 if (val.get(1).asString() == "=") {
194 Bottle b;
195 b.add(val.get(0));
196 b.append(val.tail().tail());
197 return putBottle(key, b);
198 }
199 return putBottle(key, val);
200 }
201
202 Bottle& putBottle(const char* key, const Bottle& val)
203 {
204 PropertyItem* p = getProp(key, true);
205 p->clear();
206 p->bot = val;
207 return p->bot;
208 }
209
210
211 Bottle& putBottle(const char* key)
212 {
213 PropertyItem* p = getProp(key, true);
214 p->clear();
215 p->bot.clear();
216 return p->bot;
217 }
218
219
220 Bottle* getBottle(const std::string& key) const
221 {
223 if (p != nullptr) {
224 p->flush();
225 return &(p->bot);
226 }
227 return nullptr;
228 }
229
230 void clear()
231 {
232 data.clear();
233 }
234
235 void fromString(const std::string& txt, bool wipe = true)
236 {
237 Bottle bot;
238 bot.fromString(txt);
239 fromBottle(bot, wipe);
240 }
241
242 void fromCommand(int argc, char* argv[], bool wipe = true)
243 {
244 std::string tag;
247 bool qualified = false;
248 for (int i = 0; i < argc; i++) {
249 std::string work = argv[i];
250 bool isTag = false;
251 if (work.length() >= 2) {
252 if (work[0] == '-' && work[1] == '-') {
253 work = work.substr(2, work.length() - 2);
254 isTag = true;
255 if (work.find("::") != std::string::npos) {
256 qualified = true;
257 }
258 }
259 }
260 if (isTag) {
261 if (!tag.empty()) {
262 total.addList().copy(accum);
263 }
264 tag = work;
265 accum.clear();
266 } else {
267 if (work.find('\\') != std::string::npos) {
268 // Specifically when reading from the command
269 // line, we will allow windows-style paths.
270 // Hence we have to break the "\" character
271 std::string buf;
272 for (char i : work) {
273 buf += i;
274 if (i == '\\') {
275 buf += i;
276 }
277 }
278 work = buf;
279 }
280 }
282 }
283 if (!tag.empty()) {
284 total.addList().copy(accum);
285 }
286 if (!qualified) {
288 return;
289 }
290 if (wipe) {
291 clear();
292 }
293 Bottle* cursor = nullptr;
294 for (size_t i = 0; i < total.size(); i++) {
295 cursor = nullptr;
296 Bottle* term = total.get(i).asList();
297 if (term == nullptr) {
298 continue;
299 }
300 std::string key = term->get(0).asString();
301 std::string base = key;
302 while (key.length() > 0) {
303 base = key;
304 size_t at = key.find("::");
305 if (at != std::string::npos) {
306 base = key.substr(0, at);
307 key = key.substr(at + 2);
308 } else {
309 key = "";
310 }
311 Bottle& result = (cursor != nullptr) ? (cursor->findGroup(base)) : owner->findGroup(base);
312 if (result.isNull()) {
313 if (cursor == nullptr) {
314 cursor = &putBottle((base).c_str());
315 } else {
316 cursor = &cursor->addList();
317 }
318 cursor->addString(base);
319 } else {
320 cursor = &result;
321 }
322 }
323 if (cursor != nullptr) {
324 cursor->copy(*term);
325 cursor->get(0) = Value(base);
326 }
327 }
328 }
329
330 bool readDir(const std::string& dirname, yarp::os::impl::DIR*& dir, std::string& result, const std::string& section = std::string())
331 {
332 bool ok = true;
333 yCDebug(PROPERTY, "reading directory %s", dirname.c_str());
334
335 yarp::os::impl::dirent** namelist;
336 yarp::os::impl::closedir(dir);
337 dir = nullptr;
338 int n = yarp::os::impl::scandir(dirname.c_str(), &namelist, nullptr, yarp::os::impl::alphasort);
339 if (n < 0) {
340 return false;
341 }
342 for (int i = 0; i < n; i++) {
343 std::string name = namelist[i]->d_name;
344 free(namelist[i]);
345 auto len = static_cast<int>(name.length());
346 if (len < 4) {
347 continue;
348 }
349 if (name.substr(len - 4) != ".ini") {
350 continue;
351 }
352 std::string fname = std::string(dirname) + "/" + name;
353 std::replace(fname.begin(), fname.end(), '\\', '/');
354 if (section.empty()) {
355 ok = ok && readFile(fname, result, false);
356 result += "\n[]\n"; // reset any nested sections
357 } else {
358 result.append("[include ").append(section).append(" \"").append(fname).append("\" \"").append(fname).append("\"]\n");
359 }
360 }
361 free(namelist);
362 return ok;
363 }
364
365 bool readFile(const std::string& fname, std::string& result, bool allowDir)
366 {
367 if (allowDir) {
368 yarp::os::impl::DIR* dir = yarp::os::impl::opendir(fname.c_str());
369 if (dir != nullptr) {
370 return readDir(fname, dir, result);
371 }
372 }
373 yCDebug(PROPERTY, "reading file %s", fname.c_str());
374 FILE* fin = fopen(fname.c_str(), "r");
375 if (fin == nullptr) {
376 return false;
377 }
378 char buf[25600];
379 while (fgets(buf, sizeof(buf) - 1, fin) != nullptr) {
380 result += buf;
381 }
382 fclose(fin);
383 fin = nullptr;
384 return true;
385 }
386
387 bool fromConfigFile(const std::string& fname, Searchable& env, bool wipe = true)
388 {
389 std::string searchPath = env.check("CONFIG_PATH",
390 Value(""),
391 "path to search for config files")
392 .toString();
393
394 yCDebug(PROPERTY, "looking for %s, search path: %s", fname.c_str(), searchPath.c_str());
395
396 std::string pathPrefix;
397 std::string txt;
398
399 bool ok = true;
400 if (!readFile(fname, txt, true)) {
401 ok = false;
402 for (const auto& s : yarp::conf::string::split(searchPath, ';')) {
403 std::string trial = s;
404 trial += '/';
405 trial += fname;
406
407 yCDebug(PROPERTY, "looking for %s as %s", fname.c_str(), trial.c_str());
408
409 txt = "";
410 if (readFile(trial, txt, true)) {
411 ok = true;
412 pathPrefix = s;
413 pathPrefix += '/';
414 break;
415 }
416 }
417 }
418
419 std::string path;
420 size_t index = fname.rfind('/');
421 if (index == std::string::npos) {
422 index = fname.rfind('\\');
423 }
424 if (index != std::string::npos) {
425 path = fname.substr(0, index);
426 }
427
428 if (!ok) {
429 yCError(PROPERTY, "cannot read from %s", fname.c_str());
430 return false;
431 }
432
434 envExtended.fromString(env.toString());
435 if (!path.empty()) {
436 if (searchPath.length() > 0) {
437 searchPath += ";";
438 }
440 searchPath += path;
441 envExtended.put("CONFIG_PATH", searchPath);
442 }
443
444 fromConfig(txt.c_str(), envExtended, wipe);
445 return true;
446 }
447
448 bool fromConfigDir(const std::string& dirname, const std::string& section, bool wipe = true)
449 {
450 Property p;
451 if (section.empty()) {
452 return fromConfigFile(dirname, p, wipe);
453 }
454
455 yCDebug(PROPERTY, "looking for %s", dirname.c_str());
456
457 yarp::os::impl::DIR* dir = yarp::os::impl::opendir(dirname.c_str());
458 if (dir == nullptr) {
459 yCError(PROPERTY, "cannot read from %s", dirname.c_str());
460 return false;
461 }
462
463 std::string txt;
464 if (!readDir(dirname, dir, txt, section)) {
465 yCError(PROPERTY, "cannot read from %s", dirname.c_str());
466 return false;
467 }
468
469 fromConfig(txt.c_str(), p, wipe);
470 return true;
471 }
472
473 void fromConfig(const char* txt, Searchable& env, bool wipe = true)
474 {
476 sis.add(txt);
477 sis.add("\n");
478 if (wipe) {
479 clear();
480 }
481 std::string tag;
483 bool done = false;
484 do {
485 bool isTag = false;
486 bool including = false;
487 std::string buf;
488 bool good = true;
489 buf = sis.readLine('\n', &good);
490 while (good && !BottleImpl::isComplete(buf.c_str())) {
491 buf += sis.readLine('\n', &good);
492 }
493 if (!good) {
494 done = true;
495 }
496 if (!done) {
497 including = false;
498
499 if (buf.find("//") != std::string::npos || buf.find('#') != std::string::npos) {
500 bool quoted = false;
501 bool prespace = true;
502 int comment = 0;
503 for (unsigned int i = 0; i < buf.length(); i++) {
504 char ch = buf[i];
505 if (ch == '\"') {
506 quoted = !quoted;
507 }
508 if (!quoted) {
509 if (ch == '/') {
510 comment++;
511 if (comment == 2) {
512 buf = buf.substr(0, i - 1);
513 break;
514 }
515 } else {
516 comment = 0;
517 if (ch == '#' && prespace) {
518 if (i == 0) {
519 buf = "";
520 } else {
521 buf = buf.substr(0, i - 1);
522 }
523 break;
524 }
525 }
526 prespace = (ch == ' ' || ch == '\t');
527 } else {
528 comment = 0;
529 prespace = false;
530 }
531 }
532 }
533
534 // expand any environment references
535 buf = expand(buf.c_str(), env, *owner);
536
537 if (buf.length() > 0 && buf[0] == '[') {
538 size_t stop = buf.find(']');
539 if (stop != std::string::npos) {
540 buf = buf.substr(1, stop - 1);
541 size_t space = buf.find(' ');
542 if (space != std::string::npos) {
543 Bottle bot(buf);
544 // BEGIN Handle include option
545 if (bot.size() > 1) {
546 if (bot.get(0).toString() == "import")
547 {
548 including = true;
549 // close an open group if an [include something] tag is found
550 if (!tag.empty()) {
551 if (accum.size() >= 1) {
552 putBottleCompat(tag.c_str(), accum);
553 }
554 tag = "";
555 }
556 std::string contextName = bot.get(1).toString();
557 std::string fileName = bot.get(2).toString();
561 bool b = rf.configure(0,nullptr);
562 if (b)
563 {
564 tag = "";
565 std::string fname = rf.findFile(fileName);
566 yCTrace(PROPERTY, "Importing: %s\n", fname.c_str());
567 fromConfigFile(fname, env, false);
568 }
569 else
570 {
571 yCWarning(PROPERTY, "Unable to import file: %s from context %s\n", fileName.c_str(), contextName.c_str());
572 }
573 } else
574 if (bot.get(0).toString() == "include") {
575 including = true;
576 // close an open group if an [include something] tag is found
577 if (!tag.empty()) {
578 if (accum.size() >= 1) {
579 putBottleCompat(tag.c_str(), accum);
580 }
581 tag = "";
582 }
583 if (bot.size() > 2) {
584 std::string subName;
585 std::string fname;
586 if (bot.size() == 3) {
587 // [include section "filename"]
588 subName = bot.get(1).toString();
589 fname = bot.get(2).toString();
590
591
592 } else if (bot.size() == 4) {
593 // [include type section "filename"]
594 std::string key;
595 key = bot.get(1).toString();
596 subName = bot.get(2).toString();
597 fname = bot.get(3).toString();
598 Bottle* target = getBottle(key);
599 if (target == nullptr) {
600 Bottle init;
601 init.addString(key.c_str());
602 init.addString(subName.c_str());
603 putBottleCompat(key.c_str(),
604 init);
605 } else {
606 target->addString(subName.c_str());
607 }
608 } else {
609 yCError(PROPERTY, "bad include");
610 return;
611 }
612
613
614 Property p;
615 if (getBottle(subName) != nullptr) {
616 p.fromString(getBottle(subName)->tail().toString());
618 ">>> prior p %s\n",
619 p.toString().c_str());
620 }
621 p.fromConfigFile(fname, env, false);
622 accum.fromString(p.toString());
623 tag = subName;
624 yCTrace(PROPERTY, ">>> tag %s accum %s\n",
625 tag.c_str(),
626 accum.toString().c_str());
627 if (!tag.empty()) {
628 if (accum.size() >= 1) {
629 Bottle b;
630 b.addString(tag.c_str());
631 //Bottle& subList = b.addList();
632 //subList.copy(accum);
633 b.append(accum);
634 putBottleCompat(tag.c_str(),
635 b);
636 }
637 tag = "";
638 }
639 } else {
640 tag = "";
641 std::string fname = bot.get(1).toString();
642 yCTrace(PROPERTY, "Including %s\n", fname.c_str());
643 fromConfigFile(fname, env, false);
644 }
645 }
646 }
647 // END handle include option
648 // BEGIN handle group
649 if (bot.size() == 2 && !including) {
650 buf = bot.get(1).toString();
651 std::string key = bot.get(0).toString();
652 Bottle* target = getBottle(key);
653 if (target == nullptr) {
654 Bottle init;
655 init.addString(key);
656 init.addString(buf);
657 putBottleCompat(key.c_str(), init);
658 } else {
659 target->addString(buf);
660 }
661 }
662 // END handle group
663 }
664 if (!including) {
665 isTag = true;
666 }
667 }
668 }
669 }
670 if (!isTag && !including) {
671 Bottle bot;
672 bot.fromString(buf);
673 if (bot.size() >= 1) {
674 if (tag.empty()) {
675 putBottleCompat(bot.get(0).toString().c_str(), bot);
676 } else {
677 if (bot.get(1).asString() == "=") {
678 Bottle& b = accum.addList();
679 for (size_t i = 0; i < bot.size(); i++) {
680 if (i != 1) {
681 b.add(bot.get(i));
682 }
683 }
684 } else {
685 accum.addList().copy(bot);
686 }
687 }
688 }
689 }
690 if (isTag || done) {
691 if (!tag.empty()) {
692 if (accum.size() >= 1) {
693 putBottleCompat(tag.c_str(), accum);
694 }
695 tag = "";
696 }
697 tag = buf;
698 accum.clear();
699 accum.addString(tag);
700 if (!tag.empty()) {
701 if (getBottle(tag) != nullptr) {
702 // merge data
703 accum.append(getBottle(tag)->tail());
705 "MERGE %s, got %s\n",
706 tag.c_str(),
707 accum.toString().c_str());
708 }
709 }
710 }
711 } while (!done);
712 }
713
714 void fromBottle(Bottle& bot, bool wipe = true)
715 {
716 if (wipe) {
717 clear();
718 }
719 for (size_t i = 0; i < bot.size(); i++) {
720 Value& bb = bot.get(i);
721 if (bb.isList()) {
722 Bottle* sub = bb.asList();
723 putBottle(bb.asList()->get(0).toString().c_str(), *sub);
724 }
725 }
726 }
727
728 std::string toString() const
729 {
730 Bottle bot;
731 for (const auto& it : data) {
732 const PropertyItem& rec = it.second;
733 Bottle& sub = bot.addList();
734 rec.flush();
735 sub.copy(rec.bot);
736 }
737 return bot.toString();
738 }
739
740 // expand any environment variables found
741 std::string expand(const char* txt, Searchable& env, Searchable& env2)
742 {
743 yCTrace(PROPERTY, "expanding %s\n", txt);
744 std::string input = txt;
745 if (input.find('$') == std::string::npos) {
746 // no variables present for sure
747 return txt;
748 }
749 // check if variables present
750 std::string output;
751 std::string var;
752 bool inVar = false;
753 bool varHasParen = false;
754 bool quoted = false;
755 for (size_t i = 0; i <= input.length(); i++) {
756 char ch = 0;
757 if (i < input.length()) {
758 ch = input[i];
759 }
760 if (quoted) {
761 if (!inVar) {
762 output += '\\';
763 if (ch != 0) {
764 output += ch;
765 }
766 } else {
767 if (ch != 0) {
768 var += ch;
769 }
770 }
771 quoted = false;
772 continue;
773 }
774 if (ch == '\\') {
775 quoted = true;
776 continue;
777 }
778
779 if (inVar) {
780 if ((isalnum(ch) != 0) || (ch == '_')) {
781 var += ch;
782 continue;
783 }
784 if (ch == '(' || ch == '{') {
785 if (var.length() == 0) {
786 // ok, just ignore
787 varHasParen = true;
788 continue;
789 }
790 }
791 inVar = false;
792 yCTrace(PROPERTY, "VARIABLE %s\n", var.c_str());
793 std::string add = yarp::conf::environment::get_string(var);
794 if (add.empty()) {
795 add = env.find(var).toString();
796 }
797 if (add.empty()) {
798 add = env2.find(var).toString();
799 }
800 if (add.empty()) {
801 if (var == "__YARP__") {
802 add = "1";
803 }
804 }
805 if (add.find('\\') != std::string::npos) {
806 // Specifically when reading from the command
807 // line, we will allow windows-style paths.
808 // Hence we have to break the "\" character
809 std::string buf;
810 for (char c : add) {
811 buf += c;
812 if (c == '\\') {
813 buf += c;
814 }
815 }
816 add = buf;
817 }
818 output += add;
819 var = "";
820 if (varHasParen && (ch == '}' || ch == ')')) {
821 continue;
822 // don't need current char
823 }
824 }
825
826 if (!inVar) {
827 if (ch == '$') {
828 inVar = true;
829 varHasParen = false;
830 continue;
831 }
832 if (ch != 0) {
833 output += ch;
834 }
835 }
836 }
837 return output;
838 }
839
840 void fromArguments(const char* command, bool wipe = true)
841 {
842 char** szarg = new char*[128 + 1]; // maximum 128 arguments
843 char* szcmd = new char[strlen(command) + 1];
844 strcpy(szcmd, command);
845 int nargs = 0;
847 szarg[nargs] = nullptr;
849 // clear allocated memory for arguments
850 delete[] szcmd;
851 szcmd = nullptr;
852 delete[] szarg;
853 szarg = nullptr;
854 }
855
856 void parseArguments(char* azParam, int* argc, char** argv, int max_arg)
857 {
858 char* pNext = azParam;
859 size_t i;
860 int j;
861 int quoted = 0;
862 size_t len = strlen(azParam);
863
864 // Protect spaces inside quotes, but lose the quotes
865 for (i = 0; i < len; i++) {
866 if ((quoted == 0) && ('"' == azParam[i])) {
867 quoted = 1;
868 azParam[i] = ' ';
869 } else if (((quoted) != 0) && ('"' == azParam[i])) {
870 quoted = 0;
871 azParam[i] = ' ';
872 } else if (((quoted) != 0) && (' ' == azParam[i])) {
873 azParam[i] = '\1';
874 }
875 }
876
877 // init
878 memset(argv, 0x00, sizeof(char*) * max_arg);
879 *argc = 1;
880 argv[0] = azParam;
881
882 while ((nullptr != pNext) && (*argc < max_arg)) {
883 splitArguments(pNext, &(argv[*argc]));
884 pNext = argv[*argc];
885
886 if (nullptr != argv[*argc]) {
887 *argc += 1;
888 }
889 }
890
891 for (j = 0; j < *argc; j++) {
892 len = strlen(argv[j]);
893 for (i = 0; i < len; i++) {
894 if ('\1' == argv[j][i]) {
895 argv[j][i] = ' ';
896 }
897 }
898 }
899 }
900
901 void splitArguments(char* line, char** args)
902 {
903 char* pTmp = strchr(line, ' ');
904 if (pTmp != nullptr) {
905 *pTmp = '\0';
906 pTmp++;
907 while (*pTmp == ' ') {
908 pTmp++;
909 }
910 if (*pTmp == '\0') {
911 pTmp = nullptr;
912 }
913 }
914 *args = pTmp;
915 }
916};
917
919 Searchable(),
920 Portable(),
921 mPriv(new Private(this))
922{
923}
924
925Property::Property(const char* str) :
926 Searchable(),
927 Portable(),
928 mPriv(new Private(this))
929{
930 fromString(str);
931}
932
936 mPriv(new Private(this))
937{
938 fromString(prop.toString());
939}
940
942 Searchable(std::move(static_cast<Searchable&>(prop))),
943 Portable(std::move(static_cast<Portable&>(prop))),
944 mPriv(prop.mPriv)
945{
946 mPriv->owner = this;
947
948 prop.mPriv = nullptr;
949}
950
951Property::Property(std::initializer_list<std::pair<std::string, yarp::os::Value>> values) :
952 Searchable(),
953 Portable(),
954 mPriv(new Private(this))
955{
956 for (const auto& val : values) {
957 put(val.first, val.second);
958 }
959}
960
962{
963 delete mPriv;
964}
965
967{
968 if (&rhs != this) {
969 Searchable::operator=(static_cast<const Searchable&>(rhs));
970 Portable::operator=(static_cast<const Portable&>(rhs));
971 mPriv->data = rhs.mPriv->data;
972 mPriv->owner = this;
973 }
974 return *this;
975}
976
978{
979 Searchable::operator=(std::move(static_cast<Searchable&>(rhs)));
980 Portable::operator=(std::move(static_cast<Portable&>(rhs)));
981 std::swap(mPriv, rhs.mPriv);
982 mPriv->owner = this;
983 rhs.mPriv->owner = &rhs;
984 return *this;
985}
986
987void Property::put(const std::string& key, const std::string& value)
988{
989 mPriv->put(key, value);
990}
991
992void Property::put(const std::string& key, const Value& value)
993{
994 mPriv->put(key, value);
995}
996
997
998void Property::put(const std::string& key, Value* value)
999{
1000 mPriv->put(key, value);
1001}
1002
1003void Property::put(const std::string& key, int value)
1004{
1005 put(key, Value::makeInt32(value));
1006}
1007
1008void Property::put(const std::string& key, double value)
1009{
1010 put(key, Value::makeFloat64(value));
1011}
1012
1013bool Property::check(const std::string& key) const
1014{
1015 return mPriv->check(key);
1016}
1017
1018void Property::unput(const std::string& key)
1019{
1020 mPriv->unput(key);
1021}
1022
1023Value& Property::find(const std::string& key) const
1024{
1025 return mPriv->get(key);
1026}
1027
1028
1030{
1031 mPriv->clear();
1032}
1033
1034
1035void Property::fromString(const std::string& txt, bool wipe)
1036{
1037 mPriv->fromString(txt, wipe);
1038}
1039
1040
1041std::string Property::toString() const
1042{
1043 return mPriv->toString();
1044}
1045
1046void Property::fromCommand(int argc, char* argv[], bool skipFirst, bool wipe)
1047{
1048 if (skipFirst) {
1049 argc--;
1050 argv++;
1051 }
1052 mPriv->fromCommand(argc, argv, wipe);
1053}
1054
1055void Property::fromCommand(int argc, const char* argv[], bool skipFirst, bool wipe)
1056{
1057 fromCommand(argc, const_cast<char**>(argv), skipFirst, wipe);
1058}
1059
1060void Property::fromArguments(const char* arguments, bool wipe)
1061{
1062 mPriv->fromArguments(arguments, wipe);
1063}
1064
1065bool Property::fromConfigDir(const std::string& dirname, const std::string& section, bool wipe)
1066{
1067 return mPriv->fromConfigDir(dirname, section, wipe);
1068}
1069
1070bool Property::fromConfigFile(const std::string& fname, bool wipe)
1071{
1072 Property p;
1073 return fromConfigFile(fname, p, wipe);
1074}
1075
1076
1077bool Property::fromConfigFile(const std::string& fname, Searchable& env, bool wipe)
1078{
1079 return mPriv->fromConfigFile(fname, env, wipe);
1080}
1081
1082void Property::fromConfig(const char* txt, bool wipe)
1083{
1084 Property p;
1085 fromConfig(txt, p, wipe);
1086}
1087
1088void Property::fromConfig(const char* txt, Searchable& env, bool wipe)
1089{
1090 mPriv->fromConfig(txt, env, wipe);
1091}
1092
1093
1095{
1096 // for now just delegate to Bottle
1097 Bottle b;
1098 bool ok = b.read(reader);
1099 if (ok) {
1100 fromString(b.toString());
1101 }
1102 return ok;
1103}
1104
1105
1107{
1108 // for now just delegate to Bottle
1109 Bottle b(toString());
1110 return b.write(writer);
1111}
1112
1113
1114Bottle& Property::findGroup(const std::string& key) const
1115{
1116 Bottle* result = mPriv->getBottle(key);
1117 if (result != nullptr) {
1118 return *result;
1119 }
1120 return Bottle::getNullBottle();
1121}
1122
1123
1124void Property::fromQuery(const char* url, bool wipe)
1125{
1126 if (wipe) {
1127 clear();
1128 }
1129 std::string str = url;
1130 str += "&";
1131 std::string buf;
1132 std::string key;
1133 std::string val;
1134 int code = 0;
1135 int coding = 0;
1136
1137 for (char ch : str) {
1138 if (ch == '=') {
1139 key = buf;
1140 val = "";
1141 buf = "";
1142 yCTrace(PROPERTY, "adding key %s\n", key.c_str());
1143 } else if (ch == '&') {
1144 yCTrace(PROPERTY, "adding val %s\n", val.c_str());
1145 val = buf;
1146 buf = "";
1147 if (!key.empty() && !val.empty()) {
1148 put(key, val);
1149 }
1150 key = "";
1151 } else if (ch == '?') {
1152 buf = "";
1153 } else {
1154 if (ch == '+') {
1155 ch = ' ';
1156 } else if (ch == '%') {
1157 coding = 2;
1158 } else {
1159 if (coding != 0) {
1160 int hex = 0;
1161 if (ch >= '0' && ch <= '9') {
1162 hex = ch - '0';
1163 }
1164 if (ch >= 'A' && ch <= 'F') {
1165 hex = ch - 'A' + 10;
1166 }
1167 if (ch >= 'a' && ch <= 'f') {
1168 hex = ch - 'a' + 10;
1169 }
1170 code *= 16;
1171 code += hex;
1172 coding--;
1173 if (coding == 0) {
1174 ch = code;
1175 }
1176 }
1177 }
1178 if (coding == 0) {
1179 buf += ch;
1180 }
1181 }
1182 }
1183}
1184
1185
1187{
1188 return mPriv->addGroup(key);
1189}
void clear()
Definition Property.cpp:67
std::string toString() const
Definition Property.cpp:92
~PropertyItem()=default
PropertyItem(PropertyItem &&rhs) noexcept=default
void flush() const
Definition Property.cpp:78
PropertyItem & operator=(const PropertyItem &rhs)
Definition Property.cpp:51
PropertyItem & operator=(PropertyItem &&rhs) noexcept=default
PropertyItem(const PropertyItem &rhs)
Definition Property.cpp:42
void flush()
Definition Property.cpp:83
std::unique_ptr< Property > backing
Definition Property.cpp:38
PropertyItem()=default
void unput(const std::string &key)
Definition Property.cpp:170
void fromCommand(int argc, char *argv[], bool wipe=true)
Definition Property.cpp:242
void put(const std::string &key, const Value &bit)
Definition Property.cpp:142
Private(Property *owner)
Definition Property.cpp:105
Value & get(const std::string &key) const
Definition Property.cpp:181
Bottle * getBottle(const std::string &key) const
Definition Property.cpp:220
void parseArguments(char *azParam, int *argc, char **argv, int max_arg)
Definition Property.cpp:856
Property & addGroup(const std::string &key)
Definition Property.cpp:160
std::string toString() const
Definition Property.cpp:728
bool check(const std::string &key) const
Definition Property.cpp:175
void put(const std::string &key, const std::string &val)
Definition Property.cpp:133
void fromArguments(const char *command, bool wipe=true)
Definition Property.cpp:840
bool fromConfigDir(const std::string &dirname, const std::string &section, bool wipe=true)
Definition Property.cpp:448
void fromConfig(const char *txt, Searchable &env, bool wipe=true)
Definition Property.cpp:473
void fromBottle(Bottle &bot, bool wipe=true)
Definition Property.cpp:714
Bottle & putBottle(const char *key)
Definition Property.cpp:211
void fromString(const std::string &txt, bool wipe=true)
Definition Property.cpp:235
std::map< std::string, PropertyItem > data
Definition Property.cpp:102
PropertyItem * getProp(const std::string &key, bool create=true)
Definition Property.cpp:119
bool fromConfigFile(const std::string &fname, Searchable &env, bool wipe=true)
Definition Property.cpp:387
PropertyItem * getPropNoCreate(const std::string &key) const
Definition Property.cpp:110
Bottle & putBottleCompat(const char *key, const Bottle &val)
Definition Property.cpp:191
bool readDir(const std::string &dirname, yarp::os::impl::DIR *&dir, std::string &result, const std::string &section=std::string())
Definition Property.cpp:330
Bottle & putBottle(const char *key, const Bottle &val)
Definition Property.cpp:202
std::string expand(const char *txt, Searchable &env, Searchable &env2)
Definition Property.cpp:741
void put(const std::string &key, Value *bit)
Definition Property.cpp:151
bool readFile(const std::string &fname, std::string &result, bool allowDir)
Definition Property.cpp:365
void splitArguments(char *line, char **args)
Definition Property.cpp:901
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
static Bottle & getNullBottle()
A special Bottle with no content.
Definition Bottle.cpp:315
void add(const Value &value)
Add a Value to the bottle, at the end of the list.
Definition Bottle.cpp:309
void fromString(const std::string &text)
Initializes bottle from a string.
Definition Bottle.cpp:204
void append(const Bottle &alt)
Append the content of the given bottle to the current list.
Definition Bottle.cpp:353
Bottle & addList()
Places an empty nested list in the bottle, at the end of the list.
Definition Bottle.cpp:182
size_type size() const
Gets the number of elements in the bottle.
Definition Bottle.cpp:251
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition Bottle.cpp:240
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition Bottle.cpp:293
void copy(const Bottle &alt, size_type first=0, size_type len=npos)
Copy all or part of another Bottle.
Definition Bottle.cpp:266
Bottle tail() const
Get all but the first element of a bottle.
Definition Bottle.cpp:361
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition Bottle.cpp:230
bool isNull() const override
Checks if the object is invalid.
Definition Bottle.cpp:343
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition Bottle.cpp:170
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition Bottle.cpp:211
A mini-server for performing network communication in the background.
An interface for reading from a network connection.
An interface for writing to a network connection.
std::string readLine(const char terminal='\n', bool *success=nullptr)
Read a block of text terminated with a specific marker (or EOF).
This is a base class for objects that can be both read from and be written to the YARP network.
Definition Portable.h:25
A class for storing options and configuration information.
Definition Property.h:33
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
std::string toString() const override
Return a standard text representation of the content of the object.
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
bool fromConfigFile(const std::string &fname, bool wipe=true)
Interprets a file as a list of properties.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition Property.cpp:987
void fromConfig(const char *txt, bool wipe=true)
Parses text in the configuration format described in fromConfigFile().
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Property & operator=(const Property &prop)
Copy assignment operator.
Definition Property.cpp:966
bool write(ConnectionWriter &writer) const override
Write this object to a network connection.
bool read(ConnectionReader &reader) override
Read this object from a network connection.
bool fromConfigDir(const std::string &dirname, const std::string &section=std::string(), bool wipe=true)
Interprets all files in a directory as lists of properties as described in fromConfigFile().
void clear()
Remove all associations.
Property()
Constructor.
Definition Property.cpp:918
void fromArguments(const char *arguments, bool wipe=true)
Interprets a list of command arguments as a list of properties.
~Property() override
Destructor.
Definition Property.cpp:961
Property & addGroup(const std::string &key)
Add a nested group.
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
void fromQuery(const char *url, bool wipe=true)
Parses text in a url.
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
void fromCommand(int argc, char *argv[], bool skipFirst=true, bool wipe=true)
Interprets a list of command arguments as a list of properties.
Helper class for finding config files and other external resources.
bool setDefaultContext(const std::string &contextName)
Sets the context for the current ResourceFinder object.
bool configure(int argc, char *argv[], bool skipFirstArgument=true)
Sets up the ResourceFinder.
std::string findFile(const std::string &name)
Find the full path to a file.
bool setDefaultConfigFile(const std::string &fname)
Provide a default value for the configuration file (can be overridden from command line with the –fro...
A base class for nested structures that can be searched.
Definition Searchable.h:31
Searchable & operator=(const Searchable &rhs)=default
Copy assignment operator.
An InputStream that reads from a string.
void add(const std::string &txt)
A single value (typically within a Bottle).
Definition Value.h:43
static Value * makeFloat64(yarp::conf::float64_t x)
Create a 64-bit floating point Value.
Definition Value.cpp:416
static Value * makeValue(const std::string &txt)
Create a Value from a text description.
Definition Value.cpp:456
static Value & getNullValue()
Return an invalid, "null" Value.
Definition Value.cpp:466
std::string toString() const override
Return a standard text representation of the content of the object.
Definition Value.cpp:356
static Value * makeInt32(std::int32_t x)
Create a 32-bit integer Value.
Definition Value.cpp:401
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
static bool isComplete(const char *txt)
#define yCError(component,...)
#define yCAssert(component, x)
#define yCTrace(component,...)
#define yCWarning(component,...)
#define yCDebug(component,...)
#define YARP_OS_LOG_COMPONENT(name, name_string)
std::string get_string(const std::string &key, bool *found=nullptr)
Read a string from an environment variable.
Definition environment.h:66
ContainerT split(const typename ContainerT::value_type &s, std::basic_regex< typename ContainerT::value_type::value_type > regex)
Utility to split a string by a separator, into a vector of strings.
Definition string.h:26
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.