Changeset 10270


Ignore:
Timestamp:
Mar 30, 2011, 3:41:11 PM (10 years ago)
Author:
tbretz
Message:
Change the interface. Now it first compiles the format string into a binary representation and any conversion can then be done later based on this.
Location:
trunk/FACT++/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/Converter.cc

    r10219 r10270  
    22/** @class Converter
    33
    4 @brief An interpreter to convert a command line into a command plus data memory
     4@brief A compiler for the DIM data format string
    55
    66The Converter class interprets arguments in a string accoring to the
     
    2121
    2222\code
    23   Converter c(cout, "I:1;F:2;I:2", "COMMAND 1 2.5 4.2 3 4");
     23   Converter c(cout, "I:1;F:2;I:2", );
     24   vector<char> v = c.GetVector("COMMAND 1 2.5 4.2 3 4");
    2425\endcode
    2526
     
    3031
    3132\code
    32    Converter c(cout, "I:1;F:2;I:2", pointer, size);
     33   Converter c(cout, "I:1;F:2;I:2");
     34   cout << c.GetString(pointer, size) << endl;
    3335 \endcode
    3436
     37Other conversion functions also exist.
     38
     39A result of a conversion is valid if valid() returns true and either the
     40result of the conversion is empty and the format string was valid empty
     41or both contain contents.
     42
     43The format parameter \b W(ord) is dedicated to this kind of conversion and
     44not understood by Dim. In addition there are \b O(ptions) which are like
     45Words but can be omitted. They should only be used at the end of the string.
     46\b B(ool) is also special. It evaluates true/false, yes/no, on/off, 1/0.
     47
     48The non-DIM like format options can be switched on and off by using the
     49strict argument in the constructor.
     50
     51*/
     52// **************************************************************************
     53#include "Converter.h"
     54
     55#include <iostream>
     56#include <iomanip>
     57#include <sstream>
     58
     59#include <cctype>    // std::tolower
     60#include <algorithm> // std::transform
     61
     62#include <boost/regex.hpp>
     63
     64#include "Readline.h"
     65#include "WindowLog.h"
     66
     67using namespace std;
     68/*
    3569In addition to converting the options from a string into binary format
    3670or back all found values are also put into a vector of boost::any objects.
     
    4680   cout << c.Get<string>(4) << endl;  // prints 'is a test'
    4781\endcode
    48 
    49 The format parameter \b W(ord) is dedicated to this kind of conversion and
    50 not understood by Dim. In addition there are \b O(ptions) which are like
    51 Words but can be omitted. They should only be used at the end of the string.
    52 \b B(ool) is also special. It evaluates true/false, yes/no, on/off, 1/0.
    53 
    54 Access with Converter::Get() is exception safe. Access with Converter::At()
    55 would throw an exception if the index is out of bounds or the conversion
    56 fails. (This is the prefered method if the type is well known, to easily
    57 detect programing faults)
    58 
    59 @remark
    60     Most probably we support more formats than dim does...
    61 
    6282*/
    63 // **************************************************************************
    64 #include "Converter.h"
    65 
    66 #include <iomanip>
    67 #include <sstream>
    68 
    69 #include <cctype>    // std::tolower
    70 #include <algorithm> // std::transform
    71 
    72 #include <boost/regex.hpp>
    73 
    74 #include "Readline.h"
    75 #include "WindowLog.h"
    76 
    77 using namespace std;
    78 
     83
     84// --------------------------------------------------------------------------
     85//
     86//! This function is supposed to remove all whitespaces from the format
     87//! string to allow easier regular expressions later.
     88//!
     89//! @param s
     90//!     string to be cleaned
     91//!
     92//! @returns
     93//!     string cleaned from whitespaces
     94//
     95std::string Converter::Clean(std::string s)
     96{
     97    while (1)
     98    {
     99        const size_t pos = s.find_last_of(' ');
     100        if (pos==string::npos)
     101            break;
     102        s.erase(pos, pos+1);
     103    }
     104
     105    return s;
     106}
     107
     108// --------------------------------------------------------------------------
     109//
     110//! This is just a simplification. For the time being it is used to output
     111//! the interpreted contents to the logging stream. Its main purpose
     112//! is to add the contents of val in a binary representation to the
     113//! vector v
     114//!
     115//! @tparam
     116//!     data type of the variable which should be added
     117//!
     118//! @param val
     119//!     reference to the data
     120//!
     121//! @param v
     122//!     vector<char> to which the binary copy should be added
     123//!
    79124template <class T>
    80     void Converter::EvalImp(int i, std::stringstream &line, std::vector<char> &v, const T &val)
    81 {
    82     if (!line)
    83         wout << " arg[" << i << "]";
    84     else
    85         wout << " (" << val << ")";
    86 
    87     vec.push_back(val);
     125void Converter::GetBinImp(std::vector<char> &v, const T &val) const
     126{
     127    wout << " (" << val << ")";
    88128
    89129    v.insert(v.end(),
     
    92132}
    93133
    94 
    95 // --------------------------------------------------------------------------
    96 //
    97 //! Gets a value of the template type T from the stringstream and adds the
    98 //! value as binary data to the end of the vector. If a value couldn't be
    99 //! obtained it is set to 0.
    100 //!
    101 //! Adds the value to Converter::vec.
    102 //!
    103 //! @param i
    104 //!     The number of the processed argument (currently used for some debug
    105 //!     output when an argument is not available and artificially set to 0)
     134// --------------------------------------------------------------------------
     135//
     136//! This is just a simplification. For the time being it is used to output
     137//! the interpreted contents to the logging stream. Its main purpose
     138//! is to add the contents of val as a boost::any object to the
     139//! vector v
     140//!
     141//! @tparam
     142//!     data type of the variable which should be added
     143//!
     144//! @param val
     145//!     reference to the data
     146//!
     147//! @param v
     148//!     vector<boost::any> to which the value should be added
     149//!
     150template <class T>
     151void Converter::GetBinImp(std::vector<boost::any> &v, const T &val) const
     152{
     153    wout << " (" << val << ")";
     154
     155    v.push_back(val);
     156}
     157
     158// --------------------------------------------------------------------------
     159//
     160//! This is just a simplification. For the time being it is used to output
     161//! the interpreted contents to the logging stream. Its main purpose
     162//! is to add the contents of the provided string at the end of the vector v.
     163//! vector v
     164//!
     165//! @param val
     166//!     reference to the string
     167//!
     168//! @param v
     169//!     vector<char> to which the value should be added
     170//!
     171void Converter::GetBinString(std::vector<char> &v, const string &val) const
     172{
     173    wout << " (" << val << ")";
     174
     175    v.insert(v.end(), val.begin(), val.end());
     176}
     177
     178// --------------------------------------------------------------------------
     179//
     180//! This is just a simplification. For the time being it is used to output
     181//! the interpreted contents to the logging stream. Its main purpose
     182//! is to add the contents of the provided string at the end of the vector v.
     183//! vector v
     184//!
     185//! @param val
     186//!     reference to the string
     187//!
     188//! @param v
     189//!     vector<boost::any> to which the value should be added
     190//!
     191void Converter::GetBinString(std::vector<boost::any> &v, const string &val) const
     192{
     193    wout << " (" << val << ")";
     194
     195    v.push_back(val);
     196}
     197
     198// --------------------------------------------------------------------------
     199//
     200//! Converts from the stringstream into the provided type.
    106201//!
    107202//! @param line
    108 //!     The stringstream from which the data should be read
    109 //!
    110 //! @param vec
    111 //!     The vector of bytes at which end the data is added in binary format
     203//!     reference to the stringstream from which the data should be
     204//!     interpreted
     205//!
     206//! @tparam
     207//!     Type of the data to be returned
     208//!
     209//! @returns
     210//!     The interpreted data
    112211//!
    113212template <class T>
    114     void Converter::Eval(int i, std::stringstream &line, std::vector<char> &v)
     213T Converter::Get(std::stringstream &line) const
    115214{
    116215    T val;
    117216    line >> val;
    118 
    119     EvalImp(i, line, v, val);
    120 }
    121 
    122 // --------------------------------------------------------------------------
    123 //
    124 //! This functions works similar the the template Eval but is dedicated to
    125 //! bools. It evaluates yes/no, on/off, true/false and 1/0.
    126 //!
    127 //! Sets the failbit of the stream if the "value" is not known.
    128 //!
    129 //! Adds the value to Converter::vec.
     217    return val;
     218}
     219
     220// --------------------------------------------------------------------------
     221//
     222//! Converts from the stringstream into bool. It allows to use lexical
     223//! boolean representations like yes/no, on/off, true/false and of
     224//! course 0/1. If the conversion fails the failbit is set.
    130225//!
    131226//! @param line
    132 //!     The stringstream from which the data should be read
    133 //!
    134 //! @param vec
    135 //!     The vector of bytes at which end the data is added in binary format
     227//!     reference to the stringstream from which the data should be
     228//!     interpreted
    136229//!
    137230//! @returns
    138 //!     The bool evaluated
    139 //!
    140 void Converter::EvalBool(int i, std::stringstream &line, std::vector<char> &v)
     231//!     The boolean. 0 in case of failure
     232//!
     233bool Converter::GetBool(std::stringstream &line) const
    141234{
    142235    string buf;
     
    145238
    146239    if (buf=="yes" || buf=="true" || buf=="on" || buf=="1")
    147     {
    148         EvalImp(i, line, v, bool(true));
    149         return;
    150     }
     240        return true;
    151241
    152242    if (buf=="no" || buf=="false" || buf=="off" || buf=="0")
    153     {
    154         EvalImp(i, line, v, bool(false));
    155         return;
    156     }
     243        return false;
    157244
    158245    line.clear(ios::failbit);
    159 }
    160 
    161 void Converter::EvalString(int i, std::stringstream &line, std::vector<char> &v)
     246
     247    return false;
     248}
     249
     250// --------------------------------------------------------------------------
     251//
     252//! Converts from the stringstream into a string. Leading whitespaces are
     253//! skipped. Everything up to the next whitespace is returned.
     254//! strings can be encapsulated into escape characters ("). Note, that
     255//! they cannot be nested.
     256//!
     257//! @param line
     258//!     reference to the stringstream from which the data should be
     259//!     interpreted
     260//!
     261//! @returns
     262//!     The string
     263//!
     264string Converter::GetString(std::stringstream &line) const
    162265{
    163266    while (line.peek()==' ')
     
    173276        line >> buf;
    174277
    175     EvalImp(i, line, v, buf);
    176 }
    177 
    178 // --------------------------------------------------------------------------
    179 //
    180 //! Constructs a data block from the given string according to the given
    181 //! format. (See also the class reference for more details).
    182 //!
    183 //! The data block is stored in a vector<char>. It's content can be
    184 //! retrieved using the member functions Ptr() and Size(). Whether parsing
    185 //! was successfull or not can be checked with GetRc().
    186 //! If parsing was not successfull, either the format contained something
    187 //! odd, the conversion failed (e.g. 5.5 for an int) or the string contained
    188 //! a wrong number of arguments.
     278    return buf;
     279}
     280
     281// --------------------------------------------------------------------------
     282//
     283//! Converts from the stringstream into a string. Leading whitespaces are
     284//! skipped. Everything until the end-of-line is returned. A trailing
     285//! \0 is added.
     286//!
     287//! @param line
     288//!     reference to the stringstream from which the data should be
     289//!     interpreted
     290//!
     291//! @returns
     292//!     The string
     293//!
     294string Converter::GetStringEol(stringstream &line) const
     295{
     296    // Remove leading whitespaces
     297    while (line.peek()==' ')
     298        line.get();
     299
     300    line >> noskipws;
     301
     302    const istream_iterator<char> eol; // end-of-line iterator
     303    const string s(istream_iterator<char>(line), eol);
     304    return s + '\0';
     305}
     306
     307// --------------------------------------------------------------------------
     308//
     309//! Converts from a binary block into a string. The type of the expected
     310//! value is defined by the template parameter.
     311//!
     312//! @param ptr
     313//!     A refrenece to the pointer of the binary representation to be
     314//!     interpreted. The pointer is incremented by the sizeof the type.
     315//!
     316//! @tparam T
     317//!     Expected type
     318//!
     319//! @returns
     320//!     The string
     321//!
     322template<class T>
     323string Converter::GetString(const char* &ptr) const
     324{
     325    const T &t = *reinterpret_cast<const T*>(ptr);
     326
     327    ostringstream stream;
     328    stream << t;
     329    ptr += sizeof(T);
     330
     331    return stream.str();
     332}
     333
     334// --------------------------------------------------------------------------
     335//
     336//! Converts from a binary block into a hex representation.
     337//!
     338//! @param ptr
     339//!     Pointer to the data block
     340//!
     341//! @param size
     342//!     Size of the data block
     343//!
     344//! @returns
     345//!     The string
     346//!
     347string Converter::GetHex(const void *dat, int size)
     348{
     349    const char *ptr = reinterpret_cast<const char *>(dat);
     350
     351    ostringstream text;
     352
     353    text << hex;
     354
     355    for (int i=0; i<size; i++)
     356        text << setw(2) << ptr[i] << " ";
     357
     358    return text.str();
     359}
     360
     361// --------------------------------------------------------------------------
     362//
     363//! Convert the pointer using GetString into a string and add it (prefixed
     364//! by a whaitespace) to the given string.
     365//!
     366//! @param str
     367//!     Reference to the string to which the ptr should be added
     368//!
     369//! @param ptr
     370//!     Pointer to the binary representation. It will be incremented
     371//!     according to the sze of the template argument
     372//!
     373//! @tparam T
     374//!     Type as which the binary data should be interpreted
     375//!
     376template<class T>
     377void Converter::Add(string &str, const char* &ptr) const
     378{
     379    str += ' ' + GetString<T>(ptr);
     380}
     381
     382// --------------------------------------------------------------------------
     383//
     384//! Convert the pointer into a boost::any object and add it to the
     385//! provided vector
     386//!
     387//! @param vec
     388//!     Vector to which the boost::any object should be added
     389//!
     390//! @param ptr
     391//!     Pointer to the binary representation. It will be incremented
     392//!     according to the sze of the template argument
     393//!
     394//! @tparam T
     395//!     Type as which the binary data should be interpreted
     396//!
     397template<class T>
     398void Converter::Add(vector<boost::any> &vec, const char* &ptr) const
     399{
     400    vec.push_back(*reinterpret_cast<const T*>(ptr));
     401    ptr += sizeof(T);
     402}
     403
     404// --------------------------------------------------------------------------
     405//
     406//! Add the string pointed to by ptr to the given string.
     407//!
     408//! @param str
     409//!     Reference to the string to which the ptr should be added
     410//!
     411//! @param ptr
     412//!     Pointer to the binary representation.
     413//!
     414void Converter::AddString(string &str, const string &ptr) const
     415{
     416    str += ' ' + ptr;
     417}
     418
     419// --------------------------------------------------------------------------
     420//
     421//! Add the string pointed to by ptr as boost::any to the provided vector
     422//!
     423//! @param vec
     424//!     Vector to which the boost::any object should be added
     425//!
     426//! @param ptr
     427//!     Pointer to the binary representation of the string.
     428//!
     429void Converter::AddString(vector<boost::any> &vec, const string &ptr) const
     430{
     431    vec.push_back(ptr);
     432}
     433
     434// --------------------------------------------------------------------------
     435//
     436//! Compiles the format string into fList. See Compile() for more details.
    189437//!
    190438//! @param out
    191 //!    The ostream to which errors and debug messages should be printed.
     439//!     Output stream to which possible logging is redirected
    192440//!
    193441//! @param fmt
    194 //!    The format descriptor according to the dim definition
    195 //!
    196 //! @param str
    197 //!    The string which should be interpreted, e.g. "1 2 5.5 abcdef"
    198 //!
    199 Converter::Converter(std::ostream &out, const std::string &fmt, const std::string &str)
    200 : rc(false), wout(out)
    201 {
     442//!     Format to be compiled. For details see class reference
     443//!
     444//! @param strict
     445//!     Setting this to true allows non DIM options, whiel false
     446//!     will restrict the possible format strings to the ones also
     447//!     understood by DIM.
     448//!
     449Converter::Converter(std::ostream &out, const std::string &fmt, bool strict)
     450: wout(out), fFormat(Clean(fmt)), fList(Compile(out, fmt, strict))
     451{
     452}
     453
     454// --------------------------------------------------------------------------
     455//
     456//! Compiles the format string into fList.
     457//!
     458//! Output by default is redirected to cout.
     459//!
     460//! @param fmt
     461//!     Format to be compiled. For details see class reference
     462//!
     463//! @param strict
     464//!     Setting this to true allows non DIM options, whiel false
     465//!     will restrict the possible format strings to the ones also
     466//!     understood by DIM.
     467//!
     468Converter::Converter(const std::string &fmt, bool strict)
     469: wout(cout), fFormat(Clean(fmt)), fList(Compile(fmt, strict))
     470{
     471}
     472
     473// --------------------------------------------------------------------------
     474//
     475//! Converts the provided format string into a vector.
     476//!
     477//! @tparam T
     478//!     Kind of data to be returned. This can either be boost::any objects
     479//!     or a bnary data-block (char).
     480//!
     481//! @param fmt
     482//!     Format to be compiled. For details see class reference
     483//!
     484//! @returns
     485//!    A vector of the given template type containing the arguments. In
     486//!    case of failure an empty vector is returned.
     487//!
     488template <class T>
     489vector<T> Converter::Get(const std::string &str) const
     490{
     491    if (!valid())
     492        return vector<T>();
     493
    202494    // If the format is empty we are already done
    203     if (fmt.empty())
    204     {
    205         if (!str.empty())
     495    if (empty())
     496    {
     497        if (str.empty())
    206498        {
    207499            wout << endl;
    208             wout << kRed << "Data string not empty as it ought to be!" << endl;
    209             return;
     500            return vector<T>();
    210501        }
    211502
    212503        wout << endl;
    213         rc = true;
    214         return;
    215     }
     504        wout << kRed << "Data string not empty as it ought to be!" << endl;
     505        return vector<T>();
     506    }
     507
     508    int arg = 0;
     509    stringstream line(str);
     510
     511    vector<T> data;
     512
     513    for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end(); i++)
     514    {
     515        if (*i->first.first == typeid(string))
     516        {
     517            GetBinString(data, GetStringEol(line));
     518            line.clear(ios::eofbit);
     519            continue;
     520        }
     521
     522        // Get as many items from the input line as requested
     523        for (int j=0; j<i->second.first; j++)
     524        {
     525            cout << j << ": " << i->first.first->name() << endl;
     526            switch (i->first.first->name()[0])
     527            {
     528            case 'c': // Skip whitespaces when checking for characters
     529                if (j>0)
     530                    line >> noskipws;
     531                GetBinImp(data, Get<char>(line));
     532                line >> skipws;
     533                break;
     534            case 'b': GetBinImp(data, GetBool(line)); break;
     535            case 's': GetBinImp(data, Get<short>    (line)); break;
     536            case 'i': GetBinImp(data, Get<int>      (line)); break;
     537            case 'l': GetBinImp(data, Get<long>     (line)); break;
     538            case 'f': GetBinImp(data, Get<float>    (line)); break;
     539            case 'd': GetBinImp(data, Get<double>   (line)); break;
     540            case 'x': GetBinImp(data, Get<long long>(line)); break;
     541            case 'N':
     542                GetBinString(data, GetString(line));
     543                if (*i->first.first == typeid(O))
     544                    line.clear(ios::goodbit);
     545                break;
     546            default:
     547                // This should never happen!
     548                wout << endl << kRed << "Format '" << i->first.first->name() << " not supported!" << endl;
     549                break;
     550            }
     551
     552            arg++;
     553        }
     554
     555        //wout << "{" << line.eof() << line.good() << line.fail() << "}";
     556        if (!line)
     557            break;
     558    }
     559
     560    wout << endl;
     561
     562    // Something wrong with the conversion (e.g. 5.5 for an int)
     563    if (line.fail() && !line.eof())
     564    {
     565        line.clear(); // This is necesasary to get a proper response from tellg()
     566        wout << kRed << "Error converting argument at " << arg << " [fmt=" << fFormat << "]!" << endl;
     567        wout << kRed << line.str() << endl;
     568        wout << kRed << setw(int(line.tellg())) << " " << "^" << endl;
     569        return vector<T>();
     570    }
     571
     572    // Not enough arguments, we have not reached the end
     573    if (line.fail() && line.eof())
     574    {
     575        line.clear();
     576        wout << kRed << "Not enough arguments [fmt=" << fFormat << "]!" << endl;
     577        wout << kRed << line.str() << endl;
     578        wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl;
     579        return vector<T>();
     580    }
     581
     582    // Too many arguments, we have not reached the end
     583    // Unfortunately, this can also mean that there is something
     584    // wrong with the last argument
     585    if (line.good() && !line.eof())
     586    {
     587        wout << kRed << "More arguments available than expected [" << fFormat << "]!" << endl;
     588        wout << kRed << line.str() << endl;
     589        wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl;
     590        return vector<T>();
     591    }
     592
     593    return data;
     594
     595}
     596
     597std::vector<boost::any> Converter::GetAny(const std::string &str) const
     598{
     599    return Get<boost::any>(str);
     600}
     601
     602std::vector<char> Converter::GetVector(const std::string &str) const
     603{
     604    return Get<char>(str);
     605}
     606
     607
     608// --------------------------------------------------------------------------
     609//
     610//! Converts the provided data block into a vector of boost::any or
     611//! a string.
     612//!
     613//! @tparam T
     614//!     Kind of data to be returned. This can either be boost::any objects
     615//!     or a string
     616//!
     617//! @returns
     618//!    A vector of the given template type containing the arguments. In
     619//!    case of failure an empty vector is returned.
     620//!
     621template<class T>
     622T Converter::Get(const void *dat, int size) const
     623{
     624    if (!valid())
     625        return T();
     626
     627    const char *ptr = reinterpret_cast<const char *>(dat);
     628
     629    T text;
     630    for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end(); i++)
     631    {
     632        if (ptr-size>=dat)
     633        {
     634            wout << kRed << "Format description '" << fFormat << "' exceeds available data size (" << size << ")" << endl;
     635            return T();
     636        }
     637
     638        if (*i->first.first == typeid(string))
     639        {
     640            const string str(ptr);
     641            AddString(text, str);
     642            ptr += str.length()+1;
     643            break;
     644        }
     645
     646        // Get as many items from the input line as requested
     647        for (int j=0; j<i->second.first; j++)
     648        {
     649            switch (i->first.first->name()[0])
     650            {
     651            case 'b': Add<bool>     (text, ptr); break;
     652            case 'c': Add<char>     (text, ptr); break;
     653            case 's': Add<short>    (text, ptr); break;
     654            case 'i': Add<int>      (text, ptr); break;
     655            case 'l': Add<long>     (text, ptr); break;
     656            case 'f': Add<float>    (text, ptr); break;
     657            case 'd': Add<double>   (text, ptr); break;
     658            case 'x': Add<long long>(text, ptr); break;
     659            case 'v':
     660                // This should never happen!
     661                wout << kRed << "Type 'void' not supported!" << endl;
     662                return T();
     663            default:
     664                // This should never happen!
     665                wout << kRed << "TypeId '" << i->first.first->name() << "' not known!" << endl;
     666                return T();
     667            }
     668        }
     669    }
     670
     671    if (ptr-size!=dat)
     672    {
     673        wout << kRed << "Data block size (" << size << ") doesn't fit format description '" << fFormat << "'" << endl;
     674        return T();
     675    }
     676
     677    return text;
     678}
     679
     680std::vector<boost::any> Converter::GetAny(const void *dat, int size) const
     681{
     682    return Get<vector<boost::any>>(dat, size);
     683}
     684
     685std::vector<char> Converter::GetVector(const void *dat, int size) const
     686{
     687    const string ref = GetString(dat, size);
     688
     689    vector<char> data;
     690    data.insert(data.begin(), ref.begin()+1, ref.end());
     691    data.push_back(0);
     692
     693    return data;
     694}
     695
     696string Converter::GetString(const void *dat, int size) const
     697{
     698    return Get<string>(dat, size).substr(1);
     699}
     700
     701template<class T>
     702Converter::Type Converter::GetType()
     703{
     704    Type t;
     705    t.first  = &typeid(T);
     706    t.second = sizeof(T);
     707    return t;
     708}
     709
     710template<class T>
     711Converter::Type Converter::GetVoid()
     712{
     713    Type t;
     714    t.first  = &typeid(T);
     715    t.second = 0;
     716    return t;
     717}
     718
     719// --------------------------------------------------------------------------
     720//
     721//! static function to compile a format string.
     722//!
     723//! @param out
     724//!     Output stream to which possible logging is redirected
     725//!
     726//! @param fmt
     727//!     Format to be compiled. For details see class reference
     728//!
     729//! @param strict
     730//!     Setting this to true allows non DIM options, whiel false
     731//!     will restrict the possible format strings to the ones also
     732//!     understood by DIM.
     733//!
     734Converter::FormatList Converter::Compile(std::ostream &out, const std::string &fmt, bool strict)
     735{
     736    ostringstream text;
    216737
    217738    // Access both, the data and the format through a stringstream
    218     stringstream line(str);
    219739    stringstream stream(fmt);
    220740
    221741    // For better performance we could use sregex
    222     static const boost::regex expr("^[ ]*([OBWCSILFDX])[ ]*(:[ ]*([1-9]+[0-9]*))?[ ]*$");
     742    static const boost::regex expr1("^([CSILFDXBOW])(:([1-9]+[0-9]*))?$");
     743    static const boost::regex expr2("^([CSILFDX])(:([1-9]+[0-9]*))?$");
     744
     745    FormatList list;
     746    Format   format;
    223747
    224748    // Tokenize the format
    225     int arg = 0;
    226749    string buffer;
    227750    while (getline(stream, buffer, ';'))
    228751    {
    229752        boost::smatch what;
    230         if (!boost::regex_match(buffer, what, expr))
     753        if (!boost::regex_match(buffer, what, strict?expr2:expr1))
    231754        {
    232             wout << endl;
    233             wout << kRed << "Wrong format string '" << buffer << "'!" << endl;
    234             return;
     755            out << kRed << "Wrong format string '" << buffer << "'!" << endl;
     756            return FormatList();
    235757        }
    236758
     
    238760        const string n = what[3]; // counter
    239761
    240         int cnt = atoi(n.c_str());
     762        const int cnt = atoi(n.c_str());
     763
     764        // if the :N part was not given assume 1
     765        format.second.first = cnt == 0 ? 1: cnt;
    241766
    242767        // Check if the format is just C (without a number)
     
    244769        if (t[0]=='C' && cnt==0)
    245770        {
    246             // Remove leading whitespaces
    247             while (line.peek()==' ')
    248                 line.get();
    249 
    250             line >> noskipws;
    251 
    252             const istream_iterator<char> eol; // end-of-line iteartor
    253             const string s(istream_iterator<char>(line), eol);
    254 
    255             vec.push_back(s);
    256 
    257             data.insert(data.end(), s.begin(), s.end());
    258             data.push_back(0);
    259 
    260             line.clear(ios::eofbit);
    261 
    262             continue;
    263         }
    264 
    265         // if the :N part was not given assume 1
    266         if (cnt==0)
    267             cnt=1;
    268 
    269         // Get as many items from the input line as requested
    270         for (int j=0; j<cnt; j++)
    271             switch (t[0])
    272             {
    273             case 'C': // Skip whitespaces when checking for characters
    274                 if (j>0)
    275                     line >> noskipws;
    276                 Eval<char>(arg++, line, data);
    277                 line >> skipws;
    278                 break;
    279             case 'B': EvalBool       (arg++, line, data); break;
    280             case 'S': Eval<short>    (arg++, line, data); break;
    281             case 'I': Eval<int>      (arg++, line, data); break;
    282             case 'L': Eval<long>     (arg++, line, data); break;
    283             case 'F': Eval<float>    (arg++, line, data); break;
    284             case 'D': Eval<double>   (arg++, line, data); break;
    285             case 'X': Eval<long long>(arg++, line, data); break;
    286             case 'W': EvalString     (arg++, line, data); break;
    287             case 'O': EvalString     (arg++, line, data); line.clear(ios::goodbit); break;
    288             default:
    289                 // This should never happen!
    290                 wout << endl << kRed << "Format '" << t[0] << " not known!" << endl;
    291                 break;
    292             }
    293 
    294         //wout << "{" << line.eof() << line.good() << line.fail() << "}";
    295         if (!line)
    296             break;
    297     }
    298     //wout << "{" << line.eof() << line.good() << line.fail() << "}";
    299 
    300     wout << " [" << fmt << "]=" << data.size() << endl;
    301 
    302     // Something wrong with the conversion (e.g. 5.5 for an int)
    303     if (line.fail() && !line.eof())
    304     {
    305         line.clear(); // This is necesasary to get a proper response from tellg()
    306         wout << kRed << "Error converting argument at " << arg << " [fmt=" << fmt << "]!" << endl;
    307         wout << kRed << str << endl;
    308         wout << kRed << setw(int(line.tellg())) << " " << "^" << endl;
    309         return;
    310     }
    311 
    312     // Not enough arguments, we have not reached the end
    313     if (line.fail() && line.eof())
    314     {
    315         line.clear();
    316         wout << kRed << "Not enough arguments [fmt=" << fmt << "]!" << endl;
    317         wout << kRed << str << endl;
    318         wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl;
    319         return;
    320     }
    321 
    322     // Too many arguments, we have not reached the end
    323     // Unfortunately, this can also mean that there is something
    324     // wrong with the last argument
    325     if (line.good() && !line.eof())
    326     {
    327         wout << kRed << "More arguments available than expected [" << fmt << "]!" << endl;
    328         wout << kRed << str << endl;
    329         wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl;
    330         return;
    331     }
    332 
    333     // Set return code to true (successfull)
    334     rc = true;
    335 }
    336 
    337 // --------------------------------------------------------------------------
    338 //
    339 //! Gets the value as a binary from the ptr and return it as a string.
    340 //! The pointer is increased accordingly.
    341 //!
    342 //! Adds the value to Converter::vec.
    343 //!
    344 //! @param ptr
    345 //!    A reference to a pointer to the data which should be converted.
    346 //!    The pointer is increased according to the size of the data.
    347 //!
    348 //! @returns
    349 //!    The data converted into a string
    350 //!
    351 template<class T>
    352 string Converter::Get(const char* &ptr)
    353 {
    354     const T &t = *reinterpret_cast<const T*>(ptr);
    355 
    356     vec.push_back(t);
    357 
    358     ostringstream stream;
    359     stream << t;
    360     ptr += sizeof(T);
    361 
    362     return stream.str();
    363 }
    364 
    365 // --------------------------------------------------------------------------
    366 //
    367 //! Constructs a string from the given data block according to the specified
    368 //! format. (See also the class reference for more details).
    369 //!
    370 //! The resulting string is stored in vector<char>  and 0-terminated.
    371 //! It can be accessed through Ptr().
    372 //!
    373 //! If the conversion faild GetRc will return false. In this case the data
    374 //! contents might not be well defined.
    375 //!
    376 //! If no format is given (size == 0) but the data size is finite (>0)
    377 //! then the data is converted into a hex representation.
    378 //!
    379 //! @remark
    380 //!    In cases of failures the stored data might be inexisting and
    381 //!    Ptr() might return NULL. If you output NULL to our streams
    382 //!    they might not show any further output anymore.
    383 //!
    384 //! @param fmt
    385 //!    The format descriptor according to the dim definition
    386 //!
    387 //! @param out
    388 //!    The ostream to which errors and debug messages should be printed.
    389 //!
    390 //! @param dat
    391 //!    Pointer to the start of the binary data
    392 //!
    393 //! @param size
    394 //!    Size of the binary data region
    395 //!
    396 Converter::Converter(ostream &out, const string &fmt, const void *dat, int size)
    397 : rc(false), wout(out)
    398 {
    399     const char *ptr = reinterpret_cast<const char *>(dat);
    400 
    401     ostringstream text;
    402 
    403     // Structure: print hex representation
    404     if (fmt.size()==0)
    405     {
    406         if (size==0)
    407         {
    408             data.push_back(0);
    409             rc = true;
    410             return;
    411         }
    412 
    413         text << hex;
    414 
    415         for (int i=0; i<size; i++)
    416             text << setw(2) << ptr[i] << " ";
    417 
    418         const string &ref = text.str();
    419         data.insert(data.begin(), ref.begin(), ref.end());
    420         data.push_back(0);
    421         return;
    422     }
    423 
    424     // Access both, the data and the format through a stringstream
    425     stringstream stream(fmt);
    426 
    427     // For better performance we could use sregex
    428     static const boost::regex expr("^[ ]*([CSILFDX])[ ]*(:[ ]*([1-9]+[0-9]*))?[ ]*$");
    429 
    430     // Tokenize the format
    431     string buffer;
    432     while (getline(stream, buffer, ';'))
    433     {
    434         if (ptr-size>=dat)
    435         {
    436             wout << kRed << "Format description '" << fmt << "' exceeds available data size (" << size << ")" << endl;
    437             return;
    438         }
    439 
    440         boost::smatch what;
    441         if (!boost::regex_match(buffer, what, expr))
    442         {
    443             wout << kRed << "Wrong format string '" << buffer << "'!" << endl;
    444             return;
    445         }
    446 
    447         const string t = what[1]; // type id
    448         const string n = what[3]; // counter
    449 
    450         int cnt = atoi(n.c_str());
    451 
    452         // Check if the format is just C (without a number)
    453         // That would mean that it is a \0 terminated string
    454         if (t[0]=='C' && cnt==0)
    455         {
    456             const string str(ptr);
    457             text << ' ' << str;
    458             ptr += str.length()+1;
    459 
    460             vec.push_back(str);
    461 
     771            format.first = GetType<string>();
     772            list.push_back(format);
     773            format.second.second = 0; // end position not known
    462774            break;
    463775        }
    464776
    465         // if the :N part was not given assume 1
    466         if (cnt==0)
    467             cnt=1;
    468 
    469777        // Get as many items from the input line as requested
    470         for (int j=0; j<cnt; j++)
     778        switch (t[0])
    471779        {
    472             text << ' ';
    473 
    474             switch (t[0])
    475             {
    476             case 'C': text << Get<char>     (ptr); break;
    477             case 'S': text << Get<short>    (ptr); break;
    478             case 'I': text << Get<int>      (ptr); break;
    479             case 'L': text << Get<long>     (ptr); break;
    480             case 'F': text << Get<float>    (ptr); break;
    481             case 'D': text << Get<double>   (ptr); break;
    482             case 'X': text << Get<long long>(ptr); break;
    483             default:
    484                 // This should never happen!
    485                 wout << kRed << "Format '" << t[0] << " not known!" << endl;
    486                 return;
    487             }
     780        case 'B':  format.first = GetType<bool>();      break;
     781        case 'C':  format.first = GetType<char>();      break;
     782        case 'S':  format.first = GetType<short>();     break;
     783        case 'I':  format.first = GetType<int>();       break;
     784        case 'L':  format.first = GetType<long>();      break;
     785        case 'F':  format.first = GetType<float>();     break;
     786        case 'D':  format.first = GetType<double>();    break;
     787        case 'X':  format.first = GetType<long long>(); break;
     788        case 'O':  format.first = GetVoid<O>();         break;
     789        case 'W':  format.first = GetVoid<W>();         break;
     790        default:
     791            // This should never happen!
     792            out << kRed << "Format '" << t[0] << " not known!" << endl;
     793            return list;
    488794        }
    489     }
    490 
    491     if (ptr-size!=dat)
    492     {
    493         wout << kRed << "Data block size (" << size << ") doesn't fit format description '" << fmt << "'" << endl;
    494         return;
    495     }
    496 
    497     rc = true;
    498 
    499     const string &ref = text.str();
    500     data.insert(data.begin(), ref.begin()+1, ref.end());
    501     data.push_back(0);
    502 }
    503 
    504 
     795
     796        list.push_back(format);
     797        format.second.second += format.first.second * format.second.first;
     798    }
     799
     800    format.first = GetVoid<void>();
     801    format.second.first = 0;
     802
     803    list.push_back(format);
     804
     805    return list;
     806}
     807
     808// --------------------------------------------------------------------------
     809//
     810//! Same as Compile(ostream&,string&,bool) but cout is used as the default
     811//! output stream.
     812//!
     813//!
     814Converter::FormatList Converter::Compile(const std::string &fmt, bool strict)
     815{
     816    return Compile(cout, fmt, strict);
     817}
    505818
    506819vector<string> Converter::Regex(const string &expr, const string &line)
  • trunk/FACT++/src/Converter.h

    r10219 r10270  
    99class Converter
    1010{
     11public:
     12    typedef std::pair<const std::type_info *, int> Type;
     13    typedef std::pair<int, int>                    Offset;
     14    typedef std::pair<Type, Offset>                Format;
     15    typedef std::vector<Format>                    FormatList;
     16
     17    struct O { };
     18    struct W { };
     19
     20    static std::string Clean(std::string s);
     21
    1122private:
    12     bool rc;                        /// Flag for the success of the conversion
    13     std::ostream &wout;             /// ostream to which output is redirected
    14     std::vector<char> data;         /// data storage
    15     std::vector<boost::any> vec;    /// storage for typed data
     23    std::ostream &wout;        /// ostream to which output is redirected
     24
     25    const std::string fFormat; /// Original format string
     26    const FormatList  fList;   /// Compiled format description
     27
     28    template <class T>
     29        T Get(std::stringstream &line) const;
     30
     31    bool        GetBool(std::stringstream &line) const;
     32    std::string GetString(std::stringstream &line) const;
     33    std::string GetStringEol(std::stringstream &line) const;
    1634
    1735    template<class T>
    18         void EvalImp(int i, std::stringstream &line, std::vector<char> &v, const T &val);
     36        void GetBinImp(std::vector<char> &v, const T &val) const;
    1937    template<class T>
    20         void Eval(int i, std::stringstream &line, std::vector<char> &v);
    21         void EvalBool(int i, std::stringstream &line, std::vector<char> &v);
    22         void EvalString(int i, std::stringstream &line, std::vector<char> &v);
     38        void GetBinImp(std::vector<boost::any> &v, const T &val) const;
     39
     40    void GetBinString(std::vector<char> &v, const std::string &val) const;
     41    void GetBinString(std::vector<boost::any> &v, const std::string &val) const;
    2342
    2443    template<class T>
    25         std::string Get(const char *&data);
     44        std::string GetString(const char *&data) const;
     45
     46    template<class T>
     47        static Type GetType();
     48    template<class T>
     49        static Type GetVoid();
     50
     51    template <class T>
     52        std::vector<T> Get(const std::string &str) const;
     53    template <class T>
     54        T Get(const void *d, int size) const;
     55
     56
     57
     58    template<class T>
     59        void Add(std::string &str, const char* &ptr) const;
     60    void AddString(std::string &str, const std::string &ptr) const;
     61    template<class T>
     62        void Add(std::vector<boost::any> &vec, const char* &ptr) const;
     63    void AddString(std::vector<boost::any> &vec, const std::string &ptr) const;
     64
    2665
    2766public:
    28     Converter(std::ostream &out, const std::string &fmt, const std::string &str);
    29     Converter(std::ostream &out, const std::string &fmt, const void *d, int size);
     67    Converter(std::ostream &out, const std::string &fmt, bool strict=true);
     68    Converter(const std::string &fmt, bool strict=true);
    3069
    31     /// Returns whether the conversion was successfull
    32     bool GetRc() const { return rc; }
     70    /// @returns whether the interpreted format was valid but empty ("")
     71    bool empty() const { return fList.size()==1 && fList.back().first.second==0; }
    3372
    34     /// const Pointer to the data memory
    35     const char *Ptr() const { return &*data.begin(); }
    36     /// non-const Pointer to the data memory (for convinience using Dim)
    37     char *Ptr() { return &*data.begin(); }
     73    /// @returns whether the compilation was successfull
     74    bool valid() const { return !fList.empty() && fList.back().first.second==0; }
    3875
    39     /// Return the size of the data memory
    40     int  Size() const { return data.size(); }
     76    /// @returns true if the compilation failed
     77    bool operator!() const { return !valid(); }
    4178
    42     /// Return the data memory converted into a string (not necessarily \0-terminated)
    43     const std::string Str() const { return std::string(&*data.begin(), data.size()); }
     79    const FormatList &GetList() const { return fList; }
    4480
     81    static FormatList Compile(std::ostream &out, const std::string &fmt, bool strict=false);
     82    static FormatList Compile(const std::string &fmt, bool strict=false);
    4583
     84    std::string             GetString(const void *d, int size) const;
     85    std::vector<char>       GetVector(const void *d, int size) const;
     86    std::vector<boost::any> GetAny(const void *d, int size) const;
     87
     88    std::vector<boost::any> GetAny(const std::string &str) const;
     89    std::vector<char>       GetVector(const std::string &str) const;
     90
     91    static std::string GetHex(const void *d, int size);
     92
     93/*
    4694    // Returns the number of entries in Converter:vec
    4795    int N() const { return vec.size(); }
     
    58106    template <class T>
    59107        T At(int i) const { return boost::any_cast<T>(vec[i]); }
    60 
     108*/
    61109
    62110    static std::vector<std::string> Regex(const std::string &expr, const std::string &line);
Note: See TracChangeset for help on using the changeset viewer.