Module: sems
Branch: master
Commit: 9762fba26189e72dd6dcbafd8cb1dac2ae7da81b
URL:    
http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=9762fba26189e72dd6dcbafd8cb1dac2ae7da81b

Author: Stefan Sayer <[email protected]>
Committer: Stefan Sayer <[email protected]>
Date:   Fri Jul 16 02:14:54 2010 +0200

core: json: add number with exp format parsing

---

 core/jsonxx.cpp             |  230 +++++++++++++++++++++++++++++++++++++++++-
 core/tests/test_jsonarg.cpp |   53 ++++++++++
 2 files changed, 277 insertions(+), 6 deletions(-)

diff --git a/core/jsonxx.cpp b/core/jsonxx.cpp
index e3b307a..41cddf5 100644
--- a/core/jsonxx.cpp
+++ b/core/jsonxx.cpp
@@ -33,6 +33,10 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <iostream>
 #include <sstream>
 
+#include <math.h>
+
+#include "log.h"
+
 namespace jsonxx {
 
 void eat_whitespaces(std::istream& input) {
@@ -125,6 +129,7 @@ bool parse_null(std::istream& input) {
     return false;
 }
 
+  /*
 bool parse_float(std::istream& input, double* value) {
     eat_whitespaces(input);
     char ch;
@@ -160,6 +165,8 @@ bool parse_float(std::istream& input, double* value) {
         return false;
     }
 }
+  */
+
 
 bool parse_number(std::istream& input, long* value) {
     eat_whitespaces(input);
@@ -188,27 +195,238 @@ bool parse_number(std::istream& input, long* value) {
     }
 }
 
+
 bool parse_number(std::istream& input, int* value) {
     eat_whitespaces(input);
     char ch;
     std::string value_str;
+    std::string exp_str; // whole exp part
+    std::string exp_value_str; // value of exp part
     int sign = 1;
+    int e_sign = 1;
+    bool correct = true;
+    int e_value;
+
+    enum {
+      p_number,
+      p_e,
+      p_enumber
+    } p_state = p_number;
+
     if (match("-", input)) {
         sign = -1;
     } else {
         match("+", input);
     }
+
     while(input && !input.eof()) {
-        input.get(ch);
-        if (!isdigit(ch)) {
-            input.putback(ch);
-            break;
-        }
-        value_str.push_back(ch);
+      input.get(ch);
+      switch (p_state) {
+      case p_number: {
+       // DBG("st = p_number, ch=%c\n",ch);
+       if (ch == 'E' || ch == 'e') {
+         exp_str.push_back(ch);
+         p_state = p_e;
+         continue;
+       }
+       if (!isdigit(ch)) {
+         input.putback(ch);
+         correct = false;
+         break;
+       }
+       value_str.push_back(ch);
+      } break;
+
+      case p_e: {
+       // DBG("st = p_e, ch=%c\n",ch);
+
+       if (ch == '+') {
+         exp_str.push_back(ch);
+         p_state = p_enumber;
+       } else if (ch == '-') {
+         e_sign = -1;
+         exp_str.push_back(ch);
+         p_state = p_enumber;
+       } else if (isdigit(ch)) {
+         exp_value_str.push_back(ch);
+         exp_str.push_back(ch);
+         p_state = p_enumber;
+       } else {
+         input.putback(ch);
+         correct = false;
+       }
+      } break;
+
+      case p_enumber: {
+       // DBG("st = p_enumber, ch=%c\n",ch);
+
+       if (isdigit(ch)) {
+         exp_value_str.push_back(ch);
+         exp_str.push_back(ch);
+       } else {
+         input.putback(ch);
+         correct = false;
+       }
+      } break;
+
+      }
+
+      if (!correct)
+       break;
+    }
+
+    if (p_state == p_e) { 
+      // todo: check also some other error states
+      for (std::string::reverse_iterator r_it=
+            exp_str.rbegin(); r_it != exp_str.rend(); r_it++)
+       input.putback(*r_it);
+      for (std::string::reverse_iterator r_it=
+            value_str.rbegin(); r_it != value_str.rend(); r_it++)
+       input.putback(*r_it);
+      return false;
     }
+    
     if (value_str.size() > 0) {
         std::istringstream(value_str) >> *value;
        *value*=sign;
+
+       if (exp_value_str.size()) {       
+         std::istringstream(exp_value_str) >> e_value;
+
+         if (e_value && e_sign==-1) {
+           // should have been catched by parse_float
+           for (std::string::reverse_iterator r_it=
+                  exp_str.rbegin(); r_it != exp_str.rend(); r_it++)
+             input.putback(*r_it);
+           for (std::string::reverse_iterator r_it=
+                  value_str.rbegin(); r_it != value_str.rend(); r_it++)
+             input.putback(*r_it);
+           
+           return false;  
+         }
+         *value *= pow(10, e_value);
+       }
+
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+bool parse_float(std::istream& input, double* value) {
+    eat_whitespaces(input);
+    char ch;
+    std::string value_str;
+    std::string exp_str; // whole exp part
+    std::string exp_value_str; // value of exp part
+    int sign = 1;
+    int e_sign = 1;
+    bool correct = true;
+    int e_value;
+    bool has_dot = false;
+
+    enum {
+      p_number,
+      p_e,
+      p_enumber
+    } p_state = p_number;
+
+    if (match("-", input)) {
+        sign = -1;
+    } else {
+        match("+", input);
+    }
+
+    while(input && !input.eof()) {
+      input.get(ch);
+      bool end = false;
+      switch (p_state) {
+      case p_number: {
+        // DBG("st = p_number, ch=%c\n",ch);
+       if (ch == 'E' || ch == 'e') {
+         exp_str.push_back(ch);
+         p_state = p_e;
+         continue;
+       }
+       if (ch == '.') {
+         if (has_dot) {
+           correct = false;
+           break;
+         }
+         has_dot = true;
+         value_str.push_back(ch);
+         continue;
+       }
+
+       if (!isdigit(ch)) {
+         input.putback(ch);
+         end = true;
+         break;
+       }
+       value_str.push_back(ch);
+      } break;
+
+      case p_e: {
+        // DBG("st = p_e, ch=%c\n",ch);
+       if (ch == '+') {
+         exp_str.push_back(ch);
+         p_state = p_enumber;
+       } else if (ch == '-') {
+         e_sign = -1;
+         exp_str.push_back(ch);
+         p_state = p_enumber;
+       } else if (isdigit(ch)) {
+         exp_value_str.push_back(ch);
+         exp_str.push_back(ch);
+         p_state = p_enumber;
+       } else {
+         input.putback(ch);
+         correct = false;
+       }
+      } break;
+
+      case p_enumber: {
+       // DBG("st = p_enumber, ch=%c\n",ch);
+
+       if (isdigit(ch)) {
+         exp_value_str.push_back(ch);
+         exp_str.push_back(ch);
+       } else {
+         input.putback(ch);
+         end = true;
+       }
+      } break;
+
+      }
+
+      if (end || !correct)
+       break;
+    }
+
+    // DBG("correct = %s, has_dot = %s, e_sign = %d, exp_value_str.size() = 
%zd\n", 
+    //         
correct?"true":"false",has_dot?"true":"false",e_sign,exp_value_str.size());
+    if (!correct || (!has_dot && !(e_sign == -1 && exp_value_str.size())) || 
p_state == p_e) { 
+      // todo: check also some other error states
+      for (std::string::reverse_iterator r_it=
+            exp_str.rbegin(); r_it != exp_str.rend(); r_it++)
+       input.putback(*r_it);
+      for (std::string::reverse_iterator r_it=
+            value_str.rbegin(); r_it != value_str.rend(); r_it++)
+       input.putback(*r_it);
+      return false;
+    }
+    
+    if (value_str.size() > 0) {
+        std::istringstream(value_str) >> *value;
+       *value*=sign;
+
+       if (exp_value_str.size()) {       
+         std::istringstream(exp_value_str) >> e_value;
+
+         *value *= pow(10, e_sign*e_value);
+       }
+
         return true;
     } else {
         return false;
diff --git a/core/tests/test_jsonarg.cpp b/core/tests/test_jsonarg.cpp
index 7de8533..2e25db8 100644
--- a/core/tests/test_jsonarg.cpp
+++ b/core/tests/test_jsonarg.cpp
@@ -49,4 +49,57 @@ FCTMF_SUITE_BGN(test_jsonarg) {
       fct_chk(rpc_params["result"][""].asInt()==1);
     } FCT_TEST_END();
 
+    FCT_TEST_BGN(json_number_e_parse) {
+      string s = "{\"result\": 0E1}";
+      // DBG("s.c_str() %s\n", s.c_str() );
+      AmArg rpc_params;
+      fct_chk(json2arg(s.c_str(), rpc_params));
+      fct_chk(isArgInt(rpc_params["result"]) && rpc_params["result"].asInt() 
== 0);
+    } FCT_TEST_END();
+
+    FCT_TEST_BGN(json_number_e_pow) {
+      string s = "{\"result\": 1E1}";
+      // DBG("s.c_str() %s\n", s.c_str() );
+      AmArg rpc_params;
+      fct_chk(json2arg(s.c_str(), rpc_params));
+      fct_chk(isArgInt(rpc_params["result"]) && rpc_params["result"].asInt() 
== 10);
+    } FCT_TEST_END();
+
+    FCT_TEST_BGN(json_number_e_pow2) {
+      string s = "{\"result\": 5e0}";
+      // DBG("s.c_str() %s\n", s.c_str() );
+      AmArg rpc_params;
+      fct_chk(json2arg(s.c_str(), rpc_params));
+      fct_chk(isArgInt(rpc_params["result"]) && rpc_params["result"].asInt() 
== 5);
+    } FCT_TEST_END();
+
+    FCT_TEST_BGN(json_number_e_wrong) {
+      string s = "{\"result\": 1E}";
+      // DBG("s.c_str() %s\n", s.c_str() );
+      AmArg rpc_params;
+      fct_chk(!json2arg(s.c_str(), rpc_params));
+    } FCT_TEST_END();
+
+    FCT_TEST_BGN(json_number_e_powneg1) {
+      string s = "{\"result\": 1E-1}";
+      // DBG("s.c_str() %s\n", s.c_str() );
+      AmArg rpc_params;
+      fct_chk(json2arg(s.c_str(), rpc_params));
+      // DBG("res: %s, type %d\n",  
AmArg::print(rpc_params["result"]).c_str(), rpc_params["result"].getType());
+
+      fct_chk(isArgDouble(rpc_params["result"]));
+      fct_chk(isArgDouble(rpc_params["result"]) && 
rpc_params["result"].asDouble() == 0.1);
+    } FCT_TEST_END();
+
+    FCT_TEST_BGN(json_number_float_parse) {
+      string s = "{\"result\": 1.21}";
+      // DBG("s.c_str() %s\n", s.c_str() );
+      AmArg rpc_params;
+      fct_chk(json2arg(s.c_str(), rpc_params));
+      // DBG("res: %s, type %d\n",  
AmArg::print(rpc_params["result"]).c_str(), rpc_params["result"].getType());
+
+      fct_chk(isArgDouble(rpc_params["result"]));
+      fct_chk(isArgDouble(rpc_params["result"]) && 
rpc_params["result"].asDouble() == 1.21);
+    } FCT_TEST_END();
+
 } FCTMF_SUITE_END();

_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev

Reply via email to