Urbi SDK Remote for C++  2.7.5
uvalue-common.cc
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2011, Gostai S.A.S.
00003  *
00004  * This software is provided "as is" without warranty of any kind,
00005  * either expressed or implied, including but not limited to the
00006  * implied warranties of fitness for a particular purpose.
00007  *
00008  * See the LICENSE file for more information.
00009  */
00010 
00012 #include <boost/algorithm/string/erase.hpp>
00013 #include <boost/algorithm/string/predicate.hpp>
00014 
00015 #include <libport/cassert>
00016 #include <libport/compiler.hh>
00017 #include <libport/cstdio>
00018 #include <libport/cstdlib>
00019 #include <libport/cstring>
00020 #include <libport/debug.hh>
00021 #include <libport/escape.hh>
00022 #include <libport/foreach.hh>
00023 #include <libport/format.hh>
00024 #include <libport/iostream>
00025 #include <libport/lexical-cast.hh>
00026 #include <libport/xalloc.hh>
00027 #include <sstream>
00028 #include <iomanip>
00029 
00030 #include <urbi/ubinary.hh>
00031 #include <urbi/uvalue.hh>
00032 
00033 GD_CATEGORY(Urbi.UValue);
00034 
00035 namespace urbi
00036 {
00037 
00038   int&
00039   kernelMajor(std::ostream& o)
00040   {
00041     typedef libport::xalloc<int> version_type;
00042     static version_type version;
00043     return version(o);
00044   }
00045 
00046   /*---------------.
00047   | UValue Casts.  |
00048   `---------------*/
00049 
00050   UBinary
00051   uvalue_caster<UBinary>::operator() (UValue& v)
00052   {
00053     if (v.type == DATA_BINARY)
00054       return UBinary(*v.binary);
00055     return UBinary();
00056   }
00057 
00058   UList
00059   uvalue_caster<UList>::operator() (UValue& v)
00060   {
00061     if (v.type == DATA_LIST)
00062       return UList(*v.list);
00063     return UList();
00064   }
00065 
00066   UDictionary
00067   uvalue_caster<UDictionary>::operator() (UValue& v)
00068   {
00069     if (v.type == DATA_DICTIONARY)
00070       return UDictionary(*v.dictionary);
00071     return UDictionary();
00072   }
00073 
00074   const char*
00075   uvalue_caster<const char*>::operator() (UValue& v)
00076   {
00077     if (v.type == DATA_STRING)
00078       return v.stringValue->c_str();
00079     return "invalid";
00080   }
00081 
00082 
00083   /*---------.
00084   | UValue.  |
00085   `---------*/
00086 
00087   UValue&
00088   UValue::error()
00089   {
00090     static UValue instance("<<UValue::error (denotes an error)>>");
00091     return instance;
00092   }
00093 
00094   static const char* formats[] = {
00095     "binary",
00096     "dictionary",
00097     "double",
00098     "list",
00099     "object",
00100     "string",
00101     "void"
00102   };
00103 
00104   const char*
00105   UValue::format_string() const
00106   {
00107     int f = static_cast<int>(type);
00108     if (f < 0 || f > DATA_VOID)
00109       return "unknown";
00110     return formats[f];
00111   }
00112 
00113 #define SKIP_SPACES()                           \
00114     while (message[pos] == ' ')                 \
00115       ++pos
00116 
00117   namespace
00118   {
00119     static
00120     bool
00121     strprefix(const char* prefix, const char* string)
00122     {
00123       return !strncmp(prefix, string, strlen(prefix));
00124     }
00125   }
00126 
00127 // Works on message[pos].
00128 #define EXPECT(Char)                                            \
00129   do {                                                          \
00130     if (message[pos] != Char)                                   \
00131     {                                                           \
00132       GD_FERROR("parse error: unexpected `%s', expected `%s'"   \
00133                 " in `%s' at %s",                               \
00134                 message[pos], Char, message, pos);              \
00135       return -pos;                                              \
00136     }                                                           \
00137   } while (false)
00138 
00139 // Works on message[p] (not pos).
00140 #define CHECK_NEOF()                                            \
00141   do {                                                          \
00142     if (!message[p])                                            \
00143     {                                                           \
00144       GD_ERROR("parse error: unexpected end of file");          \
00145       return -p;                                                \
00146     }                                                           \
00147   } while (false)
00148 
00149   int
00150   UValue::parse(const char* message, int pos,
00151                 const binaries_type& bins,
00152                 binaries_type::const_iterator& binpos)
00153   {
00154     SKIP_SPACES();
00155     if (message[pos] == '"')
00156     {
00157       //string
00158       type = DATA_STRING;
00159       //get terminating '"'
00160       int p = pos + 1;
00161       while (message[p] && message[p] != '"')
00162         p += 1 + (message[p] == '\\');
00163       CHECK_NEOF();
00164 
00165       stringValue = new std::string(
00166         libport::unescape(std::string(message + pos + 1, p - pos - 1)));
00167       return p + 1;
00168     }
00169 
00170     if (message[pos] == '[')
00171     {
00172       // List or Dictionary message.
00173       ++pos;
00174       bool hasElt = false;
00175       while (message[pos])
00176       {
00177         SKIP_SPACES();
00178         // Detect empty dictionaries.
00179         if (!hasElt && !::strncmp(message + pos, "=>", 2))
00180         {
00181           type = DATA_DICTIONARY;
00182           dictionary = new UDictionary();
00183           pos += 2;
00184           SKIP_SPACES();
00185           continue;
00186         }
00187         if (message[pos] == ']')
00188         {
00189           // End of an empty list / dictionary (created above).
00190           if (type == DATA_VOID)
00191           {
00192             // End of an empty list, create it.
00193             type = DATA_LIST;
00194             list = new UList();
00195           }
00196           break;
00197         }
00198         UValue* v = new UValue();
00199         pos = v->parse(message, pos, bins, binpos);
00200         if (pos < 0)
00201         {
00202           delete v;
00203           return pos;
00204         }
00205         SKIP_SPACES();
00206         // Here is a dictionary key.
00207         if ((type == DATA_DICTIONARY || type == DATA_VOID)
00208             && !::strncmp(message + pos, "=>", 2) && v->type == DATA_STRING)
00209         {
00210           if (type == DATA_VOID)
00211           {
00212             type = DATA_DICTIONARY;
00213             dictionary = new UDictionary();
00214           }
00215 
00216           pos += 2;
00217           SKIP_SPACES();
00218           // Handle value associated with given key.
00219           std::string key = *(v->stringValue);
00220           (*dictionary)[key] = UValue();
00221           pos = (*dictionary)[key].parse(message, pos, bins, binpos);
00222           if (pos < 0)
00223           {
00224             delete v;
00225             return pos;
00226           }
00227         }
00228         else
00229         {
00230           if (type == DATA_VOID)
00231           {
00232             type = DATA_LIST;
00233             list = new UList();
00234           }
00235           list->array.push_back(v);
00236         }
00237         SKIP_SPACES();
00238         // Expect "," or "]".
00239         if (message[pos] == ']')
00240           break;
00241         EXPECT(',');
00242         hasElt = true;
00243         ++pos;
00244       }
00245 
00246       EXPECT(']');
00247       return pos + 1;
00248     }
00249 
00250     if (strprefix("void", message+pos))
00251     {
00252       //void
00253       type = DATA_VOID;
00254       pos += 4;
00255       return pos;
00256     }
00257     if (strprefix("nil", message+pos))
00258     {
00259       //void
00260       type = DATA_VOID;
00261       pos += 3;
00262       return pos;
00263     }
00264     if (strprefix("BIN ", message + pos))
00265     {
00266       //binary message: delegate
00267       type = DATA_BINARY;
00268       binary = new UBinary();
00269       pos += 4;
00270       //parsing type
00271       return binary->parse(message, pos, bins, binpos);
00272     }
00273 
00274     // true and false used by k2
00275     if (strprefix("true", message + pos))
00276     {
00277       type = DATA_DOUBLE;
00278       val = 1;
00279       return pos+4;
00280     }
00281 
00282     if (strprefix("false", message + pos))
00283     {
00284       type = DATA_DOUBLE;
00285       val = 0;
00286       return pos+5;
00287     }
00288 
00289     // Last attempt: it should be a double.
00290     {
00291       int p;
00292       double dval; // in case ufloat is not double
00293       if (sscanf(message+pos, "%lf%n", &dval, &p))
00294       {
00295         type = DATA_DOUBLE;
00296         pos += p;
00297         val = dval;
00298         return pos;
00299       }
00300     }
00301 
00302     // Anything else is an error, but be resilient and ignore it.
00303     GD_FWARN("parse error (ignored): \"%s\"", libport::escape(message + pos));
00304     return -pos;
00305   }
00306 
00307   std::ostream&
00308   UValue::print(std::ostream& s) const
00309   {
00310     switch (type)
00311     {
00312       case DATA_DOUBLE:
00313         s << std::setprecision(21) << val;
00314         break;
00315       case DATA_STRING:
00316         s << '"' << libport::escape(*stringValue, '"') << '"';
00317         break;
00318       case DATA_SLOTNAME:
00319         s << *stringValue;
00320         break;
00321       case DATA_BINARY:
00322         s << *binary;
00323         break;
00324       case DATA_LIST:
00325         s << *list;
00326         break;
00327       case DATA_DICTIONARY:
00328         s << *dictionary;
00329         break;
00330       case DATA_VOID:
00331         s << "nil";
00332         break;
00333     }
00334     return s;
00335   }
00336 
00337 
00338 
00339   /*---------.
00340   | UValue.  |
00341   `---------*/
00342 
00344   UValue::UValue()
00345     : type(DATA_VOID), val (0), storage(0)
00346   {}
00347 
00348   // All the following mess could be avoid if we used templates...
00349   // boost::any could be very useful here.  Some day, hopefully...
00350 
00351 #define UVALUE_OPERATORS(Args, DataType, Field, Value)  \
00352   UValue::UValue(Args, bool copy)                       \
00353     : type(DataType)                                    \
00354     , Field(Value)                                      \
00355   {                                                     \
00356     LIBPORT_USE(copy);                                  \
00357   }                                                     \
00358                                                         \
00359   UValue& UValue::operator=(Args)                       \
00360   {                                                     \
00361     clear();                                            \
00362     type = DataType;                                    \
00363     Field = Value;                                      \
00364     return *this;                                       \
00365   }
00366 
00367 #define UVALUE_DOUBLE(Type)                     \
00368   UVALUE_OPERATORS(Type v, DATA_DOUBLE, val, v)
00369 
00370   UVALUE_DOUBLE(ufloat)
00371   UVALUE_DOUBLE(int)
00372   UVALUE_DOUBLE(unsigned int)
00373   UVALUE_DOUBLE(long)
00374   UVALUE_DOUBLE(unsigned long)
00375   UVALUE_DOUBLE(long long)
00376   UVALUE_DOUBLE(unsigned long long)
00377 
00378 #undef UVALUE_DOUBLE
00379 
00380 
00381   /*----------------------.
00382   | UValue: DATA_STRING.  |
00383   `----------------------*/
00384 
00385 #define UVALUE_STRING(Type, Value)                                      \
00386   UVALUE_OPERATORS(Type v, DATA_STRING, stringValue, new std::string(Value))
00387 
00388   UVALUE_STRING(const char*,        v)
00389   UVALUE_STRING(const std::string&, v)
00390   UVALUE_STRING(const void*,        (libport::format("%%ptr_%x", v)))
00391 
00392 #undef UVALUE_STRING
00393 
00394   /*----------------------.
00395   | UValue: DATA_BINARY.  |
00396   `----------------------*/
00397 
00398 #define UVALUE_BINARY(Type)                     \
00399   UVALUE_OPERATORS(Type v, DATA_BINARY, binary, new UBinary(v, copy))
00400 
00401   UVALUE_BINARY(const UBinary&)
00402   UVALUE_BINARY(const USound&)
00403   UVALUE_BINARY(const UImage&)
00404 
00405 #undef UVALUE_BINARY
00406 
00407   UVALUE_OPERATORS(const UList& v, DATA_LIST, list, new UList(v))
00408   UVALUE_OPERATORS(const UDictionary& d,
00409                    DATA_DICTIONARY, dictionary, new UDictionary(d));
00410 
00411 #undef UVALUE_OPERATORS
00412 
00413   void
00414   UValue::clear()
00415   {
00416     switch(type)
00417     {
00418       case DATA_STRING:
00419       case DATA_SLOTNAME:
00420         delete stringValue;
00421         break;
00422       case DATA_BINARY:
00423         delete binary;
00424         break;
00425       case DATA_LIST:
00426         delete list;
00427         break;
00428       case DATA_DICTIONARY:
00429         delete dictionary;
00430         break;
00431       case DATA_DOUBLE:
00432       case DATA_VOID:
00433         break;
00434     }
00435     type = DATA_VOID;
00436   }
00437 
00438   UValue::~UValue()
00439   {
00440     clear();
00441   }
00442 
00443   UValue::operator ufloat() const
00444   {
00445     switch (type)
00446     {
00447       case DATA_DOUBLE:
00448         return val;
00449       case DATA_STRING:
00450         return lexical_cast<ufloat>(*stringValue);
00451       case DATA_BINARY:
00452       case DATA_LIST:
00453       case DATA_DICTIONARY:
00454       case DATA_VOID:
00455       case DATA_SLOTNAME:
00456         break;
00457     }
00458     return ufloat(0);
00459   }
00460 
00461 
00462   UValue::operator std::string() const
00463   {
00464     switch (type)
00465     {
00466       case DATA_DOUBLE:
00467         return string_cast(val);
00468       case DATA_STRING:
00469       case DATA_SLOTNAME:
00470         return *stringValue;
00471       // We cannot convert to UBinary because it is ambigous so we
00472       // try until we found the right type.
00473       case DATA_BINARY:
00474       {
00475         USound snd(*this);
00476         if (snd.soundFormat != SOUND_UNKNOWN)
00477           return string_cast(snd);
00478         break;
00479       }
00480       default:
00481         break;
00482     }
00483     return "invalid";
00484   }
00485 
00486   UValue::operator const UBinary&() const
00487   {
00488     static UBinary dummy;
00489     if (type != DATA_BINARY)
00490       return dummy;
00491     else
00492       return *binary;
00493   }
00494 
00495   UValue::operator UImage() const
00496   {
00497     if (type == DATA_BINARY && binary->type == BINARY_IMAGE)
00498       return binary->image;
00499     return UImage::make();
00500   }
00501 
00502   UValue::operator USound() const
00503   {
00504     if (type == DATA_BINARY && binary->type == BINARY_SOUND)
00505       return binary->sound;
00506     return USound::make();
00507   }
00508 
00509   UValue::operator UList() const
00510   {
00511     if (type == DATA_LIST)
00512       return UList(*list);
00513     return UList();
00514   }
00515 
00516   UValue::operator UDictionary() const
00517   {
00518     if (type == DATA_DICTIONARY)
00519       return UDictionary(*dictionary);
00520     return UDictionary();
00521   }
00522 
00523   UValue& UValue::operator= (const UValue& v)
00524   {
00525     return set(v);
00526   }
00527 
00528   UValue& UValue::set(const UValue& v, bool copy)
00529   {
00530     // TODO: optimize
00531     if (this == &v)
00532       return *this;
00533     bool sameType = type == v.type;
00534     if (!sameType)
00535       clear();
00536 
00537     switch (v.type)
00538     {
00539       case DATA_DOUBLE:
00540         val = v.val;
00541         break;
00542       case DATA_STRING:
00543       case DATA_SLOTNAME:
00544         if (sameType)
00545           *stringValue = *v.stringValue;
00546         else
00547           stringValue = new std::string(*v.stringValue);
00548         break;
00549       case DATA_BINARY:
00550         if (sameType)
00551           delete binary;
00552         binary = new UBinary(*v.binary, copy);
00553         break;
00554       case DATA_LIST:
00555         if (sameType)
00556         {
00557           list->offset = v.list->offset;
00558           unsigned int mins
00559             = std::min(v.list->array.size(), list->array.size());
00560           // Reuse existing uvalues
00561           for (unsigned int i = 0; i<mins; ++i)
00562             list->array[i]->set(*v.list->array[i]);
00563           // Destroy extra ones
00564           for(unsigned int k= 0; k<list->array.size() - mins; ++k)
00565           {
00566             delete list->array.back();
00567             list->array.pop_back();
00568           }
00569           // Or push new ones
00570           for (unsigned int j = mins; j< v.list->array.size(); ++j)
00571             list->array.push_back(new UValue(v.list->array[j]));
00572         }
00573         else
00574           list = new UList(*v.list);
00575         break;
00576       case DATA_DICTIONARY:
00577         if (sameType)
00578         {
00579           dictionary->clear();
00580           dictionary->insert(v.dictionary->begin(), v.dictionary->end());
00581         }
00582         else
00583           dictionary = new UDictionary(*v.dictionary);
00584         break;
00585       case DATA_VOID:
00586         storage = v.storage;
00587         break;
00588     }
00589     type = v.type;
00590     return *this;
00591   }
00592 
00593 
00594   UValue::UValue(const UValue& v)
00595     : type(DATA_VOID)
00596   {
00597     *this = v;
00598   }
00599   /*--------.
00600   | UList.  |
00601   `--------*/
00602 
00603   UList::UList()
00604     : offset(0)
00605   {}
00606 
00607   UList::UList(const UList& b)
00608     : offset(0)
00609   {
00610     *this = b;
00611   }
00612 
00613   UList& UList::operator= (const UList& b)
00614   {
00615     if (this == &b)
00616       return *this;
00617     clear();
00618     foreach (UValue* v, b.array)
00619       array.push_back(new UValue(*v));
00620     offset = b.offset;
00621     return *this;
00622   }
00623 
00624   UList::~UList()
00625   {
00626     clear();
00627   }
00628 
00629   void UList::clear()
00630   {
00631     offset = 0;
00632     foreach (UValue *v, array)
00633       delete v;
00634     array.clear();
00635   }
00636 
00637   std::ostream&
00638   UList::print(std::ostream& o) const
00639   {
00640     o << '[';
00641     size_t sz = size();
00642     for (unsigned i = 0; i < sz; ++i)
00643       o << (*this)[i]
00644         << (i != sz - 1 ? ", " : "");
00645     o << ']';
00646     return o;
00647   }
00648 
00649   std::ostream&
00650   operator<< (std::ostream& o, const UList& t)
00651   {
00652     return t.print(o);
00653   }
00654 
00655   std::ostream&
00656   operator<<(std::ostream& s, const urbi::UDictionary& d)
00657   {
00658     s << "[";
00659     if (d.empty())
00660       s << "=>";
00661     else
00662     {
00663       bool isFirst = true;
00664       foreach (const UDictionary::value_type& t, d)
00665       {
00666         if (!isFirst)
00667           s << ",";
00668         s << "\"" << libport::escape(t.first) << "\"=>";
00669         t.second.print(s);
00670         isFirst = false;
00671       }
00672     }
00673     return s << "]";
00674   }
00675 
00676 
00677 
00678 
00679   std::string
00680   syncline_push(const std::string& srcdir, std::string file, unsigned line)
00681   {
00682     if (boost::algorithm::starts_with(file, srcdir + "/"))
00683       boost::algorithm::erase_head(file, srcdir.size() + 1);
00684     return libport::format("//#push %d \"%s\"\n", line, file);
00685   }
00686 
00687 } // namespace urbi