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  std::map<std::string, PropertyItem>::iterator 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 (unsigned int i=0; i<work.length(); i++) {
264  buf += work[i];
265  if (work[i]=='\\') {
266  buf += work[i];
267  }
268  }
269  work = buf;
270  }
271  }
272  accum.add(Value::makeValue(work.c_str()));
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.c_str())) : owner.findGroup(base.c_str());
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 += "[include " + section + " \"" + fname + "\" \"" + fname + "\"]\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().c_str();
375 
377  std::string("looking for ") + fname.c_str() + ", 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 ") + fname + " as " +
394  trial.c_str());
395 
396  txt = "";
397  if (readFile(trial.c_str(), txt, true)) {
398  ok = true;
399  pathPrefix = ss.get(i);
400  pathPrefix += '/';
401  break;
402  }
403  }
404  }
405 
406  std::string path("");
407  size_t index = fname.rfind('/');
408  if (index==std::string::npos) {
409  index = fname.rfind('\\');
410  }
411  if (index!=std::string::npos) {
412  path = fname.substr(0, index);
413  }
414 
415  if (!ok) {
416  YARP_ERROR(Logger::get(), std::string("cannot read from ") +
417  fname);
418  return false;
419  }
420 
421  Property envExtended;
422  envExtended.fromString(env.toString());
423  if (path!="") {
424  if (searchPath.length()>0) {
425  searchPath += ";";
426  }
427  searchPath += pathPrefix;
428  searchPath += path;
429  envExtended.put("CONFIG_PATH", searchPath.c_str());
430  }
431 
432  fromConfig(txt.c_str(), envExtended, wipe);
433  return true;
434  }
435 
436  bool fromConfigDir(const std::string& dirname, const std::string& section, bool wipe=true) {
437  Property p;
438  if (section.empty()) {
439  return fromConfigFile(dirname, p, wipe);
440  }
441 
442  YARP_DEBUG(Logger::get(), std::string("looking for ") + dirname.c_str());
443 
444  yarp::os::impl::DIR *dir = yarp::os::impl::opendir(dirname.c_str());
445  if (!dir) {
446  YARP_ERROR(Logger::get(), std::string("cannot read from ") + dirname);
447  return false;
448  }
449 
450  std::string txt;
451  if (!readDir(dirname, dir, txt, section)) {
452  YARP_ERROR(Logger::get(), std::string("cannot read from ") + dirname);
453  return false;
454  }
455 
456  fromConfig(txt.c_str(), p, wipe);
457  return true;
458  }
459 
460  void fromConfig(const char *txt, Searchable& env, bool wipe=true) {
461  StringInputStream sis;
462  sis.add(txt);
463  sis.add("\n");
464  if (wipe) {
465  clear();
466  }
467  std::string tag = "";
468  Bottle accum;
469  bool done = false;
470  do {
471  bool isTag = false;
472  bool including = false;
473  std::string buf;
474  bool good = true;
475  buf = sis.readLine('\n', &good);
476  while (good && !BottleImpl::isComplete(buf.c_str())) {
477  buf += sis.readLine('\n', &good);
478  }
479  if (!good) {
480  done = true;
481  }
482  if (!done) {
483  including = false;
484 
485  if (buf.find("//")!=std::string::npos||buf.find('#')!=std::string::npos) {
486  bool quoted = false;
487  bool prespace = true;
488  int comment = 0;
489  for (unsigned int i=0; i<buf.length(); i++) {
490  char ch = buf[i];
491  if (ch=='\"') { quoted = !quoted; }
492  if (!quoted) {
493  if (ch=='/') {
494  comment++;
495  if (comment==2) {
496  buf = buf.substr(0, i-1);
497  break;
498  }
499  } else {
500  comment = 0;
501  if (ch=='#'&&prespace) {
502  if (i==0) {
503  buf = "";
504  } else {
505  buf = buf.substr(0, i-1);
506  }
507  break;
508  }
509  }
510  prespace = (ch==' '||ch=='\t');
511  } else {
512  comment = 0;
513  prespace = false;
514  }
515  }
516  }
517 
518  // expand any environment references
519  buf = expand(buf.c_str(), env, owner).c_str();
520 
521  if (buf.length()>0 && buf[0]=='[') {
522  size_t stop = buf.find(']');
523  if (stop!=std::string::npos) {
524  buf = buf.substr(1, stop-1);
525  size_t space = buf.find(' ');
526  if (space!=std::string::npos) {
527  Bottle bot(buf.c_str());
528  // BEGIN Handle include option
529  if (bot.size()>1) {
530  if (bot.get(0).toString() == "include") {
531  including = true;
532  // close an open group if an [include something] tag is found
533  if (bot.size()>1) {
534  if (tag!="") {
535  if (accum.size()>=1) {
536  putBottleCompat(tag.c_str(),
537  accum);
538  }
539  tag = "";
540  }
541  }
542  if (bot.size()>2) {
543  std::string subName, fname;
544  if (bot.size()==3) {
545  // [include section "filename"]
546  subName = bot.get(1).toString();
547  fname = bot.get(2).toString();
548 
549 
550  } else if (bot.size()==4) {
551  // [include type section "filename"]
552  std::string key;
553  key = bot.get(1).toString();
554  subName = bot.get(2).toString();
555  fname = bot.get(3).toString();
556  Bottle *target =
557  getBottle(key.c_str());
558  if (target==nullptr) {
559  Bottle init;
560  init.addString(key.c_str());
561  init.addString(subName.c_str());
562  putBottleCompat(key.c_str(),
563  init);
564  } else {
565  target->addString(subName.c_str());
566  }
567  } else {
569  std::string("bad include"));
570  return;
571  }
572 
573 
574  Property p;
575  if (getBottle(subName)!=nullptr) {
576  p.fromString(getBottle(subName)->tail().toString());
577  //printf(">>> prior p %s\n",
578  // p.toString().c_str());
579  }
580  p.fromConfigFile(fname.c_str(),
581  env, false);
582  accum.fromString(p.toString());
583  tag = subName.c_str();
584  //printf(">>> tag %s accum %s\n",
585  // tag.c_str(),
586  // accum.toString().c_str());
587  if (tag!="") {
588  if (accum.size()>=1) {
589  Bottle b;
590  b.addString(tag.c_str());
591  //Bottle& subList = b.addList();
592  //subList.copy(accum);
593  b.append(accum);
594  putBottleCompat(tag.c_str(),
595  b);
596  }
597  tag = "";
598  }
599  } else {
600  tag = "";
601  std::string fname =
602  bot.get(1).toString();
603  //printf("Including %s\n", fname.c_str());
604  fromConfigFile(fname.c_str(),
605  env, false);
606  }
607  }
608  }
609  // END handle include option
610  // BEGIN handle group
611  if (bot.size()==2 && !including) {
612  buf = bot.get(1).toString().c_str();
613  std::string key = bot.get(0).toString().c_str();
614  Bottle *target = getBottle(key.c_str());
615  if (target==nullptr) {
616  Bottle init;
617  init.addString(key.c_str());
618  init.addString(buf.c_str());
619  putBottleCompat(key.c_str(), init);
620  } else {
621  target->addString(buf.c_str());
622  }
623  }
624  // END handle group
625  }
626  if (!including) {
627  isTag = true;
628  }
629  }
630  }
631  }
632  if (!isTag && !including) {
633  Bottle bot;
634  bot.fromString(buf.c_str());
635  if (bot.size()>=1) {
636  if (tag=="") {
637  putBottleCompat(bot.get(0).toString().c_str(), bot);
638  } else {
639  if (bot.get(1).asString()=="=") {
640  Bottle& b = accum.addList();
641  for (size_t i=0; i<bot.size(); i++) {
642  if (i!=1) {
643  b.add(bot.get(i));
644  }
645  }
646  } else {
647  accum.addList().copy(bot);
648  }
649  }
650  }
651  }
652  if (isTag||done) {
653  if (tag!="") {
654  if (accum.size()>=1) {
655  putBottleCompat(tag.c_str(), accum);
656  }
657  tag = "";
658  }
659  tag = buf;
660  accum.clear();
661  accum.addString(tag.c_str());
662  if (tag!="") {
663  if (getBottle(tag.c_str())!=nullptr) {
664  // merge data
665  accum.append(getBottle(tag.c_str())->tail());
666  //printf("MERGE %s, got %s\n", tag.c_str(),
667  // accum.toString().c_str());
668  }
669  }
670  }
671  } while (!done);
672  }
673 
674  void fromBottle(Bottle& bot, bool wipe=true) {
675  if (wipe) {
676  clear();
677  }
678  for (size_t i=0; i<bot.size(); i++) {
679  Value& bb = bot.get(i);
680  if (bb.isList()) {
681  Bottle *sub = bb.asList();
682  putBottle(bb.asList()->get(0).toString().c_str(), *sub);
683  }
684  }
685  }
686 
687  std::string toString() const {
688  Bottle bot;
689  for (std::map<std::string, PropertyItem>::const_iterator it = data.begin(); it != data.end(); ++it) {
690  const PropertyItem& rec = it->second;
691  Bottle& sub = bot.addList();
692  rec.flush();
693  sub.copy(rec.bot);
694  }
695  return bot.toString();
696  }
697 
698  // expand any environment variables found
699  std::string expand(const char *txt, Searchable& env, Searchable& env2) {
700  //printf("expanding %s\n", txt);
701  std::string input = txt;
702  if (input.find('$')==std::string::npos) {
703  // no variables present for sure
704  return txt;
705  }
706  // check if variables present
707  std::string output = "";
708  std::string var = "";
709  bool inVar = false;
710  bool varHasParen = false;
711  bool quoted = false;
712  for (int i=0; i<=(int)input.length(); i++) {
713  char ch = 0;
714  if (i<(int)input.length()) {
715  ch = input[i];
716  }
717  if (quoted) {
718  if (!inVar) {
719  output += '\\';
720  if (ch!=0) {
721  output += ch;
722  }
723  } else {
724  if (ch!=0) {
725  var += ch;
726  }
727  }
728  quoted = false;
729  continue;
730  } else {
731  if (ch=='\\') {
732  quoted = true;
733  continue;
734  }
735  }
736 
737  if (inVar) {
738  if (isalnum(ch)||(ch=='_')) {
739  var += ch;
740  continue;
741  } else {
742  if (ch=='('||ch=='{') {
743  if (var.length()==0) {
744  // ok, just ignore
745  varHasParen = true;
746  continue;
747  }
748  }
749  inVar = false;
750  //printf("VARIABLE %s\n", var.c_str());
751  std::string add = NetworkBase::getEnvironment(var.c_str()).c_str();
752  if (add=="") {
753  add = env.find(var.c_str()).toString().c_str();
754  }
755  if (add=="") {
756  add = env2.find(var.c_str()).toString().c_str();
757  }
758  if (add=="") {
759  if (var=="__YARP__") {
760  add = "1";
761  }
762  }
763  if (add.find('\\')!=std::string::npos) {
764  // Specifically when reading from the command
765  // line, we will allow windows-style paths.
766  // Hence we have to break the "\" character
767  std::string buf = "";
768  for (unsigned int i=0; i<add.length(); i++) {
769  buf += add[i];
770  if (add[i]=='\\') {
771  buf += add[i];
772  }
773  }
774  add = buf;
775  }
776  output += add;
777  var = "";
778  if (varHasParen && (ch=='}'||ch==')')) {
779  continue;
780  // don't need current char
781  }
782  }
783  }
784 
785  if (!inVar) {
786  if (ch=='$') {
787  inVar = true;
788  varHasParen = false;
789  continue;
790  } else {
791  if (ch!=0) {
792  output += ch;
793  }
794  }
795  }
796  }
797  return output.c_str();
798  }
799 
800  void fromArguments(const char *command, bool wipe=true) {
801  char** szarg = new char*[128 + 1]; // maximum 128 arguments
802  char* szcmd = new char[strlen(command)+1];
803  strcpy(szcmd, command);
804  int nargs = 0;
805  parseArguments(szcmd, &nargs, szarg, 128);
806  szarg[nargs]=nullptr;
807  fromCommand(nargs, szarg, wipe);
808  // clear allocated memory for arguments
809  delete [] szcmd;
810  szcmd = nullptr;
811  delete [] szarg;
812  szarg = nullptr;
813  }
814 
815  void parseArguments(char *azParam, int *argc, char **argv, int max_arg) {
816  char *pNext = azParam;
817  size_t i;
818  int j;
819  int quoted = 0;
820  size_t len = strlen(azParam);
821 
822  // Protect spaces inside quotes, but lose the quotes
823  for(i = 0; i < len; i++) {
824  if ((!quoted) && ('"' == azParam [i])) {
825  quoted = 1;
826  azParam [i] = ' ';
827  } else if ((quoted) && ('"' == azParam [i])) {
828  quoted = 0;
829  azParam [i] = ' ';
830  } else if ((quoted) && (' ' == azParam [i])) {
831  azParam [i] = '\1';
832  }
833  }
834 
835  // init
836  memset(argv, 0x00, sizeof(char*) * max_arg);
837  *argc = 1;
838  argv[0] = azParam ;
839 
840  while ((nullptr != pNext) && (*argc < max_arg)) {
841  splitArguments(pNext, &(argv[*argc]));
842  pNext = argv[*argc];
843 
844  if (nullptr != argv[*argc]) {
845  *argc += 1;
846  }
847  }
848 
849  for(j = 0; j < *argc; j++) {
850  len = strlen(argv[j]);
851  for(i = 0; i < len; i++) {
852  if ('\1' == argv[j][i]) {
853  argv[j][i] = ' ';
854  }
855  }
856  }
857  }
858 
859  void splitArguments(char *line, char **args) {
860  char *pTmp = strchr(line, ' ');
861  if (pTmp) {
862  *pTmp = '\0';
863  pTmp++;
864  while ((*pTmp) && (*pTmp == ' ')) {
865  pTmp++;
866  }
867  if (*pTmp == '\0') {
868  pTmp = nullptr;
869  }
870  }
871  *args = pTmp;
872  }
873 
874 
875 };
876 
877 
878 // implementation is a PropertyHelper
879 #define HELPER(x) (*((PropertyHelper*)(x)))
880 
881 
882 Property::Property(int hash_size) {
883  this->hash_size = hash_size;
884  implementation = nullptr;
885 }
886 
887 
888 Property::Property(const char *str) {
889  hash_size = 0;
890  implementation = new PropertyHelper(*this, 0);
891  yAssert(implementation!=nullptr);
892  fromString(str);
893 }
894 
895 
897  hash_size = 0;
898  implementation = new PropertyHelper(*this, 0);
899  yAssert(implementation!=nullptr);
900  fromString(prop.toString());
901 }
902 
903 
905  if (check()) return;
907  yAssert(implementation!=nullptr);
908 }
909 
910 
911 bool Property::check() const {
912  return implementation!=nullptr;
913 }
914 
915 
917  if (implementation!=nullptr) {
918  delete &HELPER(implementation);
919  implementation = nullptr;
920  }
921 }
922 
923 
925  summon();
926  fromString(prop.toString());
927  return *this;
928 }
929 
930 
931 void Property::put(const std::string& key, const std::string& value) {
932  summon();
933  HELPER(implementation).put(key, value);
934 }
935 
936 void Property::put(const std::string& key, const Value& value) {
937  summon();
938  HELPER(implementation).put(key, value);
939 }
940 
941 
942 void Property::put(const std::string& key, Value *value) {
943  summon();
944  HELPER(implementation).put(key, value);
945 }
946 
947 void Property::put(const std::string& key, int value) {
948  summon();
949  put(key, Value::makeInt32(value));
950 }
951 
952 void Property::put(const std::string& key, double value) {
953  summon();
954  put(key, Value::makeFloat64(value));
955 }
956 
957 bool Property::check(const std::string& key) const {
958  if (!check()) return false;
959  return HELPER(implementation).check(key);
960 }
961 
962 
963 void Property::unput(const std::string& key) {
964  summon();
965  HELPER(implementation).unput(key);
966 }
967 
968 
969 Value& Property::find(const std::string& key) const {
970  if (!check()) return Value::getNullValue();
971  return HELPER(implementation).get(key);
972 }
973 
974 
976  summon();
977  HELPER(implementation).clear();
978 }
979 
980 
981 void Property::fromString(const std::string& txt, bool wipe) {
982  summon();
983  HELPER(implementation).fromString(txt, wipe);
984 }
985 
986 
987 std::string Property::toString() const {
988  if (!check()) return "";
989  return HELPER(implementation).toString();
990 }
991 
992 void Property::fromCommand(int argc, char *argv[], bool skipFirst,
993  bool wipe) {
994  summon();
995  if (skipFirst) {
996  argc--;
997  argv++;
998  }
999  HELPER(implementation).fromCommand(argc, argv, wipe);
1000 }
1001 
1002 void Property::fromCommand(int argc, const char *argv[], bool skipFirst, bool wipe) {
1003  summon();
1004  fromCommand(argc, (char **)argv, skipFirst, wipe);
1005 }
1006 
1007 void Property::fromArguments(const char *arguments, bool wipe) {
1008  summon();
1009  HELPER(implementation).fromArguments(arguments, wipe);
1010 }
1011 
1012 bool Property::fromConfigDir(const std::string& dirname, const std::string& section, bool wipe) {
1013  summon();
1014  return HELPER(implementation).fromConfigDir(dirname, section, wipe);
1015 }
1016 
1017 bool Property::fromConfigFile(const std::string& fname, bool wipe) {
1018  summon();
1019  Property p;
1020  return fromConfigFile(fname, p, wipe);
1021 }
1022 
1023 
1024 bool Property::fromConfigFile(const std::string& fname, Searchable& env, bool wipe) {
1025  summon();
1026  return HELPER(implementation).fromConfigFile(fname, env, wipe);
1027 }
1028 
1029 void Property::fromConfig(const char *txt, bool wipe) {
1030  summon();
1031  Property p;
1032  fromConfig(txt, p, wipe);
1033 }
1034 
1035 void Property::fromConfig(const char *txt, Searchable& env, bool wipe) {
1036  summon();
1037  HELPER(implementation).fromConfig(txt, env, wipe);
1038 }
1039 
1040 
1042  // for now just delegate to Bottle
1043  Bottle b;
1044  bool ok = b.read(reader);
1045  if (ok) {
1046  fromString(b.toString());
1047  }
1048  return ok;
1049 }
1050 
1051 
1052 bool Property::write(ConnectionWriter& writer) const {
1053  // for now just delegate to Bottle
1054  Bottle b(toString());
1055  return b.write(writer);
1056 }
1057 
1058 
1059 Bottle& Property::findGroup(const std::string& key) const {
1060  if (!check()) return Bottle::getNullBottle();
1061  Bottle *result = HELPER(implementation).getBottle(key);
1062  if (getMonitor()!=nullptr) {
1063  SearchReport report;
1064  report.key = key;
1065  report.isGroup = true;
1066  if (result != nullptr) {
1067  report.isFound = true;
1068  report.value = result->toString();
1069  }
1070  reportToMonitor(report);
1071  if (result != nullptr) {
1072  std::string context = getMonitorContext();
1073  context += ".";
1074  context += key;
1075  result->setMonitor(getMonitor(),
1076  context.c_str()); // pass on any monitoring
1077  }
1078  }
1079 
1080  if (result!=((Bottle*)nullptr)) { return *result; }
1081  return Bottle::getNullBottle();
1082 }
1083 
1084 
1085 void Property::fromQuery(const char *url, bool wipe) {
1086  summon();
1087  if (wipe) {
1088  clear();
1089  }
1090  std::string str = url;
1091  str += "&";
1092  std::string buf = "";
1093  std::string key = "";
1094  std::string val = "";
1095  int code = 0;
1096  int coding = 0;
1097 
1098  for (unsigned int i=0; i<str.length(); i++) {
1099  char ch = str[i];
1100  if (ch=='=') {
1101  key = buf;
1102  val = "";
1103  buf = "";
1104  //printf("adding key %s\n", key.c_str());
1105  } else if (ch=='&') {
1106  //printf("adding val %s\n", val.c_str());
1107  val = buf;
1108  buf = "";
1109  if (key!="" && val!="") {
1110  put(key.c_str(), val.c_str());
1111  }
1112  key = "";
1113  } else if (ch=='?') {
1114  buf = "";
1115  } else {
1116  if (ch=='+') {
1117  ch = ' ';
1118  } else if (ch=='%') {
1119  coding = 2;
1120  } else {
1121  if (coding) {
1122  int hex = 0;
1123  if (ch>='0'&&ch<='9') { hex = ch-'0'; }
1124  if (ch>='A'&&ch<='F') { hex = ch-'A'+10; }
1125  if (ch>='a'&&ch<='f') { hex = ch-'a'+10; }
1126  code *= 16;
1127  code += hex;
1128  coding--;
1129  if (coding == 0) {
1130  ch = code;
1131  }
1132  }
1133  }
1134  if (coding==0) {
1135  buf += ch;
1136  }
1137  }
1138  }
1139 }
1140 
1141 
1142 Property& yarp::os::Property::addGroup(const std::string& key) {
1143  summon();
1144  return HELPER(implementation).addGroup(key);
1145 }
const Property & operator=(const Property &prop)
Assignment operator.
Definition: Property.cpp:924
std::string expand(const char *txt, Searchable &env, Searchable &env2)
Definition: Property.cpp:699
void fromString(const std::string &text)
Initializes bottle from a string.
Definition: Bottle.cpp:163
void splitArguments(char *line, char **args)
Definition: Property.cpp:859
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:815
A class for storing options and configuration information.
Definition: Property.h:35
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:65
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:27
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:433
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:987
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:911
#define HELPER(x)
Definition: Property.cpp:879
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:1029
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
virtual Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:969
void fromArguments(const char *command, bool wipe=true)
Definition: Property.cpp:800
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:674
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:1336
Property & owner
Definition: Property.cpp:79
A simple collection of objects that can be described and transmitted in a portable way...
Definition: Bottle.h:70
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:963
virtual Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Property.cpp:1059
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:104
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:241
virtual ~Property()
Destructor.
Definition: Property.cpp:916
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:1085
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:436
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:40
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:981
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:1012
void clear()
Remove all associations.
Definition: Property.cpp:975
bool check(const std::string &key, Value *&output) const
Definition: Property.cpp:143
std::string toString() const
Definition: Property.cpp:687
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
virtual 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:1052
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:460
Property & addGroup(const std::string &key)
Add a nested group.
Definition: Property.cpp:1142
bool read(ConnectionReader &reader) override
Read this object from a network connection.
Definition: Property.cpp:1041
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:1007
Property(int hash_size=0)
Constructor.
Definition: Property.cpp:882
bool fromConfigFile(const std::string &fname, bool wipe=true)
Interprets a file as a list of properties.
Definition: Property.cpp:1017
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:931
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:992
Value & get(size_t index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:205