Remote Procedure Call (RPC) over Websockets (uses MbedJSONValue)
Dependents: RPC_mbed_client RPC_Wifly_HelloWorld RPC_Ethernet_HelloWorld
Revision 2:af408b5cae75, committed 2011-09-22
- Comitter:
- samux
- Date:
- Thu Sep 22 10:38:50 2011 +0000
- Parent:
- 1:7b7230760e0c
- Child:
- 3:4a3bc3a2314f
- Commit message:
Changed in this revision
--- a/MbedJSONRpc.cpp Thu Sep 22 10:20:52 2011 +0000 +++ b/MbedJSONRpc.cpp Thu Sep 22 10:38:50 2011 +0000 @@ -1,12 +1,12 @@ #include "MbedJSONRpc.h" -RPC_TYPE MbedJSONRpc::call(char * fn, char * dest, MbedRpcValue& val, MbedRpcValue& resp) { +RPC_TYPE MbedJSONRpc::call(char * fn, char * dest, MbedJSONValue& val, MbedJSONValue& resp) { char json[150]; RPC_TYPE t; string str = val.serialize(); int id = rand() % 100; - MbedRpcValue tmp; + MbedJSONValue tmp; sprintf(json, (const char *)MSG_CALL, my_id, dest, id, fn, str.c_str()); @@ -18,7 +18,7 @@ return CALL_OK; } -RPC_TYPE MbedJSONRpc::waitAnswer(MbedRpcValue& v, int id, char * json) { +RPC_TYPE MbedJSONRpc::waitAnswer(MbedJSONValue& v, int id, char * json) { Timer tmr; tmr.start(); @@ -57,7 +57,7 @@ void MbedJSONRpc::checkMethods(char * dest) { char json[150]; char name[5]; - MbedRpcValue tmp; + MbedJSONValue tmp; int id = rand() % 100; sprintf(json, (const char *)MSG_INFO_METHODS, my_id, dest, id); @@ -71,7 +71,7 @@ printf("\r\n"); } -RPC_TYPE MbedJSONRpc::decodeMsg(MbedRpcValue& v, int id) { +RPC_TYPE MbedJSONRpc::decodeMsg(MbedJSONValue& v, int id) { if (v.hasMember("id_msg")) if (v["id_msg"].get<int>() != -1 && id != v["id_msg"].get<int>()) { @@ -108,10 +108,10 @@ } -RPC_TYPE MbedJSONRpc::registerMethod(const char * public_name, void (*fn)(MbedRpcValue& val, MbedRpcValue& res) ) { +RPC_TYPE MbedJSONRpc::registerMethod(const char * public_name, void (*fn)(MbedJSONValue& val, MbedJSONValue& res) ) { char json[100]; int id = rand() % 100; - MbedRpcValue tmp; + MbedJSONValue tmp; RPC_TYPE t; sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name); @@ -130,7 +130,7 @@ void MbedJSONRpc::work() { char json_recv[150]; DigitalOut led4(LED4); - MbedRpcValue v, r; + MbedJSONValue v, r; int i = -1; while (1) { wait(0.2);
--- a/MbedJSONRpc.h Thu Sep 22 10:20:52 2011 +0000 +++ b/MbedJSONRpc.h Thu Sep 22 10:38:50 2011 +0000 @@ -37,7 +37,7 @@ #include "Websocket.h" #include "Wifly.h" #include "mbed.h" -#include "MbedJSONRpcValue.h" +#include "MbedJSONValue.h" #include <string> #define NB_METH 30 @@ -58,7 +58,7 @@ */ enum RPC_TYPE { JSON_PARSE_ERROR, /*!< Json parse error */ - RPC_PARSE_ERROR, /*!< rpc parse error (the message doesn't contain good identifiers in a TypeObject MbedRpcValue)*/ + RPC_PARSE_ERROR, /*!< rpc parse error (the message doesn't contain good identifiers in a TypeObject MbedJSONValue)*/ PROC_NOT_FOUND, /*!< The user wants to call an inexisting method or procedure */ CLIENT_NOT_CONNECTED, /*!< The user wants to call a method or procedure on a client not connected (no response from the client within 3s) */ SERVER_NOT_CONNECTED, /*!< No response from the server within 5s */ @@ -71,19 +71,19 @@ class ObjBase { public: - virtual void execute(MbedRpcValue& val, MbedRpcValue& res) = 0; + virtual void execute(MbedJSONValue& val, MbedJSONValue& res) = 0; }; template <class T> class Obj : public ObjBase { public: - Obj(T * ptr, void (T::*fn_ptr)(MbedRpcValue& , MbedRpcValue& )) { + Obj(T * ptr, void (T::*fn_ptr)(MbedJSONValue& , MbedJSONValue& )) { obj_ptr = ptr; fn = fn_ptr; }; - virtual void execute(MbedRpcValue& val, MbedRpcValue& res) { + virtual void execute(MbedJSONValue& val, MbedJSONValue& res) { ((*obj_ptr).*fn)(val, res); } @@ -91,7 +91,7 @@ T * obj_ptr; //method - void (T::*fn)(MbedRpcValue& , MbedRpcValue& ); + void (T::*fn)(MbedJSONValue& , MbedJSONValue& ); }; @@ -230,7 +230,7 @@ * #endif * * RPC_TYPE t; - * MbedRpcValue arg, resp; + * MbedJSONValue arg, resp; * arg[0] = "Hello"; * * // print all methods and procedure available on the client "server" @@ -271,16 +271,16 @@ * * @param public_name the method will be seen and called by this name * @param obj_ptr a pointeur on the object which contains the method to register - * @param fn the method to register (this method must have this signature: void fn(MbedRpcValue& val, MbedRpcValue& res) + * @param fn the method to register (this method must have this signature: void fn(MbedJSONValue& val, MbedJSONValue& res) * @return if REGISTER_OK, the method is registered, otherwise, there is an error * */ - template<typename T> RPC_TYPE registerMethod(const char * public_name, T * obj_ptr, void (T::*fn)(MbedRpcValue& val, MbedRpcValue& res)) { + template<typename T> RPC_TYPE registerMethod(const char * public_name, T * obj_ptr, void (T::*fn)(MbedJSONValue& val, MbedJSONValue& res)) { char json[100]; RPC_TYPE t; Timer tmr; int id = rand() % 100; - MbedRpcValue tmp; + MbedJSONValue tmp; sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name); webs->Send(json); @@ -300,11 +300,11 @@ * Register a procedure * * @param public_name the method will be seen and called by this name - * @param fn the procedure to register (this procedure must have this signature: void fn(MbedRpcValue& val, MbedRpcValue& res) + * @param fn the procedure to register (this procedure must have this signature: void fn(MbedJSONValue& val, MbedJSONValue& res) * @return if REGISTER_OK, the procedure is registered, otherwise, there is an error * */ - RPC_TYPE registerMethod(const char * public_name, void (*fn)(MbedRpcValue& val, MbedRpcValue& res) ); + RPC_TYPE registerMethod(const char * public_name, void (*fn)(MbedJSONValue& val, MbedJSONValue& res) ); /** @@ -320,7 +320,7 @@ * Refer to the RPC_TYPE description * */ - RPC_TYPE call(char * fn, char * dest, MbedRpcValue& val, MbedRpcValue& resp); + RPC_TYPE call(char * fn, char * dest, MbedJSONValue& val, MbedJSONValue& resp); /** @@ -336,12 +336,12 @@ private: - typedef void (*FNPTR)(MbedRpcValue& , MbedRpcValue& ); + typedef void (*FNPTR)(MbedJSONValue& , MbedJSONValue& ); int methodAlreadyRegistered(char *); int procAlreadyRegistered(char *); - RPC_TYPE decodeMsg(MbedRpcValue& , int); - RPC_TYPE waitAnswer(MbedRpcValue& , int, char *); + RPC_TYPE decodeMsg(MbedJSONValue& , int); + RPC_TYPE waitAnswer(MbedJSONValue& , int, char *); Websocket * webs;
--- a/MbedJSONRpcValue.cpp Thu Sep 22 10:20:52 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -#include "MbedJSONRpcValue.h" - -# include <stdlib.h> -# include <stdio.h> - -// Clean up -void MbedRpcValue::clean() { - switch (_type) { - case TypeString: - delete _value.asString; - break; - case TypeArray: - for (int i = 0; i < index_array; i++) - delete array[i]; - index_array = 0; - break; - case TypeObject: - for (int i = 0; i < index_token; i++) { - delete token[i]; - delete token_name[i]; - } - index_token = 0; - break; - default: - break; - } - _type = TypeNull; - _type = TypeNull; -} - -bool MbedRpcValue::hasMember(char * name) -{ - for(int i = 0; i < index_token; i++) - if( !strcmp(name, (*(token_name[i])).c_str() )) - return true; - return false; -} - - -void copy(const std::string& s, std::back_insert_iterator<std::string> oi) { - std::copy(s.begin(), s.end(), oi); -} - -void serialize_str(const std::string& s, std::back_insert_iterator<std::string> oi) { - *oi++ = '"'; - for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { - switch (*i) { -#define MAP(val, sym) case val: copy(sym, oi); break - MAP('"', "\\\""); - MAP('\\', "\\\\"); - MAP('/', "\\/"); - MAP('\b', "\\b"); - MAP('\f', "\\f"); - MAP('\n', "\\n"); - MAP('\r', "\\r"); - MAP('\t', "\\t"); -#undef MAP - default: - if ((unsigned char)*i < 0x20 || *i == 0x7f) { - char buf[7]; - sprintf(buf, "\\u%04x", *i & 0xff); - copy(buf, buf + 6, oi); - } else { - *oi++ = *i; - } - break; - } - } - *oi++ = '"'; -} - -std::string MbedRpcValue::serialize(){ - std::string s; - serialize(std::back_inserter(s)); - return s; -} - -std::string MbedRpcValue::to_str(){ - switch (_type) { - case TypeNull: - return "null"; - case TypeBoolean: - return _value.asBool ? "true" : "false"; - case TypeInt: { - char buf[10]; - sprintf(buf, "%d", _value.asInt); - return buf; - } - case TypeDouble: { - char buf[10]; - sprintf(buf, "%f", _value.asDouble); - return buf; - } - default: - break; - } - return NULL; -} - - - -void MbedRpcValue::serialize(std::back_insert_iterator<std::string> oi) { - switch (_type) { - case TypeString: - serialize_str(*_value.asString, oi); - break; - case TypeArray: { - *oi++ = '['; - for (int i = 0; i < index_array; i++) { - if (i) - *oi++ = ','; - (*this)[i].serialize(oi); - } - *oi++ = ']'; - break; - } - case TypeObject: { - *oi++ = '{'; - for (int i = 0; i < index_token; i++) { - if (i) - *oi++ = ','; - serialize_str(*(token_name[i]), oi); - *oi++ = ':'; - (*(token[i])).serialize(oi); - } - *oi++ = '}'; - break; - } - default: - copy(to_str(), oi); - break; - } -} - - - -MbedRpcValue& MbedRpcValue::operator[](int i) { - _type = TypeArray; - if (i < NB_TOKEN && index_array == i ) { -#ifdef DEBUG - printf("will add an element to the array\r\n"); -#endif - array[i] = new MbedRpcValue(); - index_array++; - return *(array[i]); - } - if (i < NB_TOKEN && index_array > i) - return *(array[i]); - - //if the user is not doing something wrong, this code is never executed!! - return *(new MbedRpcValue()); -} - -MbedRpcValue& MbedRpcValue::operator[](std::string k) { - _type = TypeObject; - for (int i = 0; i < index_token; i++) { -#ifdef DEBUG - printf("k: %s\r\n", k.c_str()); - printf("str: %s\r\n", token_name[i]->c_str()); -#endif - //existing token - if (!strcmp(k.c_str(), token_name[i]->c_str())) { -#ifdef DEBUG - printf("token found: %d\r\n", i); -#endif - return *(token[i]); - } - } - - if(index_token >= NB_TOKEN) - index_token = NB_TOKEN - 1; - //non existing token - token_name[index_token] = new std::string(k); - token[index_token] = new MbedRpcValue(); - index_token++; - return *(token[index_token - 1]); -} - -MbedRpcValue& MbedRpcValue::operator[](std::string k) const -{ - for (int i = 0; i < index_token; i++) { -#ifdef DEBUG - printf("k: %s\r\n", k.c_str()); - printf("str: %s\r\n", token_name[i]->c_str()); -#endif - if (!strcmp(k.c_str(), token_name[i]->c_str())) { -#ifdef DEBUG - printf("token found: %d\r\n", i); -#endif - return *(token[i]); - } - } - - //if the user is not doing something wrong, this code is never executed!! - return *(new MbedRpcValue()); -} - - -// Operators -MbedRpcValue& MbedRpcValue::operator=(MbedRpcValue const& rhs) { - if (this != &rhs) { - clean(); - _type = rhs._type; - switch (_type) { - case TypeBoolean: - _value.asBool = rhs._value.asBool; - break; - case TypeInt: - _value.asInt = rhs._value.asInt; - break; - case TypeDouble: - _value.asDouble = rhs._value.asDouble; - break; - case TypeString: - _value.asString = new std::string(*rhs._value.asString); - break; - case TypeArray: - for (int i = 0; i < rhs.index_array; i++) - (*this)[i] = rhs[i]; - case TypeObject: - for (int i = 0; i < rhs.index_token; i++) - (*this)[*(rhs.token_name[i])] = rhs[*(rhs.token_name[i])]; - default: - break; - } - } - return *this; -} - - -// Works for strings, arrays, and structs. -int MbedRpcValue::size() const { - switch (_type) { - case TypeString: - return int(_value.asString->size()); - case TypeArray: - return index_array; - case TypeObject: - return index_token; - default: - break; - } - return -1; -} -
--- a/MbedJSONRpcValue.h Thu Sep 22 10:20:52 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,568 +0,0 @@ -/** -* @author Samuel Mokrani -* -* @section LICENSE -* -* Copyright (c) 2011 mbed -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* @section DESCRIPTION -* Types Abstraction for the RPC communication -* -*/ - -#ifndef _MbedJSON_RPC_VALUE_H_ -#define _MbedJSON_RPC_VALUE_H_ - -#define NB_TOKEN 20 -/*!< Number maximum of MbedRpcValue in an array or an object */ - -#include <string> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -/** MbedRpcValue class - * - * Example: - * - creation of an MbedRpcValue of type TypeObject containing two others MbedRpcValue: - * -one array of one string and one integer identified by "my_array" - * -a boolean identified by "my_boolean" - * - serialization in JSON format of this object - * @code - * MbedRpcValue demo; - * std::string s; - * - * //fill the object - * demo["my_array"][0] = "demo_string"; - * demo["my_array"][1] = 10; - * demo["my_boolean"] = true; - * - * //serialize it into a JSON string - * s = demo.serialize(); - * - * - * @endcode - * - * Example: - * - creation of an MbedRpcValue from a JSON string - * - extraction of different values from this existing MbedRpcValue - * @code - * - * MbedRpcValue demo; - * - * const char * json = "{\"my_array\": [\"demo_string\", 10], \"my_boolean\": true}"; - * - * //parse the previous string and fill the object demo - * parse(demo, json); - * - * std::string my_str; - * int my_int; - * bool my_bool; - * - * my_str = demo["my_array"][0]; - * my_int = demo["my_array"][1]; - * my_bool = demo["my_boolean"]; - * - * @endcode - */ -class MbedRpcValue { -public: - - /** - * \enum Type - * \brief All types which can be used - */ - enum Type { - TypeNull, /*!< Null type */ - TypeBoolean, /*!< Boolean */ - TypeInt, /*!< Integer */ - TypeDouble, /*!< Double */ - TypeString, /*!< String */ - TypeArray, /*!< Array of Type */ - TypeObject /*!< Object */ - }; - - /** - * MbedRpcValue constructor of type TypeNull - */ - MbedRpcValue() : _type(TypeNull), index_array(0), index_token(0) {} - - /** - * MbedRpcValue constructor of type TypeBoolean - * - * @param value the object created will be initialized with this boolean - */ - MbedRpcValue(bool value) : _type(TypeBoolean), index_array(0), index_token(0) { - _value.asBool = value; - } - - /** - * MbedRpcValue constructor of type TypeInt - * - * @param value the object created will be initialized with this integer - */ - MbedRpcValue(int value) : _type(TypeInt), index_array(0), index_token(0) { - _value.asInt = value; - } - - /** - * MbedRpcValue constructor of type TypeDouble - * - * @param value the object created will be initialized with this double - */ - MbedRpcValue(double value) : _type(TypeDouble), index_array(0), index_token(0) { - _value.asDouble = value; - } - - /** - * MbedRpcValue constructor of type TypeString - * - * @param value the object created will be initialized with this string - */ - MbedRpcValue(std::string const& value) : _type(TypeString), index_array(0), index_token(0) { - _value.asString = new std::string(value); - } - - /** - * MbedRpcValue constructor of type TypeString - * - * @param value the object created will be initialized with this string - */ - MbedRpcValue(const char* value) : _type(TypeString), index_array(0), index_token(0) { - _value.asString = new std::string(value); - } - - /** - * Copy constructor - * - * @param rhs object which will be copied - */ - MbedRpcValue(MbedRpcValue const& rhs) : _type(TypeNull) { *this = rhs; } - - /** - * Destructor - */ - ~MbedRpcValue() { clean(); } - - /** - * = Operator overloading for an MbedRpcValue from an MbedRpcValue - * - * @param rhs object - * @return a reference on the MbedRpcValue affected - */ - MbedRpcValue& operator=(MbedRpcValue const & rhs); - - /** - * = Operator overloading for an MbedRpcValue from an int - * - * @param integer - * @return a reference on the MbedRpcValue affected - */ - MbedRpcValue& operator=(int const& rhs) { return operator=(MbedRpcValue(rhs)); } - - /** - * = Operator overloading for an MbedRpcValue from a double - * - * @param double - * @return a reference on the MbedRpcValue affected - */ - MbedRpcValue& operator=(double const& rhs) { return operator=(MbedRpcValue(rhs)); } - - /** - * = Operator overloading for an MbedRpcValue from a string - * - * @param string - * @return a reference on the MbedRpcValue affected - */ - MbedRpcValue& operator=(const char* rhs) { return operator=(MbedRpcValue(std::string(rhs))); } - - - /** - * [] Operator overloading for an MbedRpcValue. - * Each TypeObject object can contain an array of NB_TOKEN MbedRpcvalue. - * This operator is useful to create an array or to retrieve an MbedRpcValue of an existing array. - * - * @param i index of the array - * @return a reference on the MbedRpcValue created or retrieved - */ - MbedRpcValue& operator[](int i); - - /** - * [] Operator overloading for an MbedRpcValue. - * Each TypeObject MbedRpcValue can contain NB_TOKEN MbedRpcValue IDENTIFIED BY A NAME - * This operator is useful to create a TypeObject MbedRpcValue or to retrieve an MbedRpcValue of an existing TypeObject. - * - * - * @param str identifier of the sub MbedRpcValue - * @return a reference on the MbedRpcValue created or retrieved - */ - MbedRpcValue& operator[](std::string str); - - /** - * Retrieve the value of an MbedRpcValue object. - * - * Let's suppose that we have an MbedRpcValue of type TypeString. - * To retrieve this string, you have to do: - * my_obj.get<std::string>(); - * - * @return A contant reference on the value of the object - */ - template <typename T> const T& get() const; - - /** - * Retrieve the value of an MbedRpcValue object. - * - * Let's suppose that we have an MbedRpcValue of type TypeInt. - * To retrieve this integer, you have to do: - * my_obj.get<int>(); - * - * @return A reference on the value of the object - */ - template <typename T> T& get(); - - - /** - * Return the type of the MbedRpcValue object - * - * @return type of the MbedRpcValue object - */ - Type const &getType() const { - return _type; - } - - /** - * Return the size of an MbedRpcValue object (works for TypeString, TypeArray or TypeObject) - * - * @return size - */ - int size() const; - - /** - * Check for the existence in a TypeObject object of member identified by name - * - * @param name Identifier - * @return true if the object is of type TypeObject AND contains a member named "name", false otherwise - */ - bool hasMember(char * name); - - /** - * Convert an MbedRpcValue in a JSON frame - * - * @return JSON string - */ - std::string serialize(); - -protected: - - // object type - Type _type; - - //indexes of TypeObject and TypeArray - int index_array; - int index_token; - - //an object can contain NB_TOKEN tokens. Each token have a name - MbedRpcValue * token[NB_TOKEN]; - std::string * token_name[NB_TOKEN]; - - //an object can contain an array of NB_TOKEN elements - MbedRpcValue * array[NB_TOKEN]; - - // Clean up - void clean(); - - union { - bool asBool; - int asInt; - double asDouble; - std::string* asString; - } _value; - - - MbedRpcValue& operator[](int i) const { return *(array[i]); } - MbedRpcValue& operator[](std::string k) const; - - std::string to_str(); - void serialize(std::back_insert_iterator<std::string> os); - -}; - - -#define GET(ctype, var) \ - template <> inline const ctype& MbedRpcValue::get<ctype>() const { \ - return var; \ - } \ - template <> inline ctype& MbedRpcValue::get<ctype>() { \ - return var; \ - } -GET(bool, _value.asBool) -GET(double, _value.asDouble) -GET(int, _value.asInt) -GET(std::string, *_value.asString) -#undef GET - - -//Input class for JSON parser -class input { -protected: - const char * cur_; - const char * end_; - int last_ch_; - bool ungot_; - int line_; -public: - input(const char * first, const char * last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}; - - int getc() { - if (ungot_) { - ungot_ = false; - return last_ch_; - } - if (cur_ == end_) { - last_ch_ = -1; - return -1; - } - if (last_ch_ == '\n') { - line_++; - } - last_ch_ = *cur_++ & 0xff; - return last_ch_; - } - - void ungetc() { - if (last_ch_ != -1) { - ungot_ = true; - } - } - - const char * cur() const { - return cur_; - } - int line() const { - return line_; - } - void skip_ws() { - while (1) { - int ch = getc(); - if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { - ungetc(); - break; - } - } - } - int expect(int expect) { - skip_ws(); - if (getc() != expect) { - ungetc(); - return false; - } - return true; - } - bool match(const std::string& pattern) { - for (std::string::const_iterator pi(pattern.begin()); - pi != pattern.end(); - ++pi) { - if (getc() != *pi) { - ungetc(); - return false; - } - } - return true; - } -}; - - - -inline const char * parse(MbedRpcValue& out, const char * first, const char * last, std::string* err); - -/** -* JSON string parser and creation of an MbedRpcValue -* -* @param out reference of an MbedRpcValue which will be filled according to the JSON string -* @param str JSON string -* @return A non empty string if there is a parsing error -* -*/ - -inline std::string parse(MbedRpcValue& out, const char * str); -inline bool _parse(MbedRpcValue& out, input& in); -inline bool _parse_number(MbedRpcValue& out, input& in); -inline bool _parse_string(MbedRpcValue& out, input& in); -inline bool _parse_array(MbedRpcValue& out, input& in); -inline bool _parse_object(MbedRpcValue& out, input& in); - - -inline bool _parse_string(MbedRpcValue& out, input& in) { -#ifdef DEBUG - printf("string detected\r\n"); -#endif - out = MbedRpcValue(std::string("")); - std::string& s = out.get<std::string>(); - while (1) { - int ch = in.getc(); - if (ch < ' ') { - in.ungetc(); - return false; - } else if (ch == '"') { - return true; - } else if (ch == '\\') { - if ((ch = in.getc()) == -1) { - return false; - } - switch (ch) { -#define MAP(sym, val) case sym: s.push_back(val); break - MAP('"', '\"'); - MAP('\\', '\\'); - MAP('/', '/'); - MAP('b', '\b'); - MAP('f', '\f'); - MAP('n', '\n'); - MAP('r', '\r'); - MAP('t', '\t'); -#undef MAP - default: - return false; - } - } else { - s.push_back(ch); - } - } -} - -inline bool _parse_array(MbedRpcValue& out, input& in) { -#ifdef DEBUG - printf("array detected\r\n"); -#endif - int i = 0; - if (in.expect(']')) { - return true; - } - do { - if (! _parse(out[i], in)) { - return false; - } - i++; - } while (in.expect(',')); - return in.expect(']'); -} - -inline bool _parse_object(MbedRpcValue& out, input& in) { -#ifdef DEBUG - printf("object detected\r\n"); -#endif - if (in.expect('}')) { - return true; - } - do { - MbedRpcValue key, val; - if (in.expect('"') && _parse_string(key, in) && in.expect(':') && _parse(val, in)) { - out[key.get<std::string>().c_str()] = val; -#ifdef DEBUG - printf("key: %s \r\n", key.get<std::string>().c_str()); -#endif - } else { - return false; - } - } while (in.expect(',')); - return in.expect('}'); -} - -inline bool _parse_number(MbedRpcValue& out, input& in) { -#ifdef DEBUG - printf("number detected\r\n"); -#endif - std::string num_str; - while (1) { - int ch = in.getc(); - if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.' - || ch == 'e' || ch == 'E') { - num_str.push_back(ch); - } else { - in.ungetc(); - break; - } - } - char* endp; - if (strchr(num_str.c_str(), '.') != NULL || strchr(num_str.c_str(), 'e') != NULL || strchr(num_str.c_str(), '+') != NULL) - out = MbedRpcValue(strtod(num_str.c_str(), &endp)); - else - out = MbedRpcValue((int)strtod(num_str.c_str(), &endp)); - return endp == num_str.c_str() + num_str.size(); -} - -inline bool _parse(MbedRpcValue& out, input& in) { - in.skip_ws(); - int ch = in.getc(); - switch (ch) { -#define IS(ch, text, val) case ch: \ - if (in.match(text)) { \ - out = val; \ - return true; \ - } else { \ - return false; \ - } - IS('n', "ull", MbedRpcValue()); - IS('f', "alse", MbedRpcValue(false)); - IS('t', "rue", MbedRpcValue(true)); -#undef IS - case '"': - return _parse_string(out, in); - case '[': - return _parse_array(out, in); - case '{': - return _parse_object(out, in); - default: - if (('0' <= ch && ch <= '9') || ch == '-') { - in.ungetc(); - return _parse_number(out, in); - } - break; - } - in.ungetc(); - return false; -} - -inline std::string parse(MbedRpcValue& out, const char * pos) { - const char * last = pos + strlen(pos); - std::string err; - pos = parse(out, pos, last, &err); - return err; -} - -inline const char * parse(MbedRpcValue& out, const char * first, const char * last, std::string* err) { - input in = input(first, last); - if (! _parse(out, in) && err != NULL) { - char buf[64]; - sprintf(buf, "syntax error at line %d near: ", in.line()); - *err = buf; - while (1) { - int ch = in.getc(); - if (ch == -1 || ch == '\n') { - break; - } else if (ch >= ' ') { - err->push_back(ch); - } - } - } - return in.cur(); -} - -#endif // _MbedMbedRpcValue_H_