Urbi SDK Remote for C++  2.7.3
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("unexpected `%s', expected `%s'",       \
00133                 message[pos], Char);                    \
00134       return -pos;                                      \
00135     }                                                   \
00136   } while(0)
00137 
00138 // Works on message[p] (not pos).
00139 #define CHECK_NEOF()                                            \
00140   do {                                                          \
00141     if (!message[p])                                            \
00142     {                                                           \
00143       GD_ERROR("unexpected end of file");                       \
00144       return -p;                                                \
00145     }                                                           \
00146   } while (0)
00147 
00148   int
00149   UValue::parse(const char* message, int pos,
00150                 const binaries_type& bins,
00151                 binaries_type::const_iterator& binpos)
00152   {
00153     SKIP_SPACES();
00154     if (message[pos] == '"')
00155     {
00156       //string
00157       type = DATA_STRING;
00158       //get terminating '"'
00159       int p = pos + 1;
00160       while (message[p] && message[p] != '"')
00161         p += 1 + (message[p] == '\\');
00162       CHECK_NEOF();
00163 
00164       stringValue = new std::string(
00165         libport::unescape(std::string(message + pos + 1, p - pos - 1)));
00166       return p + 1;
00167     }
00168 
00169     if (message[pos] == '[')
00170     {
00171       // List or Dictionary message.
00172       ++pos;
00173       bool hasElt = 0;
00174       while (message[pos])
00175       {
00176         SKIP_SPACES();
00177         if (!hasElt && !::strncmp(message + pos, "=>", 2))
00178         {
00179           // Detect empty dictionaries.
00180           type = DATA_DICTIONARY;
00181           dictionary = new UDictionary();
00182           pos += 2;
00183           SKIP_SPACES();
00184           continue;
00185         }
00186         if (message[pos] == ']')
00187         {
00188           // End of an empty list / dictionary (created above).
00189           if (type == DATA_VOID)
00190           {
00191             // End of an empty list, create it.
00192             type = DATA_LIST;
00193             list = new UList();
00194           }
00195           break;
00196         }
00197         UValue* v = new UValue();
00198         pos = v->parse(message, pos, bins, binpos);
00199         if (pos < 0)
00200         {
00201           delete v;
00202           return pos;
00203         }
00204         SKIP_SPACES();
00205         // Here is a dictionary key.
00206         if ((type == DATA_DICTIONARY || type == DATA_VOID)
00207             && !::strncmp(message + pos, "=>", 2) && v->type == DATA_STRING)
00208         {
00209           if (type == DATA_VOID)
00210           {
00211             type = DATA_DICTIONARY;
00212             dictionary = new UDictionary();
00213           }
00214 
00215           pos += 2;
00216           SKIP_SPACES();
00217           // Handle value associated with given key.
00218           std::string key = *(v->stringValue);
00219           (*dictionary)[key] = UValue();
00220           pos = (*dictionary)[key].parse(message, pos, bins, binpos);
00221           if (pos < 0)
00222           {
00223             delete v;
00224             return pos;
00225           }
00226         }
00227         else
00228         {
00229           if (type == DATA_VOID)
00230           {
00231             type = DATA_LIST;
00232             list = new UList();
00233           }
00234           list->array.push_back(v);
00235         }
00236         SKIP_SPACES();
00237         // Expect "," or "]".
00238         if (message[pos] == ']')
00239           break;
00240         EXPECT(',');
00241         hasElt = true;
00242         ++pos;
00243       }
00244 
00245       EXPECT(']');
00246       return pos + 1;
00247     }
00248 
00249     if (strprefix("void", message+pos))
00250     {
00251       //void
00252       type = DATA_VOID;
00253       pos += 4;
00254       return pos;
00255     }
00256     if (strprefix("nil", message+pos))
00257     {
00258       //void
00259       type = DATA_VOID;
00260       pos += 3;
00261       return pos;
00262     }
00263     if (strprefix("BIN ", message + pos))
00264     {
00265       //binary message: delegate
00266       type = DATA_BINARY;
00267       binary = new UBinary();
00268       pos += 4;
00269       //parsing type
00270       return binary->parse(message, pos, bins, binpos);
00271     }
00272 
00273     // true and false used by k2
00274     if (strprefix("true", message + pos))
00275     {
00276       type = DATA_DOUBLE;
00277       val = 1;
00278       return pos+4;
00279     }
00280 
00281     if (strprefix("false", message + pos))
00282     {
00283       type = DATA_DOUBLE;
00284       val = 0;
00285       return pos+5;
00286     }
00287 
00288     // Last attempt: it should be a double.
00289     {
00290       int p;
00291       double dval; // in case ufloat is not double
00292       if (sscanf(message+pos, "%lf%n", &dval, &p))
00293       {
00294         type = DATA_DOUBLE;
00295         pos += p;
00296         val = dval;
00297         return pos;
00298       }
00299     }
00300 
00301     // Anything else is an error, but be resilient and ignore it.
00302     GD_FWARN("syntax error (ignored): \"%s\"", libport::escape(message + pos));
00303     return -pos;
00304   }
00305 
00306   std::ostream&
00307   UValue::print(std::ostream& s) const
00308   {
00309     switch (type)
00310     {
00311       case DATA_DOUBLE:
00312         s << std::setprecision(21) << val;
00313         break;
00314       case DATA_STRING:
00315         s << '"' << libport::escape(*stringValue, '"') << '"';
00316         break;
00317       case DATA_SLOTNAME:
00318         s << *stringValue;
00319         break;
00320       case DATA_BINARY:
00321         s << *binary;
00322         break;
00323       case DATA_LIST:
00324         s << *list;
00325         break;
00326       case DATA_DICTIONARY:
00327         s << *dictionary;
00328         break;
00329       case DATA_VOID:
00330         s << "nil";
00331         break;
00332     }
00333     return s;
00334   }
00335 
00336 
00337 
00338   /*---------.
00339   | UValue.  |
00340   `---------*/
00341 
00343   UValue::UValue()
00344     : type(DATA_VOID), val (0), storage(0)
00345   {}
00346 
00347   // All the following mess could be avoid if we used templates...
00348   // boost::any could be very useful here.  Some day, hopefully...
00349 
00350 #define UVALUE_OPERATORS(Args, DataType, Field, Value)  \
00351   UValue::UValue(Args, bool copy)                       \
00352     : type(DataType)                                    \
00353     , Field(Value)                                      \
00354   {                                                     \
00355     LIBPORT_USE(copy);                                  \
00356   }                                                     \
00357                                                         \
00358   UValue& UValue::operator=(Args)                       \
00359   {                                                     \
00360     clear();                                            \
00361     type = DataType;                                    \
00362     Field = Value;                                      \
00363     return *this;                                       \
00364   }
00365 
00366 #define UVALUE_DOUBLE(Type)                     \
00367   UVALUE_OPERATORS(Type v, DATA_DOUBLE, val, v)
00368 
00369   UVALUE_DOUBLE(ufloat)
00370   UVALUE_DOUBLE(int)
00371   UVALUE_DOUBLE(unsigned int)
00372   UVALUE_DOUBLE(long)
00373   UVALUE_DOUBLE(unsigned long)
00374   UVALUE_DOUBLE(long long)
00375   UVALUE_DOUBLE(unsigned long long)
00376 
00377 #undef UVALUE_DOUBLE
00378 
00379 
00380   /*----------------------.
00381   | UValue: DATA_STRING.  |
00382   `----------------------*/
00383 
00384 #define UVALUE_STRING(Type, Value)                                      \
00385   UVALUE_OPERATORS(Type v, DATA_STRING, stringValue, new std::string(Value))
00386 
00387   UVALUE_STRING(const char*,        v)
00388   UVALUE_STRING(const std::string&, v)
00389   UVALUE_STRING(const void*,        (libport::format("%%ptr_%x", v)))
00390 
00391 #undef UVALUE_STRING
00392 
00393   /*----------------------.
00394   | UValue: DATA_BINARY.  |
00395   `----------------------*/
00396 
00397 #define UVALUE_BINARY(Type)                     \
00398   UVALUE_OPERATORS(Type v, DATA_BINARY, binary, new UBinary(v, copy))
00399 
00400   UVALUE_BINARY(const UBinary&)
00401   UVALUE_BINARY(const USound&)
00402   UVALUE_BINARY(const UImage&)
00403 
00404 #undef UVALUE_BINARY
00405 
00406   UVALUE_OPERATORS(const UList& v, DATA_LIST, list, new UList(v))
00407   UVALUE_OPERATORS(const UDictionary& d,
00408                    DATA_DICTIONARY, dictionary, new UDictionary(d));
00409 
00410 #undef UVALUE_OPERATORS
00411 
00412   void
00413   UValue::clear()
00414   {
00415     switch(type)
00416     {
00417       case DATA_STRING:
00418       case DATA_SLOTNAME:
00419         delete stringValue;
00420         break;
00421       case DATA_BINARY:
00422         delete binary;
00423         break;
00424       case DATA_LIST:
00425         delete list;
00426         break;
00427       case DATA_DICTIONARY:
00428         delete dictionary;
00429         break;
00430       case DATA_DOUBLE:
00431       case DATA_VOID:
00432         break;
00433     }
00434     type = DATA_VOID;
00435   }
00436 
00437   UValue::~UValue()
00438   {
00439     clear();
00440   }
00441 
00442   UValue::operator ufloat() const
00443   {
00444     switch (type)
00445     {
00446       case DATA_DOUBLE:
00447         return val;
00448       case DATA_STRING:
00449         return lexical_cast<ufloat>(*stringValue);
00450       case DATA_BINARY:
00451       case DATA_LIST:
00452       case DATA_DICTIONARY:
00453       case DATA_VOID:
00454       case DATA_SLOTNAME:
00455         break;
00456     }
00457     return ufloat(0);
00458   }
00459 
00460 
00461   UValue::operator std::string() const
00462   {
00463     switch (type)
00464     {
00465       case DATA_DOUBLE:
00466         return string_cast(val);
00467       case DATA_STRING:
00468       case DATA_SLOTNAME:
00469         return *stringValue;
00470       // We cannot convert to UBinary because it is ambigous so we
00471       // try until we found the right type.
00472       case DATA_BINARY:
00473       {
00474         USound snd(*this);
00475         if (snd.soundFormat != SOUND_UNKNOWN)
00476           return string_cast(snd);
00477         break;
00478       }
00479       default:
00480         break;
00481     }
00482     return "invalid";
00483   }
00484 
00485   UValue::operator const UBinary&() const
00486   {
00487     static UBinary dummy;
00488     if (type != DATA_BINARY)
00489       return dummy;
00490     else
00491       return *binary;
00492   }
00493 
00494   UValue::operator UImage() const
00495   {
00496     if (type == DATA_BINARY && binary->type == BINARY_IMAGE)
00497       return binary->image;
00498     return UImage::make();
00499   }
00500 
00501   UValue::operator USound() const
00502   {
00503     if (type == DATA_BINARY && binary->type == BINARY_SOUND)
00504       return binary->sound;
00505     return USound::make();
00506   }
00507 
00508   UValue::operator UList() const
00509   {
00510     if (type == DATA_LIST)
00511       return UList(*list);
00512     return UList();
00513   }
00514 
00515   UValue::operator UDictionary() const
00516   {
00517     if (type == DATA_DICTIONARY)
00518       return UDictionary(*dictionary);
00519     return UDictionary();
00520   }
00521 
00522   UValue& UValue::operator= (const UValue& v)
00523   {
00524     return set(v);
00525   }
00526 
00527   UValue& UValue::set(const UValue& v, bool copy)
00528   {
00529     // TODO: optimize
00530     if (this == &v)
00531       return *this;
00532     bool sameType = type == v.type;
00533     if (!sameType)
00534       clear();
00535 
00536     switch (v.type)
00537     {
00538       case DATA_DOUBLE:
00539         val = v.val;
00540         break;
00541       case DATA_STRING:
00542       case DATA_SLOTNAME:
00543         if (sameType)
00544           *stringValue = *v.stringValue;
00545         else
00546           stringValue = new std::string(*v.stringValue);
00547         break;
00548       case DATA_BINARY:
00549         if (sameType)
00550           delete binary;
00551         binary = new UBinary(*v.binary, copy);
00552         break;
00553       case DATA_LIST:
00554         if (sameType)
00555         {
00556           list->offset = v.list->offset;
00557           unsigned int mins
00558             = std::min(v.list->array.size(), list->array.size());
00559           // Reuse existing uvalues
00560           for (unsigned int i = 0; i<mins; ++i)
00561             list->array[i]->set(*v.list->array[i]);
00562           // Destroy extra ones
00563           for(unsigned int k= 0; k<list->array.size() - mins; ++k)
00564           {
00565             delete list->array.back();
00566             list->array.pop_back();
00567           }
00568           // Or push new ones
00569           for (unsigned int j = mins; j< v.list->array.size(); ++j)
00570             list->array.push_back(new UValue(v.list->array[j]));
00571         }
00572         else
00573           list = new UList(*v.list);
00574         break;
00575       case DATA_DICTIONARY:
00576         if (sameType)
00577         {
00578           dictionary->clear();
00579           dictionary->insert(v.dictionary->begin(), v.dictionary->end());
00580         }
00581         else
00582           dictionary = new UDictionary(*v.dictionary);
00583         break;
00584       case DATA_VOID:
00585         storage = v.storage;
00586         break;
00587     }
00588     type = v.type;
00589     return *this;
00590   }
00591 
00592 
00593   UValue::UValue(const UValue& v)
00594     : type(DATA_VOID)
00595   {
00596     *this = v;
00597   }
00598   /*--------.
00599   | UList.  |
00600   `--------*/
00601 
00602   UList::UList()
00603     : offset(0)
00604   {}
00605 
00606   UList::UList(const UList& b)
00607     : offset(0)
00608   {
00609     *this = b;
00610   }
00611 
00612   UList& UList::operator= (const UList& b)
00613   {
00614     if (this == &b)
00615       return *this;
00616     clear();
00617     foreach (UValue* v, b.array)
00618       array.push_back(new UValue(*v));
00619     offset = b.offset;
00620     return *this;
00621   }
00622 
00623   UList::~UList()
00624   {
00625     clear();
00626   }
00627 
00628   void UList::clear()
00629   {
00630     offset = 0;
00631     foreach (UValue *v, array)
00632       delete v;
00633     array.clear();
00634   }
00635 
00636   std::ostream&
00637   UList::print(std::ostream& o) const
00638   {
00639     o << '[';
00640     size_t sz = size();
00641     for (unsigned i = 0; i < sz; ++i)
00642       o << (*this)[i]
00643         << (i != sz - 1 ? ", " : "");
00644     o << ']';
00645     return o;
00646   }
00647 
00648   std::ostream&
00649   operator<< (std::ostream& o, const UList& t)
00650   {
00651     return t.print(o);
00652   }
00653 
00654   std::ostream&
00655   operator<<(std::ostream& s, const urbi::UDictionary& d)
00656   {
00657     s << "[";
00658     if (d.empty())
00659       s << "=>";
00660     else
00661     {
00662       bool isFirst = true;
00663       foreach (const UDictionary::value_type& t, d)
00664       {
00665         if (!isFirst)
00666           s << ",";
00667         s << "\"" << libport::escape(t.first) << "\"=>";
00668         t.second.print(s);
00669         isFirst = false;
00670       }
00671     }
00672     return s << "]";
00673   }
00674 
00675 
00676 
00677 
00678   std::string
00679   syncline_push(const std::string& srcdir, std::string file, unsigned line)
00680   {
00681     if (boost::algorithm::starts_with(file, srcdir + "/"))
00682       boost::algorithm::erase_head(file, srcdir.size() + 1);
00683     return libport::format("//#push %d \"%s\"\n", line, file);
00684   }
00685 
00686 } // namespace urbi