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