diff --git a/bin/uce_fastcgi.debug.linux.bin b/bin/uce_fastcgi.debug.linux.bin index e292064..337d006 100755 Binary files a/bin/uce_fastcgi.debug.linux.bin and b/bin/uce_fastcgi.debug.linux.bin differ diff --git a/src/lib/datastructures.h b/src/lib/datastructures.h index ee606be..5163c4e 100644 --- a/src/lib/datastructures.h +++ b/src/lib/datastructures.h @@ -124,12 +124,12 @@ string html_escape(string s) string html_escape(u64 a) { - return(to_string(a)); + return(std::to_string(a)); } string html_escape(f64 a) { - return(to_string(a)); + return(std::to_string(a)); } u64 int_val(string s, u32 base = 10) @@ -153,3 +153,8 @@ string nibble(string div, string& haystack) return(result); } } + +string json_escape(string s) +{ + return(string("\"")+s+"\""); +} diff --git a/src/lib/dtree.h b/src/lib/dtree.h index ca4f004..2bd40d5 100644 --- a/src/lib/dtree.h +++ b/src/lib/dtree.h @@ -1,4 +1,6 @@ -struct DNode { +struct DTree; + +struct DTree { char type = 'S'; @@ -6,9 +8,30 @@ struct DNode { f64 _float; bool _bool; void* _ptr; - std::map _map; + std::map _map; - string get_string() + void each(std::function f) + { + switch(type) + { + case('M'): + for (auto it = _map.begin(); it != _map.end(); ++it) + { + f(it->second, it->first); + } + break; + default: + f(*this, ""); + break; + } + } + + bool is_array() + { + return(type == 'M'); + } + + string to_string() { switch(type) { @@ -16,58 +39,342 @@ struct DNode { return(_string); break; case('F'): - return(to_string(_float)); + return(std::to_string(_float)); break; case('B'): return(_bool ? "true" : "false"); break; case('M'): - return("array()"); + return("(array)"); break; case('P'): - return("pointer()"); + return(to_hex((u64)_ptr)); break; } } - string set_string(string s) + string to_json() + { + switch(type) + { + case('S'): + return(json_escape(_string)); + break; + case('F'): + return(std::to_string(_float)); + break; + case('B'): + return(_bool ? "true" : "false"); + break; + case('M'): + return("\"(array)\""); + break; + case('P'): + return("\"(pointer)\""); + break; + } + } + + string get_type_name() + { + switch(type) + { + case('S'): + return("string"); + break; + case('F'): + return("f64"); + break; + case('B'): + return("bool"); + break; + case('M'): + return("array"); + break; + case('P'): + return("pointer"); + break; + } + } + + void set(string s) { if(type == 'M') _map.clear(); type = 'S'; _string = s; } - string set_pointer(void* p) + void set(void* p) { if(type == 'M') _map.clear(); type = 'P'; _ptr = p; } - string set_float(f64 f) + void set(f64 f) { if(type == 'M') _map.clear(); type = 'F'; _float = f; } - string set_bool(bool b) + void set_bool(bool b) { if(type == 'M') _map.clear(); type = 'B'; _bool = b; } - DNode* set(string s) + DTree* key(string s) { type = 'M'; - auto child = _map[s]; - if(!child) - { - child = new DNode(); - _map[s] = child; - } - return(child); + return(&_map[s]); + } + + DTree& operator [] (string s) { + type = 'M'; + return(_map[s]); + } + + void operator = (string v) { set(v); } + void operator = (f64 v) { set(v); } + void operator = (void* v) { set(v); } + void operator = (DTree v) { *this = v; } + + void remove(string s) + { + type = 'M'; + _map.erase(s); + } + + void clear() + { + type = 'M'; + _map.clear(); } }; + +string to_string(DTree t) +{ + return(t.to_string()); +} + +string json_encode(DTree t) +{ + string result = ""; + if(t.is_array()) + { + result += "{"; + u32 count = 0; + t.each([&] (DTree item, string key) { + if(count > 0) + result += ", "; + count += 1; + result += json_escape(key) + ": " + json_encode(item); + }); + result += "}"; + } + else + { + result = t.to_json(); + } + return(result); +} + +// https://i.stack.imgur.com/SHLOB.gif +string json_decode_string(string s, u32& i) +{ + string result; + while(i < s.length()) + { + char c = s[i]; + if(c == '"') + { + i += 1; + return(result); + } + else if(c == '\\') + { + i += 1; + c = s[i]; + switch(c) + { + case('t'): + result.append('\t', 1); + break; + case('n'): + result.append('\n', 1); + break; + case('r'): + result.append('\r', 1); + break; + case('\\'): + result.append('\\', 1); + break; + case('b'): + result.append('\b', 1); + break; + case('f'): + result.append('\f', 1); + break; + case('u'): + // todo decode + break; + default: + result.append(c, 1); + break; + } + } + else + { + result.append(c, 1); + } + i += 1; + } + return(result); +} + +DTree json_decode_map(string s, u32& i); + +void json_consume_space(string s, u32& i) +{ + while(i < s.length() && isspace(s[i])) + i += 1; +} + +string json_decode_keyword(string s, u32& i) +{ + string result; + json_consume_space(s, i); + while(i < s.length()) + { + char c = s[i]; + if(isalnum(c)) + { + result.append(c, 1); + } + else + { + return(result); + } + i += 1; + } + return(result); +} + +string json_decode_number(string s, u32& i) +{ + string result; + json_consume_space(s, i); + while(i < s.length()) + { + char c = s[i]; + if(isdigit(c) || c == '.') + { + result.append(c, 1); + } + else + { + return(result); + } + i += 1; + } + return(result); +} + +DTree json_decode_value(string s, u32& i) +{ + DTree result; + string value = ""; + json_consume_space(s, i); + char c = s[i]; + result.set("CHAR_"); + result._string.append(to_string(c)); + return(result); + if(c == '"') // string value + { + result.type = 'S'; + i += 1; + result._string = json_decode_string(s, i); + return(result); + } + else if(isdigit(c)) + { + result.type = 'S'; + result._string = json_decode_number(s, i); + //result._float = stod(json_decode_number(s, i)); + return(result); + } + else if(c == '{') + { + i += 1; + return(json_decode_map(s, i)); + } + else + { + value = json_decode_keyword(s, i); + if(value == "true") + result.set_bool(true); + else if(value == "false") + result.set_bool(false); + else if(value == "null") + result.set(""); + return(result); + } + return(result); +} + +DTree json_decode_map(string s, u32& i) +{ + DTree result; + string key = ""; + while(i < s.length()) + { + json_consume_space(s, i); + char c = s[i]; + if(c == '}') + { + return(result); + } + else if(c == ',') + { + + } + else if(c == '"') + { + i += 1; + key = json_decode_string(s, i); + json_consume_space(s, i); + if(s[i] != ':') + return(result); // malformed + result[key] = json_decode_value(s, i); + } + else + { + // malformed + return(result); + } + i += 1; + } + return(result); +} + +DTree json_decode(string s) +{ + u32 i = 0; + return(json_decode_value(s, i)); +} + +string var_dump(DTree map, string prefix = "", string postfix = "\n") +{ + string result = ""; + if(!map.is_array()) + return(map.to_string()); + map.each([&] (DTree item, string key) { + result += prefix + key + ": " + item.to_string() + postfix; + if(item.is_array()) + result += var_dump(item, prefix + "\t"); + }); + return(result); +} diff --git a/src/lib/time.h b/src/lib/time.h index b9f5fa2..17ed08e 100644 --- a/src/lib/time.h +++ b/src/lib/time.h @@ -14,7 +14,7 @@ string date(string format = "", u64 timestamp = 0) string ts; string fmt; if(timestamp > 0) - ts = string("-d '@")+to_string(timestamp)+"'"; + ts = string("-d '@")+std::to_string(timestamp)+"'"; if(format != "") fmt = string("+'"+format+"'"); return(trim(shell_exec("date "+ts+" "+fmt))); @@ -25,7 +25,7 @@ string gmdate(string format = "", u64 timestamp = 0) string ts; string fmt; if(timestamp > 0) - ts = string("-d '@")+to_string(timestamp)+"'"; + ts = string("-d '@")+std::to_string(timestamp)+"'"; if(format == "RFC1123") format = "%a, %d %b %Y %T GMT"; if(format != "") diff --git a/src/lib/types.h b/src/lib/types.h index c166c52..59bd5d7 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -11,6 +11,10 @@ #include #include #include +#include +#include +#include +#include typedef std::string string; @@ -28,7 +32,7 @@ typedef double f64; typedef unsigned long long u64; typedef long long s64; -#define to_string(a) std::to_string(a) +//#define to_string(a) std::to_string(a) #define echo(s) context->print(s) typedef std::map StringMap; @@ -41,6 +45,10 @@ struct Request; typedef void (*call_handler)(); typedef void (*request_handler)(Request* request); +string to_string(u64 v) { return(std::to_string(v)); } +string to_string(s64 v) { return(std::to_string(v)); } +string to_string(f64 v) { return(std::to_string(v)); } + struct ServerSettings { string BIN_DIRECTORY = "work"; @@ -85,8 +93,6 @@ struct SharedUnit { } }; -#include "dtree.h" - struct UploadedFile { string file_name; string tmp_name; diff --git a/src/lib/uce_gen.h b/src/lib/uce_gen.h index aa70ca2..a011535 100644 --- a/src/lib/uce_gen.h +++ b/src/lib/uce_gen.h @@ -2,6 +2,7 @@ #include "types.h" #include "datastructures.h" +#include "dtree.h" #include "sys.h" #include "time.h" diff --git a/src/lib/uri.h b/src/lib/uri.h index 48bc3d6..45252d8 100644 --- a/src/lib/uri.h +++ b/src/lib/uri.h @@ -120,7 +120,7 @@ StringMap parse_multipart(string q, string boundary, std::vector& { nibble("=\"", field); UploadedFile f; - f.tmp_name = context->server_state->config.TMP_UPLOAD_PATH + to_string(rand()); + f.tmp_name = context->server_state->config.TMP_UPLOAD_PATH + std::to_string(rand()); f.file_name = nibble("\"", field); string bin = field.substr(4, field.length()-6); f.size = bin.length(); diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index 6ddac76..aa85fbc 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -1,7 +1,3 @@ -#include -#include -#include - #include "lib/uce_gen.h" #include "fastcgi/src/fcgicc.cc" diff --git a/test/index.uce b/test/index.uce index c162ed6..fc97e3d 100644 --- a/test/index.uce +++ b/test/index.uce @@ -17,6 +17,8 @@ RENDER()
  • URI
  • Cookies
  • Session
  • +
  • DTree
  • +
  • JSON
  • params) ?>
    diff --git a/test/style.css b/test/style.css index 28a4d56..e403301 100644 --- a/test/style.css +++ b/test/style.css @@ -69,4 +69,5 @@ pre { border: 2px solid rgba(0,0,0,0.2); background: rgba(100,100,100,0.15); font-family: monospace; + white-space: pre-wrap; } diff --git a/todo.txt b/todo.txt index fdf1010..4dcc579 100644 --- a/todo.txt +++ b/todo.txt @@ -20,8 +20,7 @@ Bugs Framework ================================= -- DTree< -- File Upload +- Check: File Upload - Proxy mode - WebSockets - Persistent code / Cron / Tick?