#pragma once #include #include #include #include #include // ---------------------------------------------------------------------------- // qs_parse (modified) // https://github.com/bartgrantham/qs_parse // ---------------------------------------------------------------------------- /* Similar to strncmp, but handles URL-encoding for either string */ int qs_strncmp(const char * s, const char * qs, size_t n); /* Finds the beginning of each key/value pair and stores a pointer in qs_kv. * Also decodes the value portion of the k/v pair *in-place*. In a future * enhancement it will also have a compile-time option of sorting qs_kv * alphabetically by key. */ int qs_parse(char * qs, char * qs_kv[], int qs_kv_size); /* Used by qs_parse to decode the value portion of a k/v pair */ int qs_decode(char * qs); /* Looks up the value according to the key on a pre-processed query string * A future enhancement will be a compile-time option to look up the key * in a pre-sorted qs_kv array via a binary search. */ //char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth); /* Non-destructive lookup of value, based on key. User provides the * destinaton string and length. */ char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len); // TODO: implement sorting of the qs_kv array; for now ensure it's not compiled #undef _qsSORTING // isxdigit _is_ available in , but let's avoid another header instead #define CROW_QS_ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0) #define CROW_QS_HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) #define CROW_QS_ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) inline int qs_strncmp(const char * s, const char * qs, size_t n) { int i=0; unsigned char u1, u2, unyb, lnyb; while(n-- > 0) { u1 = (unsigned char) *s++; u2 = (unsigned char) *qs++; if ( ! CROW_QS_ISQSCHR(u1) ) { u1 = '\0'; } if ( ! CROW_QS_ISQSCHR(u2) ) { u2 = '\0'; } if ( u1 == '+' ) { u1 = ' '; } if ( u1 == '%' ) // easier/safer than scanf { unyb = (unsigned char) *s++; lnyb = (unsigned char) *s++; if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) u1 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); else u1 = '\0'; } if ( u2 == '+' ) { u2 = ' '; } if ( u2 == '%' ) // easier/safer than scanf { unyb = (unsigned char) *qs++; lnyb = (unsigned char) *qs++; if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) u2 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); else u2 = '\0'; } if ( u1 != u2 ) return u1 - u2; if ( u1 == '\0' ) return 0; i++; } if ( CROW_QS_ISQSCHR(*qs) ) return -1; else return 0; } inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) { int i, j; char * substr_ptr; for(i=0; i means x iterations of this loop -> means *x+1* k/v pairs // we only decode the values in place, the keys could have '='s in them // which will hose our ability to distinguish keys from values later for(j=0; j get_list (const std::string& name) const { std::vector ret; std::string plus = name + "[]"; char* element = nullptr; int count = 0; while(1) { element = qs_k2v(plus.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++); if (!element) break; ret.push_back(element); } return ret; } private: std::string url_; std::vector key_value_pairs_; }; } // end namespace #pragma once #include #include #include #include #include #include namespace crow { namespace black_magic { #ifndef CROW_MSVC_WORKAROUND struct OutOfRange { OutOfRange(unsigned pos, unsigned length) {} }; constexpr unsigned requires_in_range( unsigned i, unsigned len ) { return i >= len ? throw OutOfRange(i, len) : i; } class const_str { const char * const begin_; unsigned size_; public: template< unsigned N > constexpr const_str( const char(&arr)[N] ) : begin_(arr), size_(N - 1) { static_assert( N >= 1, "not a string literal"); } constexpr char operator[]( unsigned i ) const { return requires_in_range(i, size_), begin_[i]; } constexpr operator const char *() const { return begin_; } constexpr const char* begin() const { return begin_; } constexpr const char* end() const { return begin_ + size_; } constexpr unsigned size() const { return size_; } }; constexpr unsigned find_closing_tag(const_str s, unsigned p) { return s[p] == '>' ? p : find_closing_tag(s, p+1); } constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) { return i == s.size() ? f == 0 : f < 0 || f >= 2 ? false : s[i] == '<' ? is_valid(s, i+1, f+1) : s[i] == '>' ? is_valid(s, i+1, f-1) : is_valid(s, i+1, f); } constexpr bool is_equ_p(const char* a, const char* b, unsigned n) { return *a == 0 && *b == 0 && n == 0 ? true : (*a == 0 || *b == 0) ? false : n == 0 ? true : *a != *b ? false : is_equ_p(a+1, b+1, n-1); } constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) { return ai + n > a.size() || bi + n > b.size() ? false : n == 0 ? true : a[ai] != b[bi] ? false : is_equ_n(a,ai+1,b,bi+1,n-1); } constexpr bool is_int(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 5); } constexpr bool is_uint(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 6); } constexpr bool is_float(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 7) || is_equ_n(s, i, "", 0, 8); } constexpr bool is_str(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 5) || is_equ_n(s, i, "", 0, 8); } constexpr bool is_path(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 6); } #endif template struct parameter_tag { static const int value = 0; }; #define CROW_INTERNAL_PARAMETER_TAG(t, i) \ template <> \ struct parameter_tag \ { \ static const int value = i; \ }; CROW_INTERNAL_PARAMETER_TAG(int, 1); CROW_INTERNAL_PARAMETER_TAG(char, 1); CROW_INTERNAL_PARAMETER_TAG(short, 1); CROW_INTERNAL_PARAMETER_TAG(long, 1); CROW_INTERNAL_PARAMETER_TAG(long long, 1); CROW_INTERNAL_PARAMETER_TAG(unsigned int, 2); CROW_INTERNAL_PARAMETER_TAG(unsigned char, 2); CROW_INTERNAL_PARAMETER_TAG(unsigned short, 2); CROW_INTERNAL_PARAMETER_TAG(unsigned long, 2); CROW_INTERNAL_PARAMETER_TAG(unsigned long long, 2); CROW_INTERNAL_PARAMETER_TAG(double, 3); CROW_INTERNAL_PARAMETER_TAG(std::string, 4); #undef CROW_INTERNAL_PARAMETER_TAG template struct compute_parameter_tag_from_args_list; template <> struct compute_parameter_tag_from_args_list<> { static const int value = 0; }; template struct compute_parameter_tag_from_args_list { static const int sub_value = compute_parameter_tag_from_args_list::value; static const int value = parameter_tag::type>::value ? sub_value* 6 + parameter_tag::type>::value : sub_value; }; static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) { if (a == 0) return b == 0; if (b == 0) return a == 0; int sa = a%6; int sb = a%6; if (sa == 5) sa = 4; if (sb == 5) sb = 4; if (sa != sb) return false; return is_parameter_tag_compatible(a/6, b/6); } static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) { return s[p] == 0 ? throw std::runtime_error("unmatched tag <") : s[p] == '>' ? p : find_closing_tag_runtime(s, p + 1); } static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) { return s[p] == 0 ? 0 : s[p] == '<' ? ( std::strncmp(s+p, "", 5) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : std::strncmp(s+p, "", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : (std::strncmp(s+p, "", 7) == 0 || std::strncmp(s+p, "", 8) == 0) ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : (std::strncmp(s+p, "", 5) == 0 || std::strncmp(s+p, "", 8) == 0) ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : std::strncmp(s+p, "", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : throw std::runtime_error("invalid parameter type") ) : get_parameter_tag_runtime(s, p+1); } #ifndef CROW_MSVC_WORKAROUND constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) { return p == s.size() ? 0 : s[p] == '<' ? ( is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : is_path(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : throw std::runtime_error("invalid parameter type") ) : get_parameter_tag(s, p+1); } #endif template struct S { template using push = S; template using push_back = S; template class U> using rebind = U; }; template struct CallHelper; template struct CallHelper> { template ()(std::declval()...)) > static char __test(int); template static int __test(...); static constexpr bool value = sizeof(__test(0)) == sizeof(char); }; template struct single_tag_to_type { }; template <> struct single_tag_to_type<1> { using type = int64_t; }; template <> struct single_tag_to_type<2> { using type = uint64_t; }; template <> struct single_tag_to_type<3> { using type = double; }; template <> struct single_tag_to_type<4> { using type = std::string; }; template <> struct single_tag_to_type<5> { using type = std::string; }; template struct arguments { using subarguments = typename arguments::type; using type = typename subarguments::template push::type>; }; template <> struct arguments<0> { using type = S<>; }; template struct last_element_type { using type = typename std::tuple_element>::type; }; template <> struct last_element_type<> { }; // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth template using Invoke = typename T::type; template struct seq{ using type = seq; }; template struct concat; template struct concat, seq> : seq{}; template using Concat = Invoke>; template struct gen_seq; template using GenSeq = Invoke>; template struct gen_seq : Concat, GenSeq>{}; template<> struct gen_seq<0> : seq<>{}; template<> struct gen_seq<1> : seq<0>{}; template struct pop_back_helper; template struct pop_back_helper, Tuple> { template