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