diff --git a/Makefile.am b/Makefile.am index 50dc6854..4065c0d2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -71,6 +71,7 @@ cleandist: $(distdir)/tests/ulib/tmp/* \ $(distdir)/tests/ulib/private/* \ $(distdir)/tests/ulib/CApath/*.*0 \ + $(distdir)/tests/ulib/ok/json.ok \ $(distdir)/tests/ulib/ok/timer.ok \ $(distdir)/tests/ulib/ok/socket.ok \ $(distdir)/tests/ulib/ok/interrupt.ok \ diff --git a/Makefile.in b/Makefile.in index f23d4acc..eb53b20e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1008,6 +1008,7 @@ cleandist: $(distdir)/tests/ulib/tmp/* \ $(distdir)/tests/ulib/private/* \ $(distdir)/tests/ulib/CApath/*.*0 \ + $(distdir)/tests/ulib/ok/json.ok \ $(distdir)/tests/ulib/ok/timer.ok \ $(distdir)/tests/ulib/ok/socket.ok \ $(distdir)/tests/ulib/ok/interrupt.ok \ diff --git a/configure b/configure index 4937405b..ba4bcac8 100755 --- a/configure +++ b/configure @@ -27597,11 +27597,17 @@ $as_echo "yes" >&6; } $as_echo "#define USE_LIBCURL 1" >>confdefs.h - libcurl_version=$($curldir/bin/curl-config --version 2>/dev/null | sed -e "s/libcurl //g") + if test x_$PKG_CONFIG != x_no; then + libcurl_version=$(pkg-config --modversion libcurl) + fi + if test -z "${libcurl_version}"; then + libcurl_version=$($curldir/bin/curl-config --version 2>/dev/null | sed -e "s/libcurl //g") + fi if test -z "${libcurl_version}"; then libcurl_version="unknown" fi - ULIB_LIBS="-lcurl $ULIB_LIBS"; + libcurl_linking=$($curldir/bin/curl-config --libs 2>/dev/null) + ULIB_LIBS="$libcurl_linking $ULIB_LIBS"; if test $curldir != "${CROSS_ENVIRONMENT}/" -a $curldir != "${CROSS_ENVIRONMENT}/usr" -a $curldir != "${CROSS_ENVIRONMENT}/usr/local"; then CPPFLAGS="$CPPFLAGS -I$curldir/include"; LDFLAGS="$LDFLAGS -L$curldir/lib -Wl,-R$curldir/lib"; diff --git a/examples/PEC_log/PEC_report.cpp b/examples/PEC_log/PEC_report.cpp index 709ea78c..b088ea29 100644 --- a/examples/PEC_log/PEC_report.cpp +++ b/examples/PEC_log/PEC_report.cpp @@ -1204,7 +1204,7 @@ void PEC_report::loadFiles() dirwalk.walk(); - u_printSize(buffer, bytes); + (void) u_printSize(buffer, bytes); U_MESSAGE("checked %u file(s) - skipped %u file(s)\n" "start processing %u file(s) for %s of data...", nfiles, nskipped, tfile->size(), buffer); diff --git a/include/ulib/base/apex/apex_memmove.h b/include/ulib/base/apex/apex_memmove.h index de6bc273..239e6e5c 100644 --- a/include/ulib/base/apex/apex_memmove.h +++ b/include/ulib/base/apex/apex_memmove.h @@ -13,7 +13,8 @@ extern U_EXPORT pvPFpvpvs apex_memmove; * apex_memmove written by Trevor Herselman in 2014 * * FORCE `CDECL` calling convention on 32-bit builds on our function pointers, because we need it to match the original `std::memmove` definition; - * in-case the user specified a different default function calling convention! (I specified __fastcall as my default calling convention and got errors! So I needed to add this!) + * in-case the user specified a different default function calling convention! (I specified __fastcall as my default calling convention and got errors! + * So I needed to add this!) */ U_EXPORT void apex_memmove_dispatcher(void); diff --git a/include/ulib/base/base.h b/include/ulib/base/base.h index b7160cbb..4afd3601 100644 --- a/include/ulib/base/base.h +++ b/include/ulib/base/base.h @@ -148,6 +148,7 @@ typedef bool (*bPFpcpv) (const char*,const void*); typedef void (*vPFpvpc) (void*,char*); typedef void (*vPFpvpv) (void*,void*); +typedef uint32_t (*uPFdpc) (double,char*); typedef uint32_t (*uPFu32pc) (uint32_t,char*); typedef uint32_t (*uPFu64pc) (uint64_t,char*); @@ -264,43 +265,6 @@ U_EXPORT const char* u_basename(const char* restrict path) __pure; U_EXPORT const char* u_getsuffix(const char* restrict path, uint32_t len) __pure; U_EXPORT bool u_is_overlap(const char* restrict dst, const char* restrict src, size_t n); -/* conversion number to string */ -extern U_EXPORT uPFu32pc u_num2str32; -extern U_EXPORT uPFu64pc u_num2str64; -extern U_EXPORT const char u_ctn2s[200]; - -static inline uint32_t u_num2str32s(int32_t num, char* restrict cp) -{ - uint32_t bsign = (num < 0); - - U_INTERNAL_TRACE("u_num2str32s(%u,%p)", num, cp) - - if (bsign) - { - num = -num; - - *cp++ = '-'; - } - - return bsign + u_num2str32(num, cp); -} - -static inline uint32_t u_num2str64s(int64_t num, char* restrict cp) -{ - uint32_t bsign = (num < 0LL); - - U_INTERNAL_TRACE("u_num2str64s(%lld,%p)", num, cp) - - if (bsign) - { - num = -num; - - *cp++ = '-'; - } - - return bsign + u_num2str64(num, cp); -} - /* Location info */ extern U_EXPORT uint32_t u_num_line; extern U_EXPORT const char* restrict u_name_file; @@ -479,6 +443,69 @@ static inline void u_gettimenow(void) #endif */ +/* conversion number to string */ +extern U_EXPORT uPFdpc u_dbl2str; +extern U_EXPORT uPFu32pc u_num2str32; +extern U_EXPORT uPFu64pc u_num2str64; +extern U_EXPORT const char u_ctn2s[200]; + +static inline uint32_t u_num2str32s(int32_t num, char* restrict cp) +{ + uint32_t bsign = (num < 0); + + U_INTERNAL_TRACE("u_num2str32s(%u,%p)", num, cp) + + if (bsign) + { + num = -num; + + *cp++ = '-'; + } + + return bsign + u_num2str32(num, cp); +} + +static inline uint32_t u_num2str64s(int64_t num, char* restrict cp) +{ + uint32_t bsign = (num < 0); + + U_INTERNAL_TRACE("u_num2str64s(%lld,%p)", num, cp) + + if (bsign) + { + num = -num; + + *cp++ = '-'; + } + + return bsign + u_num2str64(num, cp); +} + +static inline uint32_t u_dtoa(double num, char* restrict cp) +{ + uint32_t bsign; + + U_INTERNAL_TRACE("u_dtoa(%g,%p)", num, cp) + + if (num == 0) + { + u_put_unalignedp32(cp, U_MULTICHAR_CONSTANT32('0','.','0','\0')); + + return 3; + } + + bsign = (num < 0); + + if (bsign) + { + num = -num; + + *cp++ = '-'; + } + + return bsign + u_dbl2str(num, cp); +} + #ifdef __cplusplus } #endif diff --git a/include/ulib/base/hash.h b/include/ulib/base/hash.h index 7a720db2..65989c8d 100644 --- a/include/ulib/base/hash.h +++ b/include/ulib/base/hash.h @@ -61,10 +61,10 @@ static inline uint32_t u_xxhash64(const unsigned char* restrict t, uint32_t tlen #ifdef USE_HARDWARE_CRC32 static inline uint32_t u_crc32(const unsigned char* restrict bp, uint32_t len) { - U_INTERNAL_TRACE("u_crc32(%.*s,%u)", U_min(len,128), bp, len) - uint32_t h1 = 0xABAD1DEA; + U_INTERNAL_TRACE("u_crc32(%.*s,%u)", U_min(len,128), bp, len) + # ifdef HAVE_ARCH64 while (len >= sizeof(uint64_t)) { diff --git a/include/ulib/base/macro.h b/include/ulib/base/macro.h index 7d8eeb6a..7912b60b 100644 --- a/include/ulib/base/macro.h +++ b/include/ulib/base/macro.h @@ -28,7 +28,7 @@ #ifdef DEBUG_DEBUG # define U_INTERNAL_TRACE(format,args...) u_internal_print(false, format"\n" , ##args); -# define U_INTERNAL_PRINT(format,args...) U_INTERNAL_TRACE(format,args) +# define U_INTERNAL_PRINT(format,args...) u_internal_print(false, format"\n" , ##args); #else # define U_INTERNAL_TRACE(format,args...) # define U_INTERNAL_PRINT(format,args...) diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index 26a1cd77..dbe30e12 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -147,7 +147,7 @@ U_EXPORT uint32_t u_memory_dump(char* restrict bp, unsigned char* restrict cp, u U_EXPORT int u_getScreenWidth(void) __pure; /* Determine the width of the terminal we're running on */ U_EXPORT bool u_isNumber(const char* restrict s, uint32_t n) __pure; -U_EXPORT void u_printSize(char* restrict buffer, uint64_t bytes); /* print size using u_calcRate() */ +U_EXPORT uint32_t u_printSize(char* restrict buffer, uint64_t bytes); /* print size using u_calcRate() */ U_EXPORT bool u_rmatch(const char* restrict haystack, uint32_t haystack_len, const char* restrict needle, uint32_t needle_len) __pure; U_EXPORT const char* u_get_mimetype(const char* restrict suffix, int* pmime_index); @@ -518,9 +518,13 @@ static inline unsigned long u_strtoul(const char* restrict s, const char* restri U_INTERNAL_ASSERT_POINTER(s) U_INTERNAL_ASSERT_POINTER(e) - U_INTERNAL_ASSERT(u__isdigit(*s)) - for (c = *s; s != e; c = *++s) val = (c - '0') + (val * 10UL); + for (c = *s; s != e; c = *++s) + { + U_INTERNAL_ASSERT(u__isdigit(*s)) + + val = (c - '0') + (val * 10UL); + } return val; } @@ -534,9 +538,13 @@ static inline uint64_t u_strtoull(const char* restrict s, const char* restrict e U_INTERNAL_ASSERT_POINTER(s) U_INTERNAL_ASSERT_POINTER(e) - U_INTERNAL_ASSERT(u__isdigit(*s)) - for (c = *s; s != e; c = *++s) val = (c - '0') + (val * 10ULL); + for (c = *s; s != e; c = *++s) + { + U_INTERNAL_ASSERT(u__isdigit(*s)) + + val = (c - '0') + (val * 10ULL); + } return val; } diff --git a/include/ulib/examples/wi_auth_declaration.h b/include/ulib/examples/wi_auth_declaration.h index 619f5b9a..1bb5a90e 100644 --- a/include/ulib/examples/wi_auth_declaration.h +++ b/include/ulib/examples/wi_auth_declaration.h @@ -509,6 +509,38 @@ private: WiAuthVirtualAccessPoint& operator=(const WiAuthVirtualAccessPoint&) { return *this; } }; +static uint32_t findAnagrafica(const UString& _ip) +{ + U_TRACE(5, "::findAnagrafica(%V)", _ip.rep) + + uint32_t pos = 0; + + /** + * 10.8.0.156 172.16.156.0/24 111 + * 159.213.248.233,172.25.0.0/22,213 + */ + +loop: + pos = db_anagrafica->find(_ip, pos); + + U_INTERNAL_DUMP("pos = %u", pos) + + if (pos != U_NOT_FOUND) + { + pos += _ip.size(); + + char c = db_anagrafica->c_char(pos); + + if (c != ',' && + u__isspace(c) == false) + { + goto loop; + } + } + + U_RETURN(pos); +} + class WiAuthNodog : public UDataStorage { public: @@ -868,7 +900,7 @@ public: U_INTERNAL_ASSERT(*ap_address) int op = -1; - WiAuthAccessPoint* p; + uint32_t pos; if (ap_label->empty()) (void) ap_label->assign(U_CONSTANT_TO_PARAM("ap")); @@ -907,53 +939,51 @@ public: { if (ap_address_trust == false) U_RETURN(false); + sz = 0; op = RDB_INSERT; port = _port; status = 0; hostname = (*ap_hostname ? *ap_hostname : U_STRING_FROM_CONSTANT("hostname_empty")); - last_info = since = start = u_now->tv_sec; - - sz = 1; - index_access_point = 0; + start = + since = + last_info = u_now->tv_sec; vec_access_point.clear(); - U_NEW(WiAuthAccessPoint, p, WiAuthAccessPoint(*ap_label)); - - vec_access_point.push_back(p); - - if (db_anagrafica) + if (db_anagrafica == 0 || + (pos = findAnagrafica(*ap_address), pos == U_NOT_FOUND)) { - /** - * 10.8.0.156 172.16.156.0/24 111 - * 159.213.248.233 172.25.0.0/22 213 - */ + addAccessPoint(); + } + else + { + bool bcsv = (db_anagrafica->c_char(pos) == ','); - uint32_t pos = db_anagrafica->find(*ap_address); + U_INTERNAL_DUMP("bcsv = %b", bcsv) - U_INTERNAL_DUMP("pos = %d", pos) + UString netmask; + UTokenizer tok(db_anagrafica->substr(pos)); - if (pos != U_NOT_FOUND) + if (bcsv) tok.setDelimiter(",\n"); + + (void) tok.next(netmask, (bool*)0); + (void) tok.next(*ap_label, (bool*)0); + + U_INTERNAL_ASSERT(netmask) + U_INTERNAL_ASSERT(*ap_label) + + addAccessPoint(); + + while (tok.next(*ip, (bool*)0) && + ap_address->equal(*ip)) { - pos += ap_address->size(); + (void) tok.next(netmask, (bool*)0); + (void) tok.next(*ap_label, (bool*)0); - while (u__islterm(db_anagrafica->c_char(pos)) == false) ++pos; + U_INTERNAL_ASSERT(netmask) + U_INTERNAL_ASSERT(*ap_label) - UTokenizer tok(db_anagrafica->substr(pos)); - - while (tok.next(*ip, (bool*)0) && - ap_address->equal(*ip)) - { - UString netmask, label; - - (void) tok.next(netmask, (bool*)0); - (void) tok.next(*ap_label, (bool*)0); - - U_INTERNAL_ASSERT(netmask) - U_INTERNAL_ASSERT(*ap_label) - - addAccessPoint(); - } + addAccessPoint(); } } } @@ -1179,14 +1209,45 @@ public: } } + void writeToLOG(const char* op) + { + U_TRACE(5, "WiAuthUser::writeToLOG(%S)", op) + + U_INTERNAL_ASSERT_POINTER(op) + + getDone(); + + /** + * Example + * ----------------------------------------------------------------------------------------------------------------------------------------------------------------- + * 2012/08/08 14:56:00 op: PASS_AUTH, uid: 33437934, ap: 00@10.8.1.2, ip: 172.16.1.172, mac: 00:14:a5:6e:9c:cb, time: 233, traffic: 342, policy: DAILY consume: true + * ----------------------------------------------------------------------------------------------------------------------------------------------------------------- + */ + + U_INTERNAL_ASSERT(_mac) + U_INTERNAL_ASSERT(*time_done) + U_INTERNAL_ASSERT(*traffic_done) + + ULog::log(file_LOG->getFd(), "op: %s, uid: %v, ap: %v, ip: %v, mac: %v, time: %v, traffic: %v, policy: %v", + op, uid->rep, getAP().rep, _ip.rep, _mac.rep, time_done->rep, traffic_done->rep, getPolicy().rep); + } + const char* updateCounter(const UString& logout, long time_connected, uint64_t traffic, bool& ask_logout) { U_TRACE(5, "WiAuthUser::updateCounter(%V,%ld,%llu,%b)", logout.rep, time_connected, traffic, ask_logout) const char* write_to_log = 0; - _time_done += time_connected; - _traffic_done += traffic; + uint32_t time_done_save = _time_done; + uint64_t traffic_done_save = _traffic_done; + + _time_done = time_connected; + _traffic_done = traffic; + + writeToLOG("INFO"); + + _time_done += time_done_save; + _traffic_done += traffic_done_save; if (consume) { @@ -1575,29 +1636,6 @@ next: if (op == RDB_REPLACE) (void) db_user->putDataStorage( *uid); else (void) db_user->insertDataStorage(*uid); } - - void writeToLOG(const char* op) - { - U_TRACE(5, "WiAuthUser::writeToLOG(%S)", op) - - U_INTERNAL_ASSERT_POINTER(op) - - getDone(); - - /** - * Example - * ----------------------------------------------------------------------------------------------------------------------------------------------------------------- - * 2012/08/08 14:56:00 op: PASS_AUTH, uid: 33437934, ap: 00@10.8.1.2, ip: 172.16.1.172, mac: 00:14:a5:6e:9c:cb, time: 233, traffic: 342, policy: DAILY consume: true - * ----------------------------------------------------------------------------------------------------------------------------------------------------------------- - */ - - U_INTERNAL_ASSERT(_mac) - U_INTERNAL_ASSERT(*time_done) - U_INTERNAL_ASSERT(*traffic_done) - - ULog::log(file_LOG->getFd(), "op: %s, uid: %v, ap: %v, ip: %v, mac: %v, time: %v, traffic: %v, policy: %v", - op, uid->rep, getAP().rep, _ip.rep, _mac.rep, time_done->rep, traffic_done->rep, getPolicy().rep); - } }; static UString getUserName() @@ -1934,16 +1972,7 @@ static int checkForUserPolicy(UStringRep* key, UStringRep* data) { *uid = db_user->getKeyID(); - if (user_rec->connected) - { - uint64_t traffic = user_rec->_traffic_done / (1024ULL * 1024ULL); - - if (traffic) - { - U_LOGGER("*** checkForUserPolicy() UID(%v) IP(%v) MAC(%v) AP(%v) POLICY(%v) traffic: %llu ***", - uid->rep, user_rec->_ip.rep, user_rec->_mac.rep, user_rec->nodog.rep, user_rec->_policy.rep, traffic); - } - } + if (user_rec->connected) user_rec->writeToLOG("RST_POLICY"); user_rec->_time_done = user_rec->_time_consumed = 0; @@ -3291,7 +3320,7 @@ static bool checkTimeRequest() } else { - ko = (ts->empty() && db_anagrafica); + ko = ts->empty(); if (ko) { @@ -4498,30 +4527,53 @@ static void GET_get_config() if (db_anagrafica) { - /** - * 10.8.0.156 172.16.156.0/24 111 - * 159.213.248.233 172.25.0.0/22 213 - */ - - pos = db_anagrafica->find(*ip); - - U_INTERNAL_DUMP("pos = %d", pos) + pos = findAnagrafica(*ip); if (pos != U_NOT_FOUND) { - pos += ip->size(); + bool bcsv = (db_anagrafica->c_char(pos) == ','); - while (u__isspace(db_anagrafica->c_char(pos)) == false) ++pos; + U_INTERNAL_DUMP("bcsv = %b", bcsv) UString netmask, label; UTokenizer tok(db_anagrafica->substr(pos)); + if (bcsv) tok.setDelimiter(",\n"); + (void) tok.next(netmask, (bool*)0); (void) tok.next( label, (bool*)0); U_INTERNAL_ASSERT(label) U_INTERNAL_ASSERT(netmask) + if (bcsv) + { + UString _ip; + UVector vnetmask, vlabel; + + vlabel.push(label); + vnetmask.push(netmask); + + while (tok.next(_ip, (bool*)0) && + ip->equal(_ip)) + { + (void) tok.next(netmask, (bool*)0); + (void) tok.next( label, (bool*)0); + + U_INTERNAL_ASSERT(label) + U_INTERNAL_ASSERT(netmask) + + vlabel.push(label); + vnetmask.push(netmask); + } + + if (vlabel.size() > 1) + { + label = vlabel.join(' '); + netmask = vnetmask.join(' '); + } + } + _body = UStringExt::substitute(_body, U_CONSTANT_TO_PARAM("172...0/24"), U_STRING_TO_PARAM(netmask)); buffer.snprintf("LOCAL_NETWORK_LABEL \"%v\"", label.rep); diff --git a/include/ulib/utility/dtoa_milo.h b/include/ulib/utility/dtoa_milo.h new file mode 100644 index 00000000..67d8843a --- /dev/null +++ b/include/ulib/utility/dtoa_milo.h @@ -0,0 +1,397 @@ +// https://github.com/amdn/dtoa-benchmark + +#pragma once +#include +#include + +#if defined(_MSC_VER) +#include "msinttypes/stdint.h" +#include +#else +#include +#endif + +#define UINT64_C2(h, l) ((static_cast(h) << 32) | static_cast(l)) + +struct DiyFp { + DiyFp() {} + + DiyFp(uint64_t _f, int _e) : f(_f), e(_e) {} + + DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize; + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp& rhs) const { + assert(e == rhs.e); + assert(f >= rhs.f); + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp& rhs) const { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + unsigned __int128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = p >> 64; + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#elif defined(__GNUC__) + int s = __builtin_clzll(f); + return DiyFp(f << s, e - s); +#else + DiyFp res = *this; + while (!(res.f & kDpHiddenBit)) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 1); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1); + return res; +#endif + } + + DiyFp NormalizeBoundary() const { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp (f << (63 - index), e - (63 - index)); +#else + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; +#endif + } + + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMinExponent = -kDpExponentBias; + static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; +}; + +inline DiyFp GetCachedPower(int e, int* K) { + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76), + UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea), + UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df), + UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f), + UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c), + UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5), + UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d), + UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637), + UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7), + UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5), + UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b), + UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996), + UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8), + UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053), + UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd), + UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94), + UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b), + UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac), + UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3), + UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb), + UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c), + UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000), + UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984), + UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70), + UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245), + UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8), + UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a), + UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea), + UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85), + UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2), + UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3), + UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25), + UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece), + UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5), + UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a), + UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a), + UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129), + UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429), + UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d), + UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841), + UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9), + UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (k != dk) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0])); + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} + +inline unsigned CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + if (n < 1000000000) return 9; + return 10; +} + +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = static_cast(CountDecimalDigit32(p1)); + *len = 0; + + while (kappa > 0) { + uint32_t d; + switch (kappa) { + case 10: d = p1 / 1000000000; p1 %= 1000000000; break; + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default: +#if defined(_MSC_VER) + __assume(0); +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + __builtin_unreachable(); +#else + d = 0; +#endif + } + if (d || *len) + buffer[(*len)++] = '0' + static_cast(d); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = '0' + d; + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); + return; + } + } +} + +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} + +inline const char* GetDigitsLut() { + static const char cDigitsLut[200] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', + '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', + '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', + '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', + '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', + '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', + '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', + '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', + '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' + }; + return cDigitsLut; +} + +inline uint32_t WriteExponent(int K, char* buffer) { + char* start = buffer; + + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = '0' + static_cast(K / 100); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = '0' + static_cast(K); + + return buffer - start; +} + +inline uint32_t Prettify(char* buffer, int length, int k) +{ + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (length <= kk && kk <= 21) + { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) buffer[i] = '0'; + + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + + return kk + 2; + } + + if (0 < kk && kk <= 21) + { + // 1234e-2 -> 12.34 + memmove(&buffer[kk + 1], &buffer[kk], length - kk); + + buffer[kk] = '.'; + + return length + 1; + } + + if (-6 < kk && kk <= 0) + { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + memmove(&buffer[offset], &buffer[0], length); + + buffer[0] = '0'; + buffer[1] = '.'; + + for (int i = 2; i < offset; i++) buffer[i] = '0'; + + return length + offset; + } + + if (length == 1) + { + // 1e30 + buffer[1] = 'e'; + + return 2 + WriteExponent(kk - 1, &buffer[2]); + } + + // 1234e30 -> 1.234e33 + memmove(&buffer[2], &buffer[1], length - 1); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + + return length + 2 + WriteExponent(kk - 1, &buffer[0 + length + 2]); +} diff --git a/include/ulib/utility/string_ext.h b/include/ulib/utility/string_ext.h index f3942f0c..a7d61f2f 100644 --- a/include/ulib/utility/string_ext.h +++ b/include/ulib/utility/string_ext.h @@ -81,22 +81,9 @@ public: { U_TRACE(0, "UStringExt::printSize(%I)", n) - UString x(22U); - - u_printSize(x.data(), n); - - x.size_adjust(); - - U_RETURN_STRING(x); - } - - static UString numberToString(double n) - { - U_TRACE(0, "UStringExt::numberToString(%f)", n) - UString x(32U); - x.snprintf("%f", n); + x.rep->_length = u_printSize(x.data(), n); U_RETURN_STRING(x); } @@ -114,9 +101,21 @@ public: static UString numberToString(uint64_t n); + static UString numberToString(double n) + { + U_TRACE(0, "UStringExt::numberToString(%f)", n) + + UString x(32U); + char* ptr = x.data(); + + ptr[(x.rep->_length = u_dtoa(n, ptr))] = '\0'; + + U_RETURN_STRING(x); + } + static UString stringFromNumber(long n) { - U_TRACE(0, "UStringExt::stringFromNumber(%lld)", n) + U_TRACE(0, "UStringExt::stringFromNumber(%ld)", n) UString x(22U); @@ -133,20 +132,24 @@ public: { U_TRACE(0, "UStringExt::appendNumber32(%V,%u)", s.rep, number) - char buffer[10]; - char* ptr = buffer; + uint32_t sz = s.size(); + char* ptr = s.c_pointer(sz); - (void) s.append(buffer, u_num2str32(number, ptr)); + s.rep->_length = sz + u_num2str32(number, ptr); + + U_INTERNAL_ASSERT(s.invariant()) } static void appendNumber64(UString& s, uint64_t number) { U_TRACE(0, "UStringExt::appendNumber64(%V,%llu)", s.rep, number) - char buffer[22]; - char* ptr = buffer; + uint32_t sz = s.size(); + char* ptr = s.c_pointer(sz); - (void) s.append(buffer, u_num2str64(number, ptr)); + s.rep->_length = sz + u_num2str64(number, ptr); + + U_INTERNAL_ASSERT(s.invariant()) } // convert letter to upper or lower case diff --git a/m4/ac_check_package.m4 b/m4/ac_check_package.m4 index d05d44d9..debc9309 100644 --- a/m4/ac_check_package.m4 +++ b/m4/ac_check_package.m4 @@ -484,11 +484,17 @@ dnl libssh_version=$(grep LIBSFTP_VERSION $sshdir/include/libssh/sftp.h | cut - echo "${T_MD}libcurl found in $curldir${T_ME}" USE_LIBCURL=yes AC_DEFINE(USE_LIBCURL, 1, [Define if enable libcurL support]) - libcurl_version=$($curldir/bin/curl-config --version 2>/dev/null | sed -e "s/libcurl //g") + if test x_$PKG_CONFIG != x_no; then + libcurl_version=$(pkg-config --modversion libcurl) + fi + if test -z "${libcurl_version}"; then + libcurl_version=$($curldir/bin/curl-config --version 2>/dev/null | sed -e "s/libcurl //g") + fi if test -z "${libcurl_version}"; then libcurl_version="unknown" fi - ULIB_LIBS="-lcurl $ULIB_LIBS"; + libcurl_linking=$($curldir/bin/curl-config --libs 2>/dev/null) + ULIB_LIBS="$libcurl_linking $ULIB_LIBS"; if test $curldir != "${CROSS_ENVIRONMENT}/" -a $curldir != "${CROSS_ENVIRONMENT}/usr" -a $curldir != "${CROSS_ENVIRONMENT}/usr/local"; then CPPFLAGS="$CPPFLAGS -I$curldir/include"; LDFLAGS="$LDFLAGS -L$curldir/lib -Wl,-R$curldir/lib"; diff --git a/src/ulib/base/base.c b/src/ulib/base/base.c index cc606804..a0b005c3 100644 --- a/src/ulib/base/base.c +++ b/src/ulib/base/base.c @@ -210,9 +210,6 @@ static uint32_t num2str32(uint32_t num, char* restrict cp) d1 = (num / 100) << 1; d2 = (num % 100) << 1; - U_INTERNAL_ASSERT_MINOR(d1, 200) - U_INTERNAL_ASSERT_MINOR(d2, 200) - if (num >= 1000) *cp++ = u_ctn2s[d1]; if (num >= 100) *cp++ = u_ctn2s[d1+1]; if (num >= 10) *cp++ = u_ctn2s[d2]; @@ -230,11 +227,6 @@ static uint32_t num2str32(uint32_t num, char* restrict cp) d3 = (c / 100); d4 = (c % 100); - U_INTERNAL_ASSERT_MINOR(d1, 200) - U_INTERNAL_ASSERT_MINOR(d2, 200) - U_INTERNAL_ASSERT_MINOR(d3, 100) - U_INTERNAL_ASSERT_MINOR(d4, 100) - if (num >= 10000000) *cp++ = u_ctn2s[d1]; if (num >= 1000000) *cp++ = u_ctn2s[d1+1]; if (num >= 100000) *cp++ = u_ctn2s[d2]; @@ -254,8 +246,6 @@ static uint32_t num2str32(uint32_t num, char* restrict cp) if (a < 10) *cp++ = '0' + (char)a; else { - U_INTERNAL_ASSERT_MINOR(a, 100) - U_NUM2STR16(cp, a); cp += 2; @@ -270,11 +260,6 @@ static uint32_t num2str32(uint32_t num, char* restrict cp) d3 = (c / 100); d4 = (c % 100); - U_INTERNAL_ASSERT_MINOR(d1, 100) - U_INTERNAL_ASSERT_MINOR(d2, 100) - U_INTERNAL_ASSERT_MINOR(d3, 100) - U_INTERNAL_ASSERT_MINOR(d4, 100) - U_NUM2STR16(cp, d1); U_NUM2STR16(cp+2, d2); U_NUM2STR16(cp+4, d3); @@ -398,6 +383,9 @@ static uint32_t num2str64(uint64_t num, char* restrict cp) return (cp + 16 - start); } +static uint32_t dtoa(double num, char* restrict cp) { return sprintf(cp, "%g", num); } + +uPFdpc u_dbl2str = dtoa; uPFu32pc u_num2str32 = num2str32; uPFu64pc u_num2str64 = num2str64; @@ -861,7 +849,7 @@ bool u_setStartTime(void) void u_init_ulib(char** restrict argv) { - U_INTERNAL_TRACE("u_init_ulib()") + U_INTERNAL_TRACE("u_init_ulib(%p)", argv) u_setPid(); @@ -888,13 +876,13 @@ void u_init_ulib(char** restrict argv) __get_cpuid(1, &cpuid[0], &cpuid[1], &cpuid[2], &cpuid[3]); # endif # ifndef bit_SSE2 -# define bit_SSE2 (1 << 26) /* Taken from GCC ... just more visual & descriptive! */ +# define bit_SSE2 (1 << 26) /* Taken from GCC ... just more visual & descriptive! */ # endif # ifndef bit_SSSE3 -# define bit_SSSE3 (1 << 9) +# define bit_SSSE3 (1 << 9) # endif # ifndef bit_SSE4_2 -# define bit_SSE4_2 (1 << 20) +# define bit_SSE4_2 (1 << 20) # endif # if defined(_M_X64) || defined(__x86_64__) /* 64-bit */ if ((cpuid[2] & bit_SSE4_2) != 0) u_flag_sse = 42; /* detect SSE4.2, available on Core i and newer processors, they include "fast unaligned" memory access */ @@ -964,7 +952,7 @@ void u_init_ulib(char** restrict argv) * the array indeterminate */ -uint32_t u_strftime1(char* restrict s, uint32_t maxsize, const char* restrict format) +uint32_t u_strftime1(char* restrict buffer, uint32_t maxsize, const char* restrict format) { static const int day_name_len[7] = { 6, 6, 7, 9, 8, 6, 8 }; static const int month_name_len[12] = { 7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8 }; @@ -1059,17 +1047,20 @@ uint32_t u_strftime1(char* restrict s, uint32_t maxsize, const char* restrict fo (char*)&&case_z-(char*)&&cdefault /* 'z' */ }; - char ch; /* character from format */ - int n, val; /* handy integer (short term usage) */ - uint32_t count = 0; /* return value accumulator */ - const char* restrict fmark; /* for remembering a place in format */ + int n, val; /* handy integer (short term usage) */ + const char* restrict fmark; /* for remembering a place in format */ + + char ch; /* character from format */ + uint32_t ret = 0; /* return value accumulator */ + + char* restrict bp = buffer; U_INTERNAL_TRACE("u_strftime1(%u,%s)", maxsize, format) U_INTERNAL_ASSERT_POINTER(format) U_INTERNAL_ASSERT_MAJOR(maxsize, 0) - while (count < maxsize) + while (ret < maxsize) { fmark = format; @@ -1082,7 +1073,11 @@ uint32_t u_strftime1(char* restrict s, uint32_t maxsize, const char* restrict fo if ((n = (format - fmark)) != 0) { - while (n--) s[count++] = *fmark++; + ret += n; + + u__memcpy(bp, fmark, n, __PRETTY_FUNCTION__); + + bp += n; } if (ch == '\0') break; @@ -1094,13 +1089,17 @@ uint32_t u_strftime1(char* restrict s, uint32_t maxsize, const char* restrict fo if (u__isalpha(ch) == false) { cdefault: - s[count++] = '%'; /* "%%" prints % */ + *bp++ = '%'; /* "%%" prints % */ + + ++ret; if (ch != '%') /* "%?" prints %?, unless ? is 0: pretend it was %c with argument ch */ { if (ch == '\0') break; - s[count++] = ch; + *bp++ = ch; + + ++ret; } continue; @@ -1111,314 +1110,336 @@ cdefault: goto *((char*)&&cdefault + dispatch_table[ch-'A']); case_A: /* %A The full name for the day of the week */ + (void) u__memcpy(bp, u_day_name[u_strftime_tm.tm_wday], day_name_len[u_strftime_tm.tm_wday], __PRETTY_FUNCTION__); - (void) u__memcpy(s+count, u_day_name[u_strftime_tm.tm_wday], day_name_len[u_strftime_tm.tm_wday], __PRETTY_FUNCTION__); - count += day_name_len[u_strftime_tm.tm_wday]; + bp += day_name_len[u_strftime_tm.tm_wday]; + ret += day_name_len[u_strftime_tm.tm_wday]; continue; case_B: /* %B The full name of the month */ + (void) u__memcpy(bp, u_month_name[u_strftime_tm.tm_mon], month_name_len[u_strftime_tm.tm_mon], __PRETTY_FUNCTION__); - (void) u__memcpy(s+count, u_month_name[u_strftime_tm.tm_mon], month_name_len[u_strftime_tm.tm_mon], __PRETTY_FUNCTION__); - count += month_name_len[u_strftime_tm.tm_mon]; + bp += month_name_len[u_strftime_tm.tm_mon]; + ret += month_name_len[u_strftime_tm.tm_mon]; continue; case_H: /* %H The hour (on a 24-hour clock), formatted with two digits */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, u_strftime_tm.tm_hour); + U_NUM2STR16(bp, u_strftime_tm.tm_hour); - count += 2; + bp += 2; + ret += 2; continue; case_I: /* %I The hour (on a 12-hour clock), formatted with two digits */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ if (u_strftime_tm.tm_hour == 0 || u_strftime_tm.tm_hour == 12) { - u_put_unalignedp16(s+count, U_MULTICHAR_CONSTANT16('1', '2')); + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('1', '2')); } else { val = u_strftime_tm.tm_hour % 12; - u_put_unalignedp16(s+count, U_MULTICHAR_CONSTANT16('0' + (val >= 10 ? (val / 10) : 0), - '0' + (val % 10))); + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('0' + (val >= 10 ? (val / 10) : 0), + '0' + (val % 10))); } - count += 2; + bp += 2; + ret += 2; continue; case_M: /* %M The minute, formatted with two digits */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, u_strftime_tm.tm_min); + U_NUM2STR16(bp, u_strftime_tm.tm_min); - count += 2; + bp += 2; + ret += 2; continue; case_S: /* %S The second, formatted with two digits */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, u_strftime_tm.tm_sec); + U_NUM2STR16(bp, u_strftime_tm.tm_sec); - count += 2; + bp += 2; + ret += 2; continue; case_T: /* %X A string representing the full time of day (hours, minutes, and seconds), in a format like 13:13:13 - %T The time in 24-hour notation (%H:%M:%S) (SU) */ - U_INTERNAL_ASSERT(count <= (maxsize-8)) + U_INTERNAL_ASSERT(ret <= (maxsize-8)) - /* if (count >= (maxsize - 8)) return 0; */ + /* if (ret >= (maxsize - 8)) return 0; */ - U_NUM2STR64(s+count, ':', u_strftime_tm.tm_hour, u_strftime_tm.tm_min, u_strftime_tm.tm_sec); + U_NUM2STR64(bp, ':', u_strftime_tm.tm_hour, u_strftime_tm.tm_min, u_strftime_tm.tm_sec); - count += 8; + bp += 8; + ret += 8; continue; case_U: /* %U The week number, formatted with two digits (from 0 to 53; week number 1 is taken as beginning with the first Sunday in a year). See also %W */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, (u_strftime_tm.tm_yday + 7 - u_strftime_tm.tm_wday) / 7); + U_NUM2STR16(bp, (u_strftime_tm.tm_yday + 7 - u_strftime_tm.tm_wday) / 7); - count += 2; + bp += 2; + ret += 2; continue; case_W: /* %W Another version of the week number: like %U, but counting week 1 as beginning with the first Monday in a year */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, (u_strftime_tm.tm_yday + ((8-u_strftime_tm.tm_wday) % 7)) / 7); + U_NUM2STR16(bp, (u_strftime_tm.tm_yday + ((8-u_strftime_tm.tm_wday) % 7)) / 7); - count += 2; + bp += 2; + ret += 2; continue; case_Y: /* %Y The full year, formatted with four digits to include the century */ - U_INTERNAL_ASSERT(count <= (maxsize-4)) + U_INTERNAL_ASSERT(ret <= (maxsize-4)) - /* if (count >= (maxsize - 4)) return 0; */ + /* if (ret >= (maxsize - 4)) return 0; */ - (void) sprintf(s+count, "%.4d", 1900 + u_strftime_tm.tm_year); + (void) sprintf(bp, "%.4d", 1900 + u_strftime_tm.tm_year); - U_INTERNAL_ASSERT_EQUALS(strlen(s+count), 4) + U_INTERNAL_ASSERT_EQUALS(strlen(bp), 4) - count += 4; + bp += 4; + ret += 4; continue; case_Z: /* %Z Defined by ANSI C as eliciting the time zone if available */ n = u__strlen(tzname[u_daylight], __PRETTY_FUNCTION__); - U_INTERNAL_ASSERT(count <= (maxsize-n)) + U_INTERNAL_ASSERT(ret <= (maxsize-n)) - /* if (count >= (maxsize - n)) return 0; */ + /* if (ret >= (maxsize - n)) return 0; */ - (void) u__memcpy(s+count, tzname[u_daylight], n, __PRETTY_FUNCTION__); + (void) u__memcpy(bp, tzname[u_daylight], n, __PRETTY_FUNCTION__); - count += n; + bp += n; + ret += n; continue; case_a: /* %a An abbreviation for the day of the week */ + u_put_unalignedp32(bp, U_MULTICHAR_CONSTANT32(u_day_name[u_strftime_tm.tm_wday][0], + u_day_name[u_strftime_tm.tm_wday][1], + u_day_name[u_strftime_tm.tm_wday][2],' ')); - u_put_unalignedp32(s+count, U_MULTICHAR_CONSTANT32(u_day_name[u_strftime_tm.tm_wday][0], - u_day_name[u_strftime_tm.tm_wday][1], - u_day_name[u_strftime_tm.tm_wday][2],' ')); - - count += 3; + bp += 3; + ret += 3; continue; case_b: /* %b An abbreviation for the month name - %h Equivalent to %b (SU) */ + u_put_unalignedp32(bp, U_MULTICHAR_CONSTANT32(u_month_name[u_strftime_tm.tm_mon][0], + u_month_name[u_strftime_tm.tm_mon][1], + u_month_name[u_strftime_tm.tm_mon][2],' ')); - u_put_unalignedp32(s+count, U_MULTICHAR_CONSTANT32(u_month_name[u_strftime_tm.tm_mon][0], - u_month_name[u_strftime_tm.tm_mon][1], - u_month_name[u_strftime_tm.tm_mon][2],' ')); - - count += 3; + bp += 3; + ret += 3; continue; case_c: /* %c A string representing the complete date and time, in the form Mon Apr 01 13:13:13 1992 */ - U_INTERNAL_ASSERT(count <= (maxsize-24)) + U_INTERNAL_ASSERT(ret <= (maxsize-24)) - // if (count >= (maxsize - 24)) return 0; + // if (ret >= (maxsize - 24)) return 0; - u_put_unalignedp32(s+count, U_MULTICHAR_CONSTANT32(u_day_name[u_strftime_tm.tm_wday][0], - u_day_name[u_strftime_tm.tm_wday][1], - u_day_name[u_strftime_tm.tm_wday][2],' ')); + u_put_unalignedp32(bp, U_MULTICHAR_CONSTANT32(u_day_name[u_strftime_tm.tm_wday][0], + u_day_name[u_strftime_tm.tm_wday][1], + u_day_name[u_strftime_tm.tm_wday][2],' ')); - u_put_unalignedp32(s+count+4, U_MULTICHAR_CONSTANT32(u_month_name[u_strftime_tm.tm_mon][0], - u_month_name[u_strftime_tm.tm_mon][1], - u_month_name[u_strftime_tm.tm_mon][2],' ')); + u_put_unalignedp32(bp+4, U_MULTICHAR_CONSTANT32(u_month_name[u_strftime_tm.tm_mon][0], + u_month_name[u_strftime_tm.tm_mon][1], + u_month_name[u_strftime_tm.tm_mon][2],' ')); - (void) sprintf(s+count+8, "%.2d %2.2d:%2.2d:%2.2d %.4d", u_strftime_tm.tm_mday, u_strftime_tm.tm_hour, - u_strftime_tm.tm_min, u_strftime_tm.tm_sec, - 1900 + u_strftime_tm.tm_year); + (void) sprintf(bp+8, "%.2d %2.2d:%2.2d:%2.2d %.4d", u_strftime_tm.tm_mday, u_strftime_tm.tm_hour, + u_strftime_tm.tm_min, u_strftime_tm.tm_sec, + 1900 + u_strftime_tm.tm_year); - U_INTERNAL_ASSERT_EQUALS(strlen(s+count), 8+17) + U_INTERNAL_ASSERT_EQUALS(strlen(bp), 8+17) - count += 8+17; + bp += 8+17; + ret += 8+17; continue; case_d: /* %d The day of the month, formatted with two digits */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, u_strftime_tm.tm_mday); + U_NUM2STR16(bp, u_strftime_tm.tm_mday); - count += 2; + bp += 2; + ret += 2; continue; case_e: /* %e Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ val = (u_strftime_tm.tm_mday >= 10 ? (u_strftime_tm.tm_mday / 10) : 0); - u_put_unalignedp16(s+count, U_MULTICHAR_CONSTANT16(val ? '0' + val : ' ', - '0' + (u_strftime_tm.tm_mday % 10))); + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16(val ? '0' + val : ' ', + '0' + (u_strftime_tm.tm_mday % 10))); - count += 2; + bp += 2; + ret += 2; continue; case_j: /* %j The count of days in the year, formatted with three digits (from 1 to 366) */ - U_INTERNAL_ASSERT(count <= (maxsize-3)) + U_INTERNAL_ASSERT(ret <= (maxsize-3)) - /* if (count >= (maxsize - 3)) return 0; */ + /* if (ret >= (maxsize - 3)) return 0; */ - (void) sprintf(s+count, "%.3d", u_strftime_tm.tm_yday+1); + (void) sprintf(bp, "%.3d", u_strftime_tm.tm_yday+1); - U_INTERNAL_ASSERT_EQUALS(strlen(s+count), 3) + U_INTERNAL_ASSERT_EQUALS(strlen(bp), 3) - count += 3; + bp += 3; + ret += 3; continue; case_m: /* %m The month number, formatted with two digits */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - U_NUM2STR16(s+count, u_strftime_tm.tm_mon+1); + U_NUM2STR16(bp, u_strftime_tm.tm_mon+1); - count += 2; + bp += 2; + ret += 2; continue; case_p: /* %p Either AM or PM as appropriate */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ - u_put_unalignedp16(s+count, U_MULTICHAR_CONSTANT16(u_strftime_tm.tm_hour < 12 ? 'A' : 'P','M')); + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16(u_strftime_tm.tm_hour < 12 ? 'A' : 'P','M')); - count += 2; + bp += 2; + ret += 2; continue; case_w: /* %w A single digit representing the day of the week: Sunday is day 0 */ - U_INTERNAL_ASSERT(count <= (maxsize-1)) + U_INTERNAL_ASSERT(ret <= (maxsize-1)) - /* if (count >= (maxsize - 1)) return 0; */ + /* if (ret >= (maxsize - 1)) return 0; */ - s[count++] = '0' + (u_strftime_tm.tm_wday % 10); + *bp++ = '0' + (u_strftime_tm.tm_wday % 10); + + ++ret; continue; case_x: /* %x A string representing the complete date, in a format like Mon Apr 01 1992 */ - U_INTERNAL_ASSERT(count <= (maxsize-15)) + U_INTERNAL_ASSERT(ret <= (maxsize-15)) - /* if (count >= (maxsize - 15)) return 0; */ + /* if (ret >= (maxsize - 15)) return 0; */ - u_put_unalignedp32(s+count, U_MULTICHAR_CONSTANT32(u_day_name[u_strftime_tm.tm_wday][0], - u_day_name[u_strftime_tm.tm_wday][1], - u_day_name[u_strftime_tm.tm_wday][2],' ')); + u_put_unalignedp32(bp, U_MULTICHAR_CONSTANT32(u_day_name[u_strftime_tm.tm_wday][0], + u_day_name[u_strftime_tm.tm_wday][1], + u_day_name[u_strftime_tm.tm_wday][2],' ')); - u_put_unalignedp32(s+count+4, U_MULTICHAR_CONSTANT32(u_month_name[u_strftime_tm.tm_mon][0], - u_month_name[u_strftime_tm.tm_mon][1], - u_month_name[u_strftime_tm.tm_mon][2],' ')); + u_put_unalignedp32(bp+4, U_MULTICHAR_CONSTANT32(u_month_name[u_strftime_tm.tm_mon][0], + u_month_name[u_strftime_tm.tm_mon][1], + u_month_name[u_strftime_tm.tm_mon][2],' ')); - (void) sprintf(s+count+8, "%.2d %.4d", u_strftime_tm.tm_mday, 1900 + u_strftime_tm.tm_year); + (void) sprintf(bp+8, "%.2d %.4d", u_strftime_tm.tm_mday, 1900 + u_strftime_tm.tm_year); - U_INTERNAL_ASSERT_EQUALS(strlen(s+count), 8+7) + U_INTERNAL_ASSERT_EQUALS(strlen(bp), 8+7) - count += 8+7; + bp += 8+7; + ret += 8+7; continue; case_y: /* %y The last two digits of the year */ - U_INTERNAL_ASSERT(count <= (maxsize-2)) + U_INTERNAL_ASSERT(ret <= (maxsize-2)) - /* if (count >= (maxsize - 2)) return 0; */ + /* if (ret >= (maxsize - 2)) return 0; */ /** * The year could be greater than 100, so we need the value modulo 100. * The year could be negative, so we need to correct for a possible negative remainder */ - U_NUM2STR16(s+count, ((u_strftime_tm.tm_year % 100) + 100) % 100); + U_NUM2STR16(bp, ((u_strftime_tm.tm_year % 100) + 100) % 100); - count += 2; + bp += 2; + ret += 2; continue; case_z: /* %z The +hhmm or -hhmm numeric timezone (that is, the hour and minute offset from UTC) */ - U_INTERNAL_ASSERT(count <= (maxsize-5)) + U_INTERNAL_ASSERT(ret <= (maxsize-5)) - /* if (count >= (maxsize - 5)) return 0; */ + /* if (ret >= (maxsize - 5)) return 0; */ val = (u_now_adjust / 3600); if (val > 0) { - s[count++] = '+'; + *bp++ = '+'; - U_NUM2STR16(s+count, val); + U_NUM2STR16(bp, val); } else { - s[count++] = '-'; + *bp++ = '-'; - U_NUM2STR16(s+count, -val); + U_NUM2STR16(bp, -val); } - U_NUM2STR16(s+count+2, u_now_adjust % 3600); + U_NUM2STR16(bp+3, u_now_adjust % 3600); - count += 4; + bp += 5; + ret += 5; } - U_INTERNAL_PRINT("count = %u maxsize = %u", count, maxsize) + U_INTERNAL_PRINT("ret = %u maxsize = %u", ret, maxsize) - if (count < maxsize) s[count] = '\0'; + if (ret < maxsize) *bp = '\0'; - U_INTERNAL_ASSERT(count <= maxsize) + U_INTERNAL_ASSERT(ret <= maxsize) - return count; + return ret; } uint32_t u_strftime2(char* restrict s, uint32_t maxsize, const char* restrict format, time_t t) @@ -1601,7 +1622,6 @@ static const char* tab_color[] = { U_RESET_STR, #endif /** - * ---------------------------------------------------------------------------- * Print with format extension: bBCDHMNOPQrRSUvVYwW * ---------------------------------------------------------------------------- * '%b': print bool ("true" or "false") @@ -1647,7 +1667,7 @@ uint32_t u__vsnprintf(char* restrict buffer, uint32_t buffer_size, const char* r (char*)&&case_space-(char*)&&cdefault, /* ' ' */ 0,/* '!' */ 0,/* '"' */ - (char*)&&case_number-(char*)&&cdefault,/* '#' */ + (char*)&&case_alt-(char*)&&cdefault,/* '#' */ 0,/* '$' */ 0,/* '%' */ 0,/* '&' */ @@ -1746,29 +1766,36 @@ uint32_t u__vsnprintf(char* restrict buffer, uint32_t buffer_size, const char* r int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int fieldsz; /* field size expanded by sign, dpad etc */ - char sign; /* sign prefix (' ', '+', '-', or \0) */ - const char* restrict fmark; /* for remembering a place in format */ - unsigned char buf_number[32]; /* space for %[cdiouxX] */ - unsigned char* restrict cp = 0; /* handy char pointer (short term usage) */ - - uint64_t argument = 0; /* integer arguments %[diIouxX] */ - enum { OCT, DEC, HEX } base; /* base for [diIouxX] conversion */ - - int flags; /* flags as above */ + time_t t; + char sign; /* sign prefix (' ', '+', '-', or \0) */ + unsigned char c; + uint64_t argument; /* integer arguments %[diIouxX] */ + int i, n, remaining; /* handy integer (short term usage) */ + struct U_DATA udata; + char* restrict pbase; + uint32_t len, maxlen; + unsigned char buf[32]; /* space for %[cdiouxX] or fmt for float/double */ + struct ustringrep* pstr; + const char* restrict fmark; /* for remembering a place in format */ + unsigned char* restrict cp; /* handy char pointer (short term usage) */ + enum { OCT, DEC, HEX } base; /* base for [diIouxX] conversion */ + const char* restrict fmtdate; /* Flags used during conversion */ -# define LONGINT 0x001 /* long integer */ -# define LLONGINT 0x002 /* long long integer */ -# define LONGDBL 0x004 /* long double */ -# define SHORTINT 0x008 /* short integer */ -# define ALT 0x010 /* alternate form */ -# define LADJUST 0x020 /* left adjustment */ -# define ZEROPAD 0x040 /* zero (as opposed to blank) */ -# define HEXPREFIX 0x080 /* add 0x or 0X prefix */ -# define THOUSANDS_GROUPED 0x100 /* For decimal conversion (i,d,u,f,F,g,G) the output is to be grouped with thousands */ + int flags; - /* To extend shorts properly, we need both signed and uint32_t argument extraction methods */ +# define LONGINT 0x001 /* long integer */ +# define LLONGINT 0x002 /* long long integer */ +# define LONGDBL 0x004 /* long double */ +# define SHORTINT 0x008 /* short integer */ +# define ALT 0x010 /* alternate form */ +# define LADJUST 0x020 /* left adjustment */ +# define ZEROPAD 0x040 /* zero (as opposed to blank) */ +# define HEXPREFIX 0x080 /* add 0x or 0X prefix */ +# define THOUSANDS_GROUPED 0x100 /* For decimal conversion (i,d,u,f,F,g,G) the output is to be grouped with thousands */ + + /* To extend shorts properly, we need both signed and unsigned argument extraction methods */ # define VA_ARG(type) va_arg(argp, type) @@ -1781,20 +1808,10 @@ uint32_t u__vsnprintf(char* restrict buffer, uint32_t buffer_size, const char* r flags & SHORTINT ? (uint64_t)(uint16_t) VA_ARG(int) : \ (uint64_t) VA_ARG(unsigned int)) - /* Scan the format for conversions (`%' character) */ - char ch; /* character from format */ - time_t t; uint32_t ret = 0; /* return value accumulator */ - unsigned char c; - struct U_DATA udata; - char* restrict pbase; - struct ustringrep* pstr; - const char* restrict ccp; + char* restrict bp = buffer; - unsigned char fmt_float[32]; - const char* restrict fmtdate; - int i, n, len, maxlen, remaining; /* handy integer (short term usage) */ #ifdef DEBUG const char* restrict format_save = format; #endif @@ -1807,6 +1824,8 @@ uint32_t u__vsnprintf(char* restrict buffer, uint32_t buffer_size, const char* r { U_INTERNAL_ERROR(ret <= buffer_size, "BUFFER OVERFLOW at u__vsnprintf() ret = %u buffer_size = %u format = \"%s\"", ret, buffer_size, format_save); + /* Scan the format for conversions ('%' character) */ + fmark = format; while ((ch = *format) != '\0') @@ -1820,14 +1839,18 @@ uint32_t u__vsnprintf(char* restrict buffer, uint32_t buffer_size, const char* r { ret += n; - while (n--) *bp++ = *fmark++; + u__memcpy(bp, fmark, n, __PRETTY_FUNCTION__); + + bp += n; } if (ch == '\0') break; + sign = 0; prec = -1; - sign = '\0'; - width = flags = dprec = 0; + width = + flags = + dprec = 0; ++format; /* skip over '%' */ @@ -1835,7 +1858,7 @@ rflag: ch = *format++; reswitch: - U_INTERNAL_PRINT("prec = %d ch = %c", prec, ch) + U_INTERNAL_PRINT("prec = %d sign = %d u__isprintf(%c) = %u", prec, sign, ch, u__isprintf(ch)) if (UNLIKELY(u__isprintf(ch) == false)) { @@ -1861,11 +1884,11 @@ cdefault: goto *((char*)&&cdefault + dispatch_table[ch-' ']); case_space: /* If the space and + flags both appear, the space flag will be ignored */ - if (sign == '\0') sign = ' '; + if (sign == 0) sign = ' '; goto rflag; -case_number: /* field flag characters: # */ +case_alt: /* field flag characters: # */ flags |= ALT; goto rflag; @@ -1892,7 +1915,11 @@ case_plus: /* field flag characters: + */ goto rflag; case_period: /* The field precision '.' */ - if ((ch = *format++) == '*') + if ((ch = *format++) != '*') + { + for (prec = 0; u__isdigit(ch); ch = *format++) prec = (prec*10) + (ch-'0'); + } + else { prec = VA_ARG(int); @@ -1902,68 +1929,67 @@ case_period: /* The field precision '.' */ if (u__tolower(ch) == 's') goto case_str; } - else - { - for (prec = 0; u__isdigit(ch); ch = *format++) prec = (prec*10) + (ch-'0'); - } goto reswitch; case_zero: /* Note that 0 is taken as a flag, not as the beginning of a field width */ - if (!(flags & LADJUST)) flags |= ZEROPAD; /* '-' disables '0' */ + if ((flags & LADJUST) == 0) flags |= ZEROPAD; /* '-' disables '0' */ goto rflag; case_digit: /* field width: [1-9] - An optional decimal digit string (with nonzero first digit) specifying a minimum field width */ - n = 0; + U_INTERNAL_ASSERT_EQUALS(width, 0) do { - n = n*10 + (ch-'0'); + width = width * 10 + (ch-'0'); + ch = *format++; } while (u__isdigit(ch)); - width = n; - goto reswitch; case_float: - fmt_float[0] = '%'; - - cp = fmt_float + 1; - - if ((flags & ALT) != 0) *cp++ = '#'; - if ((flags & ZEROPAD) != 0) *cp++ = '0'; - if ((flags & LADJUST) != 0) *cp++ = '-'; - if ((flags & THOUSANDS_GROUPED) != 0) *cp++ = '\''; - if (sign != '\0') *cp++ = sign; - - *cp++ = '*'; /* width */ - - u_put_unalignedp16(cp, U_MULTICHAR_CONSTANT16('.','*')); /* prec */ - - cp += 2; - - if (flags & LONGDBL) *cp++ = 'L'; - - u_put_unalignedp16(cp, U_MULTICHAR_CONSTANT16(ch,'\0')); - - ++cp; - - if (flags & LONGDBL) - { - long double ldbl = VA_ARG(long double); - - len = sprintf(bp, (const char* restrict)fmt_float, width, prec, ldbl); - } - else + if (ch == 'g' && + prec == -1 && + width == 0 && + (flags & (LADJUST | ZEROPAD | THOUSANDS_GROUPED | LONGDBL)) == 0) { double dbl = VA_ARG(double); - len = sprintf(bp, (const char* restrict)fmt_float, width, prec, dbl); + len = u_dtoa(dbl, bp); } + else + { + buf[0] = '%'; - U_INTERNAL_ASSERT_EQUALS(len, (int)strlen(bp)) + cp = buf + 1; + + if ((flags & ALT) != 0) *cp++ = '#'; + if ((flags & ZEROPAD) != 0) *cp++ = '0'; + if ((flags & LADJUST) != 0) *cp++ = '-'; + if ((flags & THOUSANDS_GROUPED) != 0) *cp++ = '\''; + if (sign) *cp++ = sign; + + u_put_unalignedp32(cp, U_MULTICHAR_CONSTANT32('*','.','*','L')); /* width, prec */ + + u_put_unalignedp16(cp + ((flags & LONGDBL) == 0 ? 3 : 4), U_MULTICHAR_CONSTANT16(ch,'\0')); + + if ((flags & LONGDBL) != 0) + { + long double ldbl = VA_ARG(long double); + + len = sprintf(bp, (const char* restrict)buf, width, prec, ldbl); + } + else + { + double dbl = VA_ARG(double); + + len = sprintf(bp, (const char* restrict)buf, width, prec, dbl); + } + + U_INTERNAL_ASSERT_EQUALS(len, strlen(bp)) + } bp += len; ret += len; @@ -2023,13 +2049,14 @@ empty: u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('"','"')); maxlen = (u_printf_string_max_length > 0 ? u_printf_string_max_length : 128); if (prec < 0 || /* NB: no precision specified... */ - prec > maxlen) + prec > (int)maxlen) { prec = maxlen; } + U_INTERNAL_ASSERT_EQUALS(sign, 0) + n = 0; - sign = 0; pbase = bp; remaining = buffer_size - ret; @@ -2072,15 +2099,14 @@ empty: u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('"','"')); remaining <= 60) { if (sign || - len < 0) /* NB: no precision specified... */ + len == U_NOT_FOUND) /* NB: no precision specified... */ { /* NB: print something that have the meaning of 'to be continued'... */ - *bp++ = '.'; - u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('.','.')); - bp += 2; + bp += 2; + *bp++ = '.'; } break; @@ -2099,11 +2125,12 @@ empty: u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('"','"')); } case_ustring_v: - sign = '\0'; - size = (prec < 0 ? (int) u__strlen((const char*)cp, __PRETTY_FUNCTION__) : prec); + U_INTERNAL_ASSERT_EQUALS(sign, 0) + + size = (prec < 0 ? (int)u__strlen((const char*)cp, __PRETTY_FUNCTION__) : prec); U_INTERNAL_ERROR(size <= (int)(buffer_size - ret), - "WE ARE GOING TO OVERFLOW BUFFER at u__vsnprintf() size = %u remaining = %u cp = %.20s buffer_size = %u format = \"%s\"", + "WE ARE GOING TO OVERFLOW BUFFER at u__vsnprintf() size = %u remaining = %d cp = %.20s buffer_size = %u format = \"%s\"", size, (buffer_size - ret), cp, buffer_size, format_save); /* if a width from format is specified, the 0 flag for padding will be ignored... */ @@ -2234,9 +2261,19 @@ case_D: /* extension: print date and time in various format */ bp += len; ret += len; - len = sprintf(bp, " +%ld days", (long)t / U_ONE_DAY_IN_SECOND); + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16(' ','+')); - U_INTERNAL_ASSERT_EQUALS(len, (int)strlen(bp)) + bp += 2; + ret += 2; + + len = u_num2str32(t / U_ONE_DAY_IN_SECOND, bp); + + u_put_unalignedp32(bp+len, U_MULTICHAR_CONSTANT32(' ','d','a','y')); + + bp += 4; + *bp++ = 's'; + + ret += 5; } } else if (width == 4) /* _millisec */ @@ -2252,7 +2289,7 @@ case_D: /* extension: print date and time in various format */ len = sprintf(bp, "_%03ld", ms); - U_INTERNAL_ASSERT_EQUALS(len, (int)strlen(bp)) + U_INTERNAL_ASSERT_EQUALS(len, strlen(bp)) } bp += len; @@ -2278,7 +2315,6 @@ case_I: /* extension: print off_t */ goto case_d; case_J: /* extension: print U_DATA */ - udata = VA_ARG(struct U_DATA); cp = udata.dptr; @@ -2326,15 +2362,15 @@ case_Q: /* extension: call exit() or abort() (var-argument is the arg passed to continue; case_R: /* extension: print msg - u_getSysError() */ - ccp = VA_ARG(const char* restrict); + cp = VA_ARG(unsigned char* restrict); - U_INTERNAL_PRINT("ccp = %s", ccp) + U_INTERNAL_PRINT("cp = %s", cp) - if (ccp) + if (cp) { - len = u__strlen(ccp, __PRETTY_FUNCTION__); + len = u__strlen((const char* restrict)cp, __PRETTY_FUNCTION__); - u__memcpy(bp, ccp, len, __PRETTY_FUNCTION__); + u__memcpy(bp, cp, len, __PRETTY_FUNCTION__); bp += len; ret += len; @@ -2342,11 +2378,11 @@ case_R: /* extension: print msg - u_getSysError() */ if ((flags & ALT) == 0) { + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16(' ','-')); + + bp += 2; *bp++ = ' '; - u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('-',' ')); - - bp += 2; ret += 3; } @@ -2357,18 +2393,18 @@ case_R: /* extension: print msg - u_getSysError() */ { errno = - errno; - ccp = getSysError_w32((uint32_t*)&len); + cp = getSysError_w32((uint32_t*)&len); - u__memcpy(bp, ccp, len, __PRETTY_FUNCTION__); + u__memcpy(bp, cp, len, __PRETTY_FUNCTION__); bp += len; ret += len; + u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16(' ','-')); + + bp += 2; *bp++ = ' '; - u_put_unalignedp16(bp, U_MULTICHAR_CONSTANT16('-',' ')); - - bp += 2; ret += 3; MAP_WIN32_ERROR_TO_POSIX @@ -2402,7 +2438,6 @@ case_U: /* extension: print user name */ continue; case_V: /* extension: print ustring */ - pstr = VA_ARG(struct ustringrep*); U_INTERNAL_ASSERT_POINTER(pstr) @@ -2437,24 +2472,20 @@ case_X: /* leading 0x/X only if non-zero */ - if (argument != 0LL && + if (argument != 0 && (flags & ALT) != 0) { flags |= HEXPREFIX; } - /* uint32_t conversions */ - nosign: - sign = '\0'; + sign = 0; - /* ... diouXx conversions ... if a precision is specified, the 0 flag will be ignored */ - -number: - if ((dprec = prec) >= 0) flags &= ~ZEROPAD; +number: /* uint32_t conversions */ + if ((dprec = prec) >= 0) flags &= ~ZEROPAD; /* ... diouXx conversions ... if a precision is specified, the 0 flag will be ignored */ if (prec == 0 && - argument == 0LL) + argument == 0) { size = 0; /* The result of converting a zero value with an explicit precision of zero is no characters */ } @@ -2462,9 +2493,9 @@ number: { if (base == OCT) { - cp = buf_number + sizeof(buf_number); + cp = buf + sizeof(buf); - do { *--cp = (argument & 7L) + '0'; } while (argument >>= 3L); + do { *--cp = (argument & 7) + '0'; } while (argument >>= 3); /* handle octal leading 0 */ @@ -2474,17 +2505,18 @@ number: *--cp = '0'; } - size = (ptrdiff_t)(buf_number + sizeof(buf_number) - cp); + size = (ptrdiff_t)(buf + sizeof(buf) - cp); } else if (base == HEX) { - const unsigned char* restrict xdigs = (ch == 'X' ? u_hex_upper : u_hex_lower); /* digits for [xX] conversion */ + const unsigned char* restrict xdigs = (ch == 'X' ? u_hex_upper + : u_hex_lower); /* digits for [xX] conversion */ - cp = buf_number + sizeof(buf_number); + cp = buf + sizeof(buf); - do { *--cp = xdigs[argument & 15L]; } while (argument /= 16L); + do { *--cp = xdigs[argument & 15]; } while (argument /= 16); - size = (ptrdiff_t)(buf_number + sizeof(buf_number) - cp); + size = (ptrdiff_t)(buf + sizeof(buf) - cp); } else { @@ -2495,12 +2527,12 @@ number: if (dprec || (flags & (LADJUST | ZEROPAD)) != 0) { - size = u_num2str64(argument, (char* restrict)(cp = buf_number)); + size = u_num2str64(argument, (char* restrict)(cp = buf)); goto next; } - if (sign != '\0') + if (sign) { *bp++ = sign; @@ -2517,20 +2549,20 @@ number: n = 1; - cp = buf_number + sizeof(buf_number); + cp = buf + sizeof(buf); - while (argument >= 10LL) /* NB: many numbers are 1 digit */ + while (argument >= 10) /* NB: many numbers are 1 digit */ { - *--cp = (unsigned char)(argument % 10LL) + '0'; + *--cp = (unsigned char)(argument % 10) + '0'; - argument /= 10LL; + argument /= 10; if ((n++ % 3) == 0) *--cp = ','; } *--cp = argument + '0'; - size = (ptrdiff_t)(buf_number + sizeof(buf_number) - cp); + size = (ptrdiff_t)(buf + sizeof(buf) - cp); } } @@ -2569,9 +2601,10 @@ case_b: /* extension: print bool */ continue; case_c: /* field conversion specifier */ - *(cp = buf_number) = VA_ARG(int); + *(cp = buf) = VA_ARG(int); + + U_INTERNAL_ASSERT_EQUALS(sign, 0) - sign = '\0'; size = 1; goto next; @@ -2579,7 +2612,7 @@ case_c: /* field conversion specifier */ case_d: argument = SARG(); - if ((int64_t)argument < 0LL) + if ((int64_t)argument < 0) { sign = '-'; argument = -argument; @@ -2698,7 +2731,6 @@ case_u: goto nosign; case_v: /* extension: print ustring */ - pstr = VA_ARG(struct ustringrep*); U_INTERNAL_ASSERT_POINTER(pstr) @@ -2773,7 +2805,7 @@ next: /* prefix */ - if (sign != '\0') + if (sign) { if (bpad) --bp; else @@ -2811,7 +2843,14 @@ next: /* the string or number proper */ - for (; size; --size) *bp++ = *cp++; + if (size) + { + U_INTERNAL_ASSERT_POINTER(cp) + + u__memcpy(bp, cp, size, __PRETTY_FUNCTION__); + + bp += size; + } /* left-adjusting padding (always blank) */ diff --git a/src/ulib/base/utility.c b/src/ulib/base/utility.c index a5645641..4709d07a 100644 --- a/src/ulib/base/utility.c +++ b/src/ulib/base/utility.c @@ -680,24 +680,32 @@ double u_calcRate(uint64_t bytes, uint32_t msecs, int* restrict units) return rate; } -void u_printSize(char* restrict buffer, uint64_t bytes) +uint32_t u_printSize(char* restrict buffer, uint64_t bytes) { int units; double size; + uint32_t len; U_INTERNAL_TRACE("u_printSize(%p,%llu)", buffer, bytes) if (bytes == 0) { - u__strcpy(buffer, "0 Byte"); + u_put_unalignedp32(buffer, U_MULTICHAR_CONSTANT32('0',' ','B','y')); + u_put_unalignedp16(buffer+4, U_MULTICHAR_CONSTANT16('t','e')); - return; + len = 6; + } + else + { + size = u_calcRate(bytes, 1000, &units); + + len = (units ? sprintf(buffer, "%5.2f %s", size, u_short_units[units]) + : sprintf(buffer, "%7.0f Bytes", size)); } - size = u_calcRate(bytes, 1000, &units); + buffer[len] = '\0'; - if (units) (void) sprintf(buffer, "%5.2f %s", size, u_short_units[units]); - else (void) sprintf(buffer, "%7.0f Bytes", size); + return len; } uint32_t u_memory_dump(char* restrict bp, unsigned char* restrict cp, uint32_t n) diff --git a/src/ulib/curl/curl.cpp b/src/ulib/curl/curl.cpp index 110d9124..b14d4e00 100644 --- a/src/ulib/curl/curl.cpp +++ b/src/ulib/curl/curl.cpp @@ -134,7 +134,7 @@ U_NO_EXPORT size_t UCURL::writeFunction(void* ptr, size_t size, size_t nmemb, vo size_t len = size * nmemb; - (void) ((UCURL*)obj)->response.reserve(((UCURL*)obj)->response.size() + len); + (void) ((UCURL*)obj)->response.reserve(len); ((UCURL*)obj)->response.append((const char*)ptr, len); diff --git a/src/ulib/internal/common.cpp b/src/ulib/internal/common.cpp index 6f9b712c..710c1804 100644 --- a/src/ulib/internal/common.cpp +++ b/src/ulib/internal/common.cpp @@ -24,7 +24,9 @@ # include "./itoa.cpp" static uint32_t itoa32(uint32_t num, char* restrict cp) { return itoa_fwd(num, cp) - cp; } static uint32_t itoa64(uint64_t num, char* restrict cp) { return itoa_fwd(num, cp) - cp; } -# endif +# elif (defined(i386) || defined(__amd64) || defined(_M_IX86) || defined(_M_X64)) && !defined(HAVE_OLD_IOSTREAM) && !defined(_MSWINDOWS_) && defined(HAVE_ARCH64) +# include "./itoa_sse2.cpp" +#endif #else U_EXPORT bool __cxa_guard_acquire() { return 1; } U_EXPORT bool __cxa_guard_release() { return 1; } @@ -33,7 +35,6 @@ U_EXPORT void* operator new( size_t n) { return malloc(n); } U_EXPORT void* operator new[](size_t n) { return malloc(n); } U_EXPORT void operator delete( void* p) { free(p); } U_EXPORT void operator delete[](void* p) { free(p); } - # ifdef __MINGW32__ U_EXPORT void operator delete( void* p, unsigned int) { free(p); } U_EXPORT void operator delete[](void* p, unsigned int) { free(p); } @@ -70,7 +71,7 @@ void ULib_init_openssl() // is responsible for seeding the PRNG by calling RAND_add() # ifdef _MSWINDOWS_ - U_SYSCALL_VOID(srand, "%ld", u_start_time); // seed with time + U_SYSCALL_VOID(srand, "%ld", u_seed_hash); while (RAND_status() == 0) // Seed PRNG only if needed { @@ -84,13 +85,29 @@ void ULib_init_openssl() } #endif +#ifndef HAVE_OLD_IOSTREAM +# include +static uint32_t dtoa_milo(double value, char* buffer) { int length, K; Grisu2(value, buffer, &length, &K); return Prettify(buffer, length, K); } +#endif + void ULib_init() { U_TRACE_NO_PARAM(1, "ULib_init()") + // conversion number to string + +#ifndef HAVE_OLD_IOSTREAM + u_dbl2str = dtoa_milo; +#endif #if defined(HAVE_CXX14) && GCC_VERSION_NUM > 60100 u_num2str32 = itoa32; u_num2str64 = itoa64; +#elif (defined(i386) || defined(__amd64) || defined(_M_IX86) || defined(_M_X64)) && !defined(HAVE_OLD_IOSTREAM) && !defined(_MSWINDOWS_) && defined(HAVE_ARCH64) + if (u_flag_sse >= 2) + { + u_num2str32 = utoa32_sse2; + u_num2str64 = utoa64_sse2; + } #endif #ifdef DEBUG diff --git a/src/ulib/internal/itoa_sse2.cpp b/src/ulib/internal/itoa_sse2.cpp new file mode 100644 index 00000000..69242714 --- /dev/null +++ b/src/ulib/internal/itoa_sse2.cpp @@ -0,0 +1,307 @@ +// SSE2 implementation according to http://0x80.pl/articles/sse-itoa.html +// Modifications: (1) fix incorrect digits (2) accept all ranges (3) write to user provided buffer. + +#if defined(i386) || defined(__amd64) || defined(_M_IX86) || defined(_M_X64) + +#include +#include + +#ifdef _MSC_VER +#include "intrin.h" +#endif + +#ifdef _MSC_VER +#define ALIGN_PRE __declspec(align(16)) +#define ALIGN_SUF +#else +#define ALIGN_PRE +#define ALIGN_SUF __attribute__ ((aligned(16))) +#endif + +static const uint32_t kDiv10000 = 0xd1b71759; +ALIGN_PRE static const uint32_t kDiv10000Vector[4] ALIGN_SUF = { kDiv10000, kDiv10000, kDiv10000, kDiv10000 }; +ALIGN_PRE static const uint32_t k10000Vector[4] ALIGN_SUF = { 10000, 10000, 10000, 10000 }; +ALIGN_PRE static const uint16_t kDivPowersVector[8] ALIGN_SUF = { 8389, 5243, 13108, 32768, 8389, 5243, 13108, 32768 }; // 10^3, 10^2, 10^1, 10^0 +ALIGN_PRE static const uint16_t kShiftPowersVector[8] ALIGN_SUF = { + 1 << (16 - (23 + 2 - 16)), + 1 << (16 - (19 + 2 - 16)), + 1 << (16 - 1 - 2), + 1 << (15), + 1 << (16 - (23 + 2 - 16)), + 1 << (16 - (19 + 2 - 16)), + 1 << (16 - 1 - 2), + 1 << (15) +}; +ALIGN_PRE static const uint16_t k10Vector[8] ALIGN_SUF = { 10, 10, 10, 10, 10, 10, 10, 10 }; +ALIGN_PRE static const char kAsciiZero[16] ALIGN_SUF = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' }; + +inline __pure __m128i Convert8DigitsSSE2(uint32_t value) { + + // abcd, efgh = abcdefgh divmod 10000 + const __m128i abcdefgh = _mm_cvtsi32_si128(value); + const __m128i abcd = _mm_srli_epi64(_mm_mul_epu32(abcdefgh, reinterpret_cast(kDiv10000Vector)[0]), 45); + const __m128i efgh = _mm_sub_epi32(abcdefgh, _mm_mul_epu32(abcd, reinterpret_cast(k10000Vector)[0])); + + // v1 = [ abcd, efgh, 0, 0, 0, 0, 0, 0 ] + const __m128i v1 = _mm_unpacklo_epi16(abcd, efgh); + + // v1a = v1 * 4 = [ abcd * 4, efgh * 4, 0, 0, 0, 0, 0, 0 ] + const __m128i v1a = _mm_slli_epi64(v1, 2); + + // v2 = [ abcd * 4, abcd * 4, abcd * 4, abcd * 4, efgh * 4, efgh * 4, efgh * 4, efgh * 4 ] + const __m128i v2a = _mm_unpacklo_epi16(v1a, v1a); + const __m128i v2 = _mm_unpacklo_epi32(v2a, v2a); + + // v4 = v2 div 10^3, 10^2, 10^1, 10^0 = [ a, ab, abc, abcd, e, ef, efg, efgh ] + const __m128i v3 = _mm_mulhi_epu16(v2, reinterpret_cast(kDivPowersVector)[0]); + const __m128i v4 = _mm_mulhi_epu16(v3, reinterpret_cast(kShiftPowersVector)[0]); + + // v5 = v4 * 10 = [ a0, ab0, abc0, abcd0, e0, ef0, efg0, efgh0 ] + const __m128i v5 = _mm_mullo_epi16(v4, reinterpret_cast(k10Vector)[0]); + + // v6 = v5 << 16 = [ 0, a0, ab0, abc0, 0, e0, ef0, efg0 ] + const __m128i v6 = _mm_slli_epi64(v5, 16); + + // v7 = v4 - v6 = { a, b, c, d, e, f, g, h } + const __m128i v7 = _mm_sub_epi16(v4, v6); + + return v7; +} + +inline __pure __m128i ShiftDigits_SSE2(__m128i a, unsigned digit) { + switch (digit) { + case 0: return a; + case 1: return _mm_srli_si128(a, 1); + case 2: return _mm_srli_si128(a, 2); + case 3: return _mm_srli_si128(a, 3); + case 4: return _mm_srli_si128(a, 4); + case 5: return _mm_srli_si128(a, 5); + case 6: return _mm_srli_si128(a, 6); + case 7: return _mm_srli_si128(a, 7); + case 8: return _mm_srli_si128(a, 8); + } + return a; // should not execute here. +} + +static uint32_t utoa32_sse2(uint32_t value, char* buffer) +{ + char* start = buffer; + + if (value < 10000) + { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) *buffer++ = u_ctn2s[d1]; + if (value >= 100) *buffer++ = u_ctn2s[d1+1]; + if (value >= 10) *buffer++ = u_ctn2s[d2]; + *buffer++ = u_ctn2s[d2+1]; + + return (buffer - start); + } + + if (value < 100000000) + { + // Experiment shows that in this case SSE2 is slower +# if 0 + const __m128i a = Convert8DigitsSSE2(value); + + // Convert to bytes, add '0' + const __m128i va = _mm_add_epi8(_mm_packus_epi16(a, _mm_setzero_si128()), reinterpret_cast(kAsciiZero)[0]); + + // Count number of digit + const unsigned mask = _mm_movemask_epi8(_mm_cmpeq_epi8(va, reinterpret_cast(kAsciiZero)[0])); + unsigned long digit; +# ifdef _MSC_VER + _BitScanForward(&digit, ~mask | 0x8000); +# else + digit = __builtin_ctz(~mask | 0x8000); +# endif + + // Shift digits to the beginning + __m128i result = ShiftDigits_SSE2(va, digit); + //__m128i result = _mm_srl_epi64(va, _mm_cvtsi32_si128(digit * 8)); + _mm_storel_epi64(reinterpret_cast<__m128i*>(buffer), result); + + return (buffer + 8 - digit - start); +# else + // value = bbbbcccc + const uint32_t b = value / 10000; + const uint32_t c = value % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100); + const uint32_t d4 = (c % 100); + + if (value >= 10000000) *buffer++ = u_ctn2s[d1]; + if (value >= 1000000) *buffer++ = u_ctn2s[d1+1]; + if (value >= 100000) *buffer++ = u_ctn2s[d2]; + *buffer++ = u_ctn2s[d2+1]; + + U_NUM2STR16(buffer, d3); + U_NUM2STR16(buffer+2, d4); + + return (buffer + 4 - start); +# endif + } + + // value = aabbbbbbbb in decimal + + const uint32_t a = value / 100000000; // 1 to 42 + value %= 100000000; + + if (a < 10) *buffer++ = '0' + (char)a; + else + { + U_NUM2STR16(buffer, a); + + buffer += 2; + } + + const __m128i b = Convert8DigitsSSE2(value); + const __m128i ba = _mm_add_epi8(_mm_packus_epi16(_mm_setzero_si128(), b), reinterpret_cast(kAsciiZero)[0]); + const __m128i result = _mm_srli_si128(ba, 8); + + _mm_storel_epi64(reinterpret_cast<__m128i*>(buffer), result); + + return (buffer + 8 - start); +} + +static uint32_t utoa64_sse2(uint64_t value, char* buffer) +{ + char* start = buffer; + + if (value < 100000000) + { + uint32_t v = static_cast(value); + + if (v < 10000) + { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) *buffer++ = u_ctn2s[d1]; + if (v >= 100) *buffer++ = u_ctn2s[d1+1]; + if (v >= 10) *buffer++ = u_ctn2s[d2]; + *buffer++ = u_ctn2s[d2+1]; + + return (buffer - start); + } + + // Experiment shows that in this case SSE2 is slower +# if 0 + const __m128i a = Convert8DigitsSSE2(v); + + // Convert to bytes, add '0' + const __m128i va = _mm_add_epi8(_mm_packus_epi16(a, _mm_setzero_si128()), reinterpret_cast(kAsciiZero)[0]); + + // Count number of digit + const unsigned mask = _mm_movemask_epi8(_mm_cmpeq_epi8(va, reinterpret_cast(kAsciiZero)[0])); + unsigned long digit; +# ifdef _MSC_VER + _BitScanForward(&digit, ~mask | 0x8000); +# else + digit = __builtin_ctz(~mask | 0x8000); +# endif + + // Shift digits to the beginning + __m128i result = ShiftDigits_SSE2(va, digit); + _mm_storel_epi64(reinterpret_cast<__m128i*>(buffer), result); + + return (buffer + 8 - digit - start); +# else + // value = bbbbcccc + const uint32_t b = v / 10000; + const uint32_t c = v % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100); + const uint32_t d4 = (c % 100); + + if (value >= 10000000) *buffer++ = u_ctn2s[d1]; + if (value >= 1000000) *buffer++ = u_ctn2s[d1+1]; + if (value >= 100000) *buffer++ = u_ctn2s[d2]; + *buffer++ = u_ctn2s[d2+1]; + + U_NUM2STR16(buffer, d3); + U_NUM2STR16(buffer+2, d4); + + return (buffer + 4 - start); +# endif + } + + if (value < 10000000000000000) + { + const uint32_t v0 = static_cast(value / 100000000); + const uint32_t v1 = static_cast(value % 100000000); + + const __m128i a0 = Convert8DigitsSSE2(v0); + const __m128i a1 = Convert8DigitsSSE2(v1); + + // Convert to bytes, add '0' + const __m128i va = _mm_add_epi8(_mm_packus_epi16(a0, a1), reinterpret_cast(kAsciiZero)[0]); + + // Count number of digit + const unsigned mask = _mm_movemask_epi8(_mm_cmpeq_epi8(va, reinterpret_cast(kAsciiZero)[0])); +# ifdef _MSC_VER + unsigned long digit; + _BitScanForward(&digit, ~mask | 0x8000); +# else + unsigned digit = __builtin_ctz(~mask | 0x8000); +# endif + + // Shift digits to the beginning + __m128i result = ShiftDigits_SSE2(va, digit); + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return (buffer + 16 - digit - start); + } + + const uint32_t a = static_cast(value / 10000000000000000); // 1 to 1844 + value %= 10000000000000000; + + if (a < 10) *buffer++ = '0' + (char)a; + else if (a < 100) + { + U_NUM2STR16(buffer, a); + + buffer += 2; + } + else if (a < 1000) + { + *buffer++ = '0' + static_cast(a / 100); + + const uint32_t i = (a % 100); + + U_NUM2STR16(buffer, i); + + buffer += 2; + } + else + { + const uint32_t i = (a / 100); + const uint32_t j = (a % 100); + + U_NUM2STR16(buffer, i); + U_NUM2STR16(buffer+2, j); + + buffer += 4; + } + + const uint32_t v0 = static_cast(value / 100000000); + const uint32_t v1 = static_cast(value % 100000000); + + const __m128i a0 = Convert8DigitsSSE2(v0); + const __m128i a1 = Convert8DigitsSSE2(v1); + + // Convert to bytes, add '0' + const __m128i va = _mm_add_epi8(_mm_packus_epi16(a0, a1), reinterpret_cast(kAsciiZero)[0]); + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), va); + + return (buffer + 16 - start); +} +#endif diff --git a/src/ulib/json/value.cpp b/src/ulib/json/value.cpp index 13d51f1b..38f365e8 100644 --- a/src/ulib/json/value.cpp +++ b/src/ulib/json/value.cpp @@ -896,11 +896,10 @@ void UValue::stringify(UString& result, UValue& _value) bool bcomma; char* presult; - const char* ch; - char buffer[32]; UString* pstring; - const char* last_nonzero; - uint32_t n, pos, sz, keysz; + uint32_t pos, sz, keysz; + + (void) result.reserve(32); U_INTERNAL_DUMP("dispatch_table[%d] = %p &&case_null = %p", _value.type_, dispatch_table[_value.type_], &&case_null) @@ -928,94 +927,88 @@ case_uchar: return; case_short: - (void) result.append(buffer, u_num2str32s(_value.value.short_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str32s(_value.value.short_, presult); return; case_ushort: - (void) result.append(buffer, u_num2str32(_value.value.ushort_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str32(_value.value.ushort_, presult); return; case_int: - (void) result.append(buffer, u_num2str32s(_value.value.int_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str32s(_value.value.int_, presult); return; case_uint: - (void) result.append(buffer, u_num2str32s(_value.value.uint_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str32(_value.value.uint_, presult); return; case_long: - (void) result.append(buffer, u_num2str64s(_value.value.long_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str64s(_value.value.long_, presult); return; case_ulong: - (void) result.append(buffer, u_num2str64s(_value.value.ulong_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str64(_value.value.ulong_, presult); return; case_llong: - (void) result.append(buffer, u_num2str64s(_value.value.llong_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str64s(_value.value.llong_, presult); return; case_ullong: - (void) result.append(buffer, u_num2str64s(_value.value.ullong_, buffer)); + presult = result.c_pointer(sz = result.size()); + + result.rep->_length = sz + u_num2str64(_value.value.ullong_, presult); return; case_float: - n = u__snprintf(buffer, sizeof(buffer), "%#.6f", _value.value.float_); + presult = result.c_pointer(sz = result.size()); - goto next; + result.rep->_length = sz + u_dtoa(_value.value.float_, presult); + + return; case_double: - n = u__snprintf(buffer, sizeof(buffer), "%#.16g", _value.value.real_); + presult = result.c_pointer(sz = result.size()); - goto next; + result.rep->_length = sz + u_dtoa(_value.value.real_, presult); + + return; case_ldouble: - n = u__snprintf(buffer, sizeof(buffer), "%#.16g", _value.value.lreal_); + presult = result.c_pointer(sz = result.size()); -next: - ch = buffer + n - 1; - - if (*ch == '0') - { - while (ch > buffer && *ch == '0') --ch; - - last_nonzero = ch; - - while (ch >= buffer) - { - char c = *ch; - - if (u__isdigit(c)) - { - --ch; - - continue; - } - - if (c == '.') n = last_nonzero - buffer + 2; // Truncate zeroes to save bytes in output, but keep one - - break; - } - } - - (void) result.append(buffer, n); + result.rep->_length = sz + u_dtoa(_value.value.lreal_, presult); return; case_string: pstring = (UString*)_value.value.ptr_; - (void) result.reserve((sz = result.size()) + (keysz = pstring->size()) * 6); + (void) result.reserve((keysz = pstring->size()) * 6); - presult = result.c_pointer(sz); + presult = result.c_pointer(sz = result.size()); result.rep->_length = sz + emitString((const unsigned char*)pstring->data(), keysz, presult); @@ -1044,9 +1037,9 @@ case_object: { U_INTERNAL_ASSERT_POINTER(member->key) - (void) result.reserve((sz = result.size()) + (keysz = member->key->size()) * 6); + (void) result.reserve((keysz = member->key->size()) * 6); - presult = result.c_pointer(sz); + presult = result.c_pointer(sz = result.size()); if (bcomma == false) bcomma = true; else @@ -2110,55 +2103,53 @@ const char* UValue::getJReadErrorDescription() "End of object found" // 14 }; - const char* descr = (jread_error >= 0 && jread_error <= 14 ? errlist[jread_error] : "Unknown jread error"); + const char* descr = (jread_error >= 0 && (int)U_NUM_ELEMENTS(errlist) ? errlist[jread_error] : "Unknown jread error"); U_RETURN(descr); } -# define U_VAL_ENTRY(n) n: descr = #n; break - const char* UValue::getDataTypeDescription(int type) { U_TRACE(0, "UValue::getDataTypeDescription(%d)", type) - const char* descr; + struct data_type_info { + int value; // The numeric value + const char* name; // The equivalent symbolic value + }; - switch (type) - { - case U_VAL_ENTRY(NULL_VALUE); - case U_VAL_ENTRY(BOOLEAN_VALUE); - case U_VAL_ENTRY(CHAR_VALUE); - case U_VAL_ENTRY(UCHAR_VALUE); - case U_VAL_ENTRY(SHORT_VALUE); - case U_VAL_ENTRY(USHORT_VALUE); - case U_VAL_ENTRY(INT_VALUE); - case U_VAL_ENTRY(UINT_VALUE); - case U_VAL_ENTRY(LONG_VALUE); - case U_VAL_ENTRY(ULONG_VALUE); - case U_VAL_ENTRY(LLONG_VALUE); - case U_VAL_ENTRY(ULLONG_VALUE); - case U_VAL_ENTRY(FLOAT_VALUE); - case U_VAL_ENTRY(REAL_VALUE); - case U_VAL_ENTRY(LREAL_VALUE); - case U_VAL_ENTRY(STRING_VALUE); - case U_VAL_ENTRY(ARRAY_VALUE); - case U_VAL_ENTRY(OBJECT_VALUE); - case U_VAL_ENTRY(NUMBER_VALUE); - case U_VAL_ENTRY(U_JR_EOL); - case U_VAL_ENTRY(U_JR_COLON); - case U_VAL_ENTRY(U_JR_COMMA); - case U_VAL_ENTRY(U_JR_EARRAY); - case U_VAL_ENTRY(U_JR_QPARAM); - case U_VAL_ENTRY(U_JR_EOBJECT); + static const struct data_type_info data_type_table[] = { + U_ENTRY(NULL_VALUE), + U_ENTRY(BOOLEAN_VALUE), + U_ENTRY(CHAR_VALUE), + U_ENTRY(UCHAR_VALUE), + U_ENTRY(SHORT_VALUE), + U_ENTRY(USHORT_VALUE), + U_ENTRY(INT_VALUE), + U_ENTRY(UINT_VALUE), + U_ENTRY(LONG_VALUE), + U_ENTRY(ULONG_VALUE), + U_ENTRY(LLONG_VALUE), + U_ENTRY(ULLONG_VALUE), + U_ENTRY(FLOAT_VALUE), + U_ENTRY(REAL_VALUE), + U_ENTRY(LREAL_VALUE), + U_ENTRY(STRING_VALUE), + U_ENTRY(ARRAY_VALUE), + U_ENTRY(OBJECT_VALUE), + U_ENTRY(NUMBER_VALUE), + U_ENTRY(U_JR_EOL), + U_ENTRY(U_JR_COLON), + U_ENTRY(U_JR_COMMA), + U_ENTRY(U_JR_EARRAY), + U_ENTRY(U_JR_QPARAM), + U_ENTRY(U_JR_EOBJECT) + }; - default: descr = "Data type unknown"; - } + const char* descr = (type >= 0 && type < (int)U_NUM_ELEMENTS(data_type_table) ? data_type_table[type].name : "Data type unknown"); U_RETURN(descr); } -# undef U_VAL_ENTRY - const char* UValue::dump(bool _reset) const { #ifdef U_STDCPP_ENABLE diff --git a/src/ulib/net/client/redis.cpp b/src/ulib/net/client/redis.cpp index d8699eab..57b130a9 100644 --- a/src/ulib/net/client/redis.cpp +++ b/src/ulib/net/client/redis.cpp @@ -28,7 +28,7 @@ bool UREDISClient_Base::connect(const char* phost, unsigned int _port) if (env_redis_host == 0) { - UClient_Base::response.snprintf("connection disabled"); + (void) UClient_Base::response.replace(U_CONSTANT_TO_PARAM("connection disabled")); U_RETURN(false); } diff --git a/src/ulib/net/server/plugin/mod_nocat.cpp b/src/ulib/net/server/plugin/mod_nocat.cpp index 31289dbb..de5e4e1e 100644 --- a/src/ulib/net/server/plugin/mod_nocat.cpp +++ b/src/ulib/net/server/plugin/mod_nocat.cpp @@ -1481,10 +1481,11 @@ void UNoCatPlugIn::addPeerInfo(int disconnected) U_INTERNAL_ASSERT(u_now->tv_sec >= peer->ctime) char* ptr; - uint32_t sz; char buffer[64]; UString info = (*vinfo_data)[U_peer_index_AUTH], str = UStringExt::substitute(peer->mac, ':', U_CONSTANT_TO_PARAM("%3A")); + uint32_t sz = info.size(); + U_INTERNAL_DUMP("U_peer_index_AUTH = %u info = %V peer->ip = %V", U_peer_index_AUTH, info.rep, peer->ip.rep) // ------------------------------------------------------------------------------------------------------------------------------------------ @@ -1500,7 +1501,7 @@ void UNoCatPlugIn::addPeerInfo(int disconnected) // /info?Mac=98%3A0c%3A82%3A76%3A3b%3A39&ip=172.16.1.8&gateway=172.16.1.254%3A5280&ap=ap%4010.8.0.1&User=1212&logout=-1&connected=3&traffic=0 // ------------------------------------------------------------------------------------------------------------------------------------------ - (void) info.reserve((sz = info.size()) + 200U); + (void) info.reserve(200U); info.snprintf_add("%.*sMac=%v&ip=%v&", (sz > 0), "&", str.rep, peer->ip.rep); @@ -1557,10 +1558,11 @@ void UNoCatPlugIn::addPeerRoaming() U_INTERNAL_ASSERT(peer->mac) U_INTERNAL_ASSERT(peer->user) - uint32_t sz; char buffer[64]; UString data = (*vroaming_data)[U_peer_index_AUTH], str = UStringExt::substitute(peer->mac, ':', U_CONSTANT_TO_PARAM("%3A")); + uint32_t sz = data.size(); + U_INTERNAL_DUMP("U_peer_index_AUTH = %u data = %V peer->ip = %V", U_peer_index_AUTH, data.rep, peer->ip.rep) // ------------------------------------------------------------------------------------------------------------- @@ -1573,7 +1575,7 @@ void UNoCatPlugIn::addPeerRoaming() // /roaming?Mac=98%3A0c%3A82%3A76%3A3b%3A39&ip=172.16.1.8&gateway=172.16.1.254%3A5280&ap=ap%4010.8.0.1&User=1212 // ------------------------------------------------------------------------------------------------------------- - (void) data.reserve((sz = data.size()) + 200U); + (void) data.reserve(200U); data.snprintf_add("%.*sMac=%v&ip=%v&", (sz > 0), "&", str.rep, peer->ip.rep); diff --git a/src/ulib/net/server/plugin/usp/businesses.usp b/src/ulib/net/server/plugin/usp/businesses.usp index 530ad5fb..51ebfbf1 100644 --- a/src/ulib/net/server/plugin/usp/businesses.usp +++ b/src/ulib/net/server/plugin/usp/businesses.usp @@ -253,11 +253,7 @@ private: HTTP2Push& operator=(const HTTP2Push&) { return *this; } }; -static UValue* pvalue; -static Request* prequest; static UMongoDBClient* mc; -static Response* presponse; -static UVector* pvresponse; static void usp_init_businesses() { @@ -289,11 +285,6 @@ static void usp_fork_businesses() return; } - - U_NEW(Request, prequest, Request); - U_NEW(Response, presponse, Response); - U_NEW(UValue, pvalue, UValue(ARRAY_VALUE)); - U_NEW(UVector, pvresponse, UVector); } #ifdef DEBUG @@ -302,14 +293,6 @@ static void usp_end_businesses() U_TRACE(5, "::usp_end_businesses()") delete mc; - - if (pvalue) - { - delete pvalue; - delete prequest; - delete presponse; - delete pvresponse; - } } #endif --> @@ -317,43 +300,18 @@ static void usp_end_businesses() Content-Type: application/json --> diff --git a/src/ulib/orm/driver/orm_driver_sqlite.cpp b/src/ulib/orm/driver/orm_driver_sqlite.cpp index 225a19b5..a5fcc624 100644 --- a/src/ulib/orm/driver/orm_driver_sqlite.cpp +++ b/src/ulib/orm/driver/orm_driver_sqlite.cpp @@ -45,10 +45,10 @@ void UOrmDriverSqlite::handlerError() U_ENTRY(SQLITE_PERM), /* Access permission denied */ U_ENTRY(SQLITE_ABORT), /* Callback routine requested an abort */ U_ENTRY(SQLITE_BUSY), /* The database file is locked */ - U_ENTRY(SQLITE_LOCKED), /* A table in the database is locked */ + U_ENTRY(SQLITE_LOCKED), /* A table in the database is locked */ U_ENTRY(SQLITE_NOMEM), /* A malloc() failed */ U_ENTRY(SQLITE_READONLY), /* Attempt to write a readonly database */ - U_ENTRY(SQLITE_INTERRUPT), /* Operation terminated by sqlite3_interrupt()*/ + U_ENTRY(SQLITE_INTERRUPT), /* Operation terminated by sqlite3_interrupt()*/ U_ENTRY(SQLITE_IOERR), /* Some kind of disk I/O error occurred */ U_ENTRY(SQLITE_CORRUPT), /* The database disk image is malformed */ U_ENTRY(SQLITE_NOTFOUND), /* Unknown opcode in sqlite3_file_control() */ @@ -56,24 +56,24 @@ void UOrmDriverSqlite::handlerError() U_ENTRY(SQLITE_CANTOPEN), /* Unable to open the database file */ U_ENTRY(SQLITE_PROTOCOL), /* Database lock protocol error */ U_ENTRY(SQLITE_EMPTY), /* Database is empty */ - U_ENTRY(SQLITE_SCHEMA), /* The database schema changed */ - U_ENTRY(SQLITE_TOOBIG), /* String or BLOB exceeds size limit */ + U_ENTRY(SQLITE_SCHEMA), /* The database schema changed */ + U_ENTRY(SQLITE_TOOBIG), /* String or BLOB exceeds size limit */ U_ENTRY(SQLITE_CONSTRAINT), /* Abort due to constraint violation */ U_ENTRY(SQLITE_MISMATCH), /* Data type mismatch */ - U_ENTRY(SQLITE_MISUSE), /* Library used incorrectly */ + U_ENTRY(SQLITE_MISUSE), /* Library used incorrectly */ U_ENTRY(SQLITE_NOLFS), /* Uses OS features not supported on host */ U_ENTRY(SQLITE_AUTH), /* Authorization denied */ - U_ENTRY(SQLITE_FORMAT), /* Auxiliary database format error */ + U_ENTRY(SQLITE_FORMAT), /* Auxiliary database format error */ U_ENTRY(SQLITE_RANGE), /* 2nd parameter to sqlite3_bind out of range */ - U_ENTRY(SQLITE_NOTADB), /* File opened that is not a database file */ + U_ENTRY(SQLITE_NOTADB), /* File opened that is not a database file */ # ifdef SQLITE_NOTICE - U_ENTRY(SQLITE_NOTICE), /* Notifications from sqlite3_log() */ + U_ENTRY(SQLITE_NOTICE), /* Notifications from sqlite3_log() */ # endif # ifdef SQLITE_WARNING U_ENTRY(SQLITE_WARNING), /* Warnings from sqlite3_log() */ # endif - U_ENTRY(SQLITE_ROW), /* sqlite3_step() has another row ready */ - U_ENTRY(SQLITE_DONE) /* sqlite3_step() has finished executing */ + U_ENTRY(SQLITE_ROW), /* sqlite3_step() has another row ready */ + U_ENTRY(SQLITE_DONE) /* sqlite3_step() has finished executing */ }; if (UOrmDriver::errmsg == 0) UOrmDriver::errmsg = U_SYSCALL(sqlite3_errmsg, "%p", (sqlite3*)UOrmDriver::connection); diff --git a/src/ulib/string.cpp b/src/ulib/string.cpp index a0efdcfd..ff509195 100644 --- a/src/ulib/string.cpp +++ b/src/ulib/string.cpp @@ -1923,7 +1923,7 @@ float UStringRep::strtof() const char* endptr; float result = ::strtof(str, &endptr); - U_INTERNAL_ASSERT_MINOR(endptr, eos) + U_INTERNAL_ASSERT(endptr <= eos) # endif U_INTERNAL_DUMP("errno = %d", errno) @@ -1951,7 +1951,7 @@ double UStringRep::strtod() const char* endptr; double result = ::strtod(str, &endptr); - U_INTERNAL_ASSERT_MINOR(endptr, eos) + U_INTERNAL_ASSERT(endptr <= eos) # endif U_INTERNAL_DUMP("errno = %d", errno) diff --git a/src/ulib/utility/string_ext.cpp b/src/ulib/utility/string_ext.cpp index 124d84da..98e8ffc1 100644 --- a/src/ulib/utility/string_ext.cpp +++ b/src/ulib/utility/string_ext.cpp @@ -146,8 +146,8 @@ UString UStringExt::numberToString(uint64_t n) { U_TRACE(0, "UStringExt::numberToString(%llu)", n) - unsigned int i; UString x(32U); + unsigned int i; uint64_t u = 1024ULL; for (i = 0; i < U_CONSTANT_SIZE("bKMGTPEZY"); ++i) @@ -189,7 +189,7 @@ UString UStringExt::expandTab(const char* s, uint32_t n, int tab) { len = _end - start; - (void) x.reserve(x.size() + len + tab); + (void) x.reserve(len + tab); if (len) { @@ -242,7 +242,7 @@ UString UStringExt::substitute(const char* s, uint32_t n, const char* a, uint32_ U_INTERNAL_DUMP("start = %u _end = %u len = %u", start, _end, len) - (void) x.reserve(x.size() + len + n2); + (void) x.reserve(len + n2); if (len) { diff --git a/src/ulib/utility/uhttp.cpp b/src/ulib/utility/uhttp.cpp index 7133dc97..9296af01 100644 --- a/src/ulib/utility/uhttp.cpp +++ b/src/ulib/utility/uhttp.cpp @@ -3843,7 +3843,6 @@ manage: #if defined(DEBUG) && !defined(U_STATIC_ONLY) if (file_data == 0 && - isGETorHEAD() && U_http_is_nocache_file && file->getSuffix().empty()) { @@ -3862,6 +3861,8 @@ manage: manageDataForCache(); U_INTERNAL_ASSERT_POINTER(file_data) + + UClientImage_Base::setRequestInFileCache(); } } #endif @@ -4846,7 +4847,8 @@ void UHTTP::clearSessionSSL() * in pair with user login, and sends session id to browser in response as cookie. Browser stores cookie. * 3) User visits any page on this domain and browser sends a cookie to server for each request. * 4) ULib server checks if cookie has been sent, if such cookie exists in server storage with pair with login. Identifies user, provides access to his private content. - * 5) Logout button removes the cookie from browser and sid-login pair from server storage. Browser does not send cookies, server does not see it and does not see sid-login pair + * 5) Logout button removes the cookie from browser and sid-login pair from server storage. Browser does not send cookies, server does not see it and does not see + * sid-login pair */ void UHTTP::addSetCookie(const UString& cookie) @@ -5391,7 +5393,7 @@ __pure int UHTTP::getFormFirstNumericValue(int _min, int _max) U_INTERNAL_DUMP("query = %.*S", U_HTTP_QUERY_TO_TRACE) - do { ++ptr; } while (*ptr != '='); + ptr = (const char*) memchr(ptr, '=', U_http_info.query_len); if (u__isdigit(*++ptr)) { @@ -5516,6 +5518,7 @@ uint32_t UHTTP::processForm() { U_ASSERT(isPOST()) + // ------------------------------------------------------------------------- // POST // ------------------------------------------------------------------------- // Content-Type: application/x-www-form-urlencoded OR multipart/form-data... @@ -5773,7 +5776,10 @@ void UHTTP::handlerResponse() { U_INTERNAL_DUMP("U_http_method_not_implemented = %b", U_http_method_not_implemented) - if (U_http_method_not_implemented) (void) UClientImage_Base::wbuffer->assign(U_CONSTANT_TO_PARAM("Your browser request a method that this server has not implemented")); + if (U_http_method_not_implemented) + { + (void) UClientImage_Base::wbuffer->assign(U_CONSTANT_TO_PARAM("Your browser request a method that this server has not implemented")); + } else { (void) UClientImage_Base::wbuffer->assign(U_CONSTANT_TO_PARAM("Allow: " @@ -6194,21 +6200,30 @@ void UHTTP::setDynamicResponse() ptr = ext->data(); -#ifdef USE_LIBZ +#ifndef USE_LIBZ + bool bcompress = false; +#else bool bcompress = (U_http_is_accept_gzip && UClientImage_Base::wbuffer->size() > (U_http_info.endHeader + U_MIN_SIZE_FOR_DEFLATE)); -#else - bool bcompress = false; #endif U_INTERNAL_DUMP("bcompress = %b", bcompress) if (U_http_info.endHeader) { - U_INTERNAL_ASSERT_MAJOR(clength, U_http_info.endHeader) + U_INTERNAL_ASSERT(clength >= U_http_info.endHeader) clength -= U_http_info.endHeader; + if (clength == 0) // no response + { + UClientImage_Base::body->clear(); // clean body to avoid writev() in response... + + UClientImage_Base::wbuffer->clear(); + + goto no_response; + } + pEndHeader = UClientImage_Base::wbuffer->data(); if (bcompress == false) goto no_compress; @@ -6338,6 +6353,7 @@ end: ext->size_adjust(ptr1); +no_response: handlerResponse(); } @@ -8903,7 +8919,7 @@ U_NO_EXPORT void UHTTP::setCGIShellScript(UString& command) c = (memchr(ptr, '"', sz) ? '\'' : '"'); } - (void) command.reserve(command.size() + sz + 4U); + (void) command.reserve(sz + 4U); command.snprintf_add(" %c%.*s%c ", c, sz, ptr, c); } @@ -9440,7 +9456,9 @@ loop: UClientImage_Base::body->clear(); - (void) set_cookie->append(UClientImage_Base::wbuffer->data(), sz - U_CONSTANT_SIZE(U_CRLF)); // NB: we use the var 'set_cookie' for opportunism within handlerResponse()... + // NB: we use the var 'set_cookie' for opportunism within handlerResponse()... + + (void) set_cookie->append(UClientImage_Base::wbuffer->data(), sz - U_CONSTANT_SIZE(U_CRLF)); setResponse(); diff --git a/tests/base/ok/sprintf.ok b/tests/base/ok/sprintf.ok index 81cb47c5..5af1bea2 100644 --- a/tests/base/ok/sprintf.ok +++ b/tests/base/ok/sprintf.ok @@ -94,7 +94,6 @@ prefix 6d 6o 6x 6X 6u 123.456 should be 123.456 10 should be 10 0.02 should be 0.02 -0.10000000000000001 Test ok. sprintf (buf, "%07llo", 040000000000ll) = 40000000000 printf ("%c", 257) =  diff --git a/tests/base/sprintf.test b/tests/base/sprintf.test index 6bd2db10..9f11c5fd 100755 --- a/tests/base/sprintf.test +++ b/tests/base/sprintf.test @@ -9,4 +9,4 @@ start_msg sprintf start_prg sprintf # Test against expected output -test_output_wc w sprintf +test_output_diff sprintf diff --git a/tests/base/test_sprintf.c b/tests/base/test_sprintf.c index 5e69d400..8cdca9c8 100644 --- a/tests/base/test_sprintf.c +++ b/tests/base/test_sprintf.c @@ -138,8 +138,6 @@ static void test3(void) char buf[200]; const char* tmp; - printf("%.17f\n",(1.0/x/10.0+1.0)*x-x); - u__snprintf(buf,sizeof(buf),"%*s%*s%*s",-1,"one",-20,"two",-30,"three"); result |= strcmp(buf, "onetwo three "); tmp = (result != 0 ? "Test failed!" : "Test ok."); diff --git a/tests/examples/businesses.test b/tests/examples/businesses.test index 393560eb..ab742ea5 100755 --- a/tests/examples/businesses.test +++ b/tests/examples/businesses.test @@ -50,8 +50,8 @@ DIR_CMD="../../examples/userver" start_prg_background userver_tcp -c inp/webserver.cfg -send_req $NCAT localhost 8080 inp/http/businesses.req businesses 2 -send_req $NCAT localhost 8080 inp/http/businesses.req businesses 2 +send_req $NCAT localhost 8080 inp/http/businesses1.req businesses 2 +send_req $NCAT localhost 8080 inp/http/businesses2.req businesses 2 kill_prg userver_tcp TERM diff --git a/tests/examples/inp/http/businesses1.req b/tests/examples/inp/http/businesses1.req new file mode 100644 index 00000000..4c1074dd --- /dev/null +++ b/tests/examples/inp/http/businesses1.req @@ -0,0 +1,7 @@ +POST /servlet/businesses HTTP/1.1 +Host: localhost:8080 +Connection: Keep-Alive +Content-Type: application/jsonrequest +Content-Length: 106 + +{ "token": "A619828KAIJ6D3", "type": "localesData", "radius": "near", "location": "40.7831 N, 73.9712 W" } diff --git a/tests/examples/inp/http/businesses2.req b/tests/examples/inp/http/businesses2.req new file mode 100644 index 00000000..10703657 --- /dev/null +++ b/tests/examples/inp/http/businesses2.req @@ -0,0 +1,7 @@ +POST /servlet/businesses HTTP/1.1 +Host: localhost:8080 +Connection: Keep-Alive +Content-Type: application/jsonrequest +Content-Length: 106 + +{ "token": "A619828KAIJ6D3", "type": "localesDita", "radius": "near", "location": "40.7831 N, 73.9712 W" } diff --git a/tests/examples/ok/businesses.ok b/tests/examples/ok/businesses.ok index bb459721..a4d5a193 100644 --- a/tests/examples/ok/businesses.ok +++ b/tests/examples/ok/businesses.ok @@ -1,15 +1,13 @@ HTTP/1.1 200 OK -Date: Thu, 21 Apr 2016 13:40:48 GMT +Date: Sat, 10 Sep 2016 16:16:24 GMT Server: ULib Connection: close -Content-Length: 418 +Content-Length: 56 Content-Type: application/json -[{"name":"Business 1","rating":"Red","address":"123 park lane, New York, NY, USA 10028","phone":"12126465788","url":"www.business1.com"},{"name":"Business 2","rating":"Yellow","address":"837 mott street, New York, NY, USA 10019","phone":"12124829384","url":"www.business2.com"},{"name":"Business 3","rating":"Green","address":"838 mott street, New York, NY, USA 10019","phone":"12124829385","url":"www.business3.com"}]HTTP/1.1 200 OK -Date: Thu, 21 Apr 2016 13:40:49 GMT +{"name":"","rating":"","address":"","phone":"","url":""}HTTP/1.1 200 OK +Date: Sat, 10 Sep 2016 16:16:24 GMT Server: ULib Connection: close -Content-Length: 418 -Content-Type: application/json +Content-Length: 0 -[{"name":"Business 1","rating":"Red","address":"123 park lane, New York, NY, USA 10028","phone":"12126465788","url":"www.business1.com"},{"name":"Business 2","rating":"Yellow","address":"837 mott street, New York, NY, USA 10019","phone":"12124829384","url":"www.business2.com"},{"name":"Business 3","rating":"Green","address":"838 mott street, New York, NY, USA 10019","phone":"12124829385","url":"www.business3.com"}] \ No newline at end of file diff --git a/tests/ulib/json.test b/tests/ulib/json.test index 83cb95ff..7a3c848f 100755 --- a/tests/ulib/json.test +++ b/tests/ulib/json.test @@ -16,4 +16,4 @@ unset UMEMPOOL start_prg json < inp/json.input # Test against expected output -test_output_wc l json +test_output_diff json diff --git a/tests/ulib/ok/json.ok b/tests/ulib/ok/json.ok deleted file mode 100644 index ec59666e..00000000 --- a/tests/ulib/ok/json.ok +++ /dev/null @@ -1,66 +0,0 @@ -randomNumber = "9342" -{"Extra value after close":true} -{"Numbers cannot have leading zeroes":13} -["Illegal backslash escape: \u0015"] -["Illegal backslash escape: \u000F"] -[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] -["Unclosed array"] -["\ttab\tcharacter\tin\tstring\t"] -["tab character in string "] -["line\nbreak"] -["line\nbreak"] -[0.0] -[0.0] -[0.0] -["<-- missing value"] -["Comma after the close"] -["Extra close"] -{"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$gCal":"http://schemas.google.com/gCal/2005","xmlns$gd":"http://schemas.google.com/g/2005","id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full"},"updated":{"$t":"2010-08-10T14:53:58.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Official Google External Developer Events","type":"text"},"subtitle":{"$t":"The calendar contains information about upcoming developer conferences at which Google will be speaking, along with other developer-related events.","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/embed?src=developer-calendar@google.com"},{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full"},{"rel":"http://schemas.google.com/g/2005#batch","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/batch"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full?alt=json&max-results=25"},{"rel":"next","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full?alt=json&start-index=26&max-results=25"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"generator":{"$t":"Google Calendar","version":"1.0","uri":"http://www.google.com/calendar"},"openSearch$totalResults":{"$t":430},"openSearch$startIndex":{"$t":1},"openSearch$itemsPerPage":{"$t":25},"gCal$timezone":{"value":"America/Los_Angeles"},"gCal$timesCleaned":{"value":0},"entry":[{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4_20100811T180000Z"},"published":{"$t":"2010-04-06T21:17:09.000Z"},"updated":{"$t":"2010-08-10T02:59:23.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Wave API Office Hours","type":"text"},"content":{"$t":"Members of the Google Wave API engineering team will be available in Google Wave Preview to answer questions about building robots or gadgets or embedding waves. \nFollow this wave to be notified when office hours are starting:\nhttps://wave.google.com/wave/#restored:search:in%253AInbox,restored:wave:googlewave.com!w%252BFICYnJWoL","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=anM2ZjAxNDMxMGQwOTh2OTliaHM5ODdrczRfMjAxMDA4MTFUMTgwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4_20100811T180000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4_20100811T180000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.canceled"},"gd$where":[{"valueString":"Google Wave Preview"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4","id":"js6f014310d098v99bhs987ks4","gd$when":{"startTime":"2010-08-11T11:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-08-11T12:00:00.000-07:00","startTime":"2010-08-11T11:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"js6f014310d098v99bhs987ks4@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/86ov9cs2g29195t96i4oud1g24_20100805T060000Z"},"published":{"$t":"2010-01-05T00:32:19.000Z"},"updated":{"$t":"2010-08-09T23:18:40.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Google Wave API Office Hours","type":"text"},"content":{"$t":"Members of the Google Wave API engineering team will be available in Wave to answer questions about building robots or gadgets or embedding waves. ","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=ODZvdjljczJnMjkxOTV0OTZpNG91ZDFnMjRfMjAxMDA4MDVUMDYwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/86ov9cs2g29195t96i4oud1g24_20100805T060000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/86ov9cs2g29195t96i4oud1g24_20100805T060000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.canceled"},"gd$where":[{"valueString":"https://wave.google.com/wave/"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/86ov9cs2g29195t96i4oud1g24","id":"86ov9cs2g29195t96i4oud1g24","gd$when":{"startTime":"2010-08-04T23:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-08-05T00:00:00.000-07:00","startTime":"2010-08-04T23:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":2},"gCal$uid":{"value":"86ov9cs2g29195t96i4oud1g24@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/gtl3e8fv17kjh2cibk2p37fg3s"},"published":{"$t":"2010-07-31T18:22:26.000Z"},"updated":{"$t":"2010-08-09T23:18:40.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"DevFest Madrid","type":"text"},"content":{"$t":"","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=Z3RsM2U4ZnYxN2tqaDJjaWJrMnAzN2ZnM3MgZGV2ZWxvcGVyLWNhbGVuZGFyQGdvb2dsZS5jb20","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/gtl3e8fv17kjh2cibk2p37fg3s"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/gtl3e8fv17kjh2cibk2p37fg3s/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":""}],"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-09-24","startTime":"2010-09-23"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.transparent"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"gtl3e8fv17kjh2cibk2p37fg3s@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4_20100728T180000Z"},"published":{"$t":"2010-04-06T21:17:09.000Z"},"updated":{"$t":"2010-08-09T23:18:39.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Wave API Office Hours","type":"text"},"content":{"$t":"Members of the Google Wave API engineering team will be available in Google Wave Preview to answer questions about building robots or gadgets or embedding waves. \nFollow this wave to be notified when office hours are starting:\nhttps://wave.google.com/wave/#restored:search:in%253AInbox,restored:wave:googlewave.com!w%252BFICYnJWoL","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=anM2ZjAxNDMxMGQwOTh2OTliaHM5ODdrczRfMjAxMDA3MjhUMTgwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4_20100728T180000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4_20100728T180000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.canceled"},"gd$where":[{"valueString":"Google Wave Preview"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/js6f014310d098v99bhs987ks4","id":"js6f014310d098v99bhs987ks4","gd$when":{"startTime":"2010-07-28T11:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-07-28T12:00:00.000-07:00","startTime":"2010-07-28T11:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"js6f014310d098v99bhs987ks4@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/tccdtqm6cgbfoloq2a9hb45au4"},"published":{"$t":"2010-01-08T23:10:35.000Z"},"updated":{"$t":"2010-08-09T23:18:39.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"GUADEC","type":"text"},"content":{"$t":"http://www.guadec.org/index.php/guadec/index\n\nGoogle returns as a sponsor","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=dGNjZHRxbTZjZ2Jmb2xvcTJhOWhiNDVhdTQgZGV2ZWxvcGVyLWNhbGVuZGFyQGdvb2dsZS5jb20","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/tccdtqm6cgbfoloq2a9hb45au4"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/tccdtqm6cgbfoloq2a9hb45au4/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"The Hague, Netherlands @ 52.083333, 4.316667"}],"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-07-31","startTime":"2010-07-23"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.transparent"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"tccdtqm6cgbfoloq2a9hb45au4@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/rcciaon58un0s7093g6811c5ns"},"published":{"$t":"2010-07-26T21:39:41.000Z"},"updated":{"$t":"2010-08-09T23:18:39.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"GTUG Campout (HTML5)","type":"text"},"content":{"$t":"http://www.meetup.com/GTUG-Campout/","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=cmNjaWFvbjU4dW4wczcwOTNnNjgxMWM1bnMgZGV2ZWxvcGVyLWNhbGVuZGFyQGdvb2dsZS5jb20","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/rcciaon58un0s7093g6811c5ns"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/rcciaon58un0s7093g6811c5ns/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"Multiple cities"}],"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-08-16","startTime":"2010-08-13"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.transparent"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"rcciaon58un0s7093g6811c5ns@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/7u0m5c29msln7lfqf62oia77qk"},"published":{"$t":"2010-08-02T15:25:17.000Z"},"updated":{"$t":"2010-08-09T23:18:39.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Google Apps Script Hackathon - Mountain View, CA","type":"text"},"content":{"$t":"Please join us on September 23, 2010 for an Apps Script hackathon in Mountain View, CA. \nRegister here: http://sites.google.com/site/appsscripthackathonmtv/","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=N3UwbTVjMjltc2xuN2xmcWY2Mm9pYTc3cWsgZGV2ZWxvcGVyLWNhbGVuZGFyQGdvb2dsZS5jb20","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/7u0m5c29msln7lfqf62oia77qk"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/7u0m5c29msln7lfqf62oia77qk/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"Google, 1600 Amphitheatre Parkway, Mountain View, CA 94043"}],"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-09-23T20:00:00.000-07:00","startTime":"2010-09-23T14:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"7u0m5c29msln7lfqf62oia77qk@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/ouls6kh853ajk6s8pgo6j7mmh8"},"published":{"$t":"2010-07-31T06:50:38.000Z"},"updated":{"$t":"2010-08-09T23:18:38.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Google Developer Day GTUG Bootcamp","type":"text"},"content":{"$t":"","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=b3VsczZraDg1M2FqazZzOHBnbzZqN21taDggZGV2ZWxvcGVyLWNhbGVuZGFyQGdvb2dsZS5jb20","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/ouls6kh853ajk6s8pgo6j7mmh8"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/ouls6kh853ajk6s8pgo6j7mmh8/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"東京国際フォーラム、東京都千代田区丸の内 3-5-1"}],"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-09-27T01:00:00.000-07:00","startTime":"2010-09-26T21:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"ouls6kh853ajk6s8pgo6j7mmh8@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100730T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-28T17:42:29.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA3MzBUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100730T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100730T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-07-29T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.declined"}}],"gd$when":[{"endTime":"2010-07-29T18:00:00.000-07:00","startTime":"2010-07-29T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100716T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA3MTZUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100716T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100716T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-07-15T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-07-15T18:00:00.000-07:00","startTime":"2010-07-15T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100702T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA3MDJUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100702T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100702T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-07-01T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-07-01T18:00:00.000-07:00","startTime":"2010-07-01T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100625T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA2MjVUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100625T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100625T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-06-24T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-06-24T18:00:00.000-07:00","startTime":"2010-06-24T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100611T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA2MTFUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100611T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100611T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-06-10T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-06-10T18:00:00.000-07:00","startTime":"2010-06-10T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100604T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA2MDRUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100604T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100604T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-06-03T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-06-03T18:00:00.000-07:00","startTime":"2010-06-03T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100528T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA1MjhUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100528T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100528T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-05-27T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-05-27T18:00:00.000-07:00","startTime":"2010-05-27T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100521T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA1MjFUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100521T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100521T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-05-20T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-05-20T18:00:00.000-07:00","startTime":"2010-05-20T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100514T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDA1MTRUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100514T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100514T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-05-13T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-05-13T18:00:00.000-07:00","startTime":"2010-05-13T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100326T000000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAzMjZUMDAwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100326T000000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100326T000000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-03-25T17:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-03-25T18:00:00.000-07:00","startTime":"2010-03-25T17:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100305T010000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAzMDVUMDEwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100305T010000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100305T010000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-03-04T17:00:00.000-08:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-03-04T18:00:00.000-08:00","startTime":"2010-03-04T17:00:00.000-08:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100226T010000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAyMjZUMDEwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100226T010000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100226T010000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-02-25T17:00:00.000-08:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-02-25T18:00:00.000-08:00","startTime":"2010-02-25T17:00:00.000-08:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100219T010000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAyMTlUMDEwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100219T010000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100219T010000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-02-18T17:00:00.000-08:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-02-18T18:00:00.000-08:00","startTime":"2010-02-18T17:00:00.000-08:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100212T010000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAyMTJUMDEwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100212T010000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100212T010000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-02-11T17:00:00.000-08:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-02-11T18:00:00.000-08:00","startTime":"2010-02-11T17:00:00.000-08:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100122T010000Z"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAxMjJUMDEwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100122T010000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00_20100122T010000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00","id":"503f9q9o4mqmhds5ilqk50er00","gd$when":{"startTime":"2010-01-21T17:00:00.000-08:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$when":[{"endTime":"2010-01-21T18:00:00.000-08:00","startTime":"2010-01-21T17:00:00.000-08:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00"},"published":{"$t":"2010-01-20T17:39:45.000Z"},"updated":{"$t":"2010-07-20T21:29:18.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Android IRC office hours","type":"text"},"content":{"$t":"Get your application development related questions answered every week from android team members. Join us in the #android-dev channel @ irc.freenode.com.\nPost your questions prior to office hours at StackOverflow with tags:\nandroid, from-irc\n","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=NTAzZjlxOW80bXFtaGRzNWlscWs1MGVyMDBfMjAxMDAxMjJUMDEwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/503f9q9o4mqmhds5ilqk50er00"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"#android-dev on irc.freenode.net"}],"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar","gd$attendeeStatus":{"value":"http://schemas.google.com/g/2005#event.invited"}}],"gd$recurrence":{"$t":"DTSTART;TZID=America/Los_Angeles:20100121T170000\r\nDTEND;TZID=America/Los_Angeles:20100121T180000\r\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TH;WKST=SU\r\nBEGIN:VTIMEZONE\r\nTZID:America/Los_Angeles\r\nX-LIC-LOCATION:America/Los_Angeles\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:PDT\r\nDTSTART:19700308T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0800\r\nTZNAME:PST\r\nDTSTART:19701101T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"},"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":4},"gCal$uid":{"value":"503f9q9o4mqmhds5ilqk50er00@google.com"}},{"id":{"$t":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/us34qg9722ghhjh7htvkquoetg_20100624T060000Z"},"published":{"$t":"2010-01-05T00:32:19.000Z"},"updated":{"$t":"2010-07-20T01:33:49.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"$t":"Google Wave API Office Hours","type":"text"},"content":{"$t":"Members of the Google Wave API engineering team will be available in the Wave developer sandbox to answer questions about building robots or gadgets or embedding waves. ","type":"text"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid=dXMzNHFnOTcyMmdoaGpoN2h0dmtxdW9ldGdfMjAxMDA2MjRUMDYwMDAwWiBkZXZlbG9wZXItY2FsZW5kYXJAZ29vZ2xlLmNvbQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/us34qg9722ghhjh7htvkquoetg_20100624T060000Z"}],"author":[{"name":{"$t":"Google Developer Calendar"},"email":{"$t":"developer-calendar@google.com"}}],"gd$comments":{"gd$feedLink":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/us34qg9722ghhjh7htvkquoetg_20100624T060000Z/comments"}},"gd$eventStatus":{"value":"http://schemas.google.com/g/2005#event.confirmed"},"gd$where":[{"valueString":"Wave Preview"}],"gd$originalEvent":{"href":"http://www.google.com/calendar/feeds/developer-calendar%40google.com/public/full/us34qg9722ghhjh7htvkquoetg","id":"us34qg9722ghhjh7htvkquoetg","gd$when":{"startTime":"2010-06-23T23:00:00.000-07:00"}},"gd$who":[{"email":"developer-calendar@google.com","rel":"http://schemas.google.com/g/2005#event.organizer","valueString":"Google Developer Calendar"}],"gd$when":[{"endTime":"2010-06-23T01:00:00.000-07:00","startTime":"2010-06-23T00:00:00.000-07:00"}],"gd$transparency":{"value":"http://schemas.google.com/g/2005#event.opaque"},"gCal$anyoneCanAddSelf":{"value":"false"},"gCal$guestsCanInviteOthers":{"value":"true"},"gCal$guestsCanModify":{"value":"false"},"gCal$guestsCanSeeGuests":{"value":"true"},"gCal$sequence":{"value":0},"gCal$uid":{"value":"us34qg9722ghhjh7htvkquoetg@google.com"}}]}} -["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-4,true,false,null,{"integer":1234567890,"real":-9876.543210,"e":1.234567890000000e-13,"E":1.234567890000000e+34,"":2.345678901200000e+76,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"/ & /","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","0123456789":"digit","special":"`1~!@#$%^&*()_+-={':[,]}|;.?","hex":"䕧覫췯ꯍ","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http://www.JSON.org/","comment":"// /* */":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","/\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?":"A key can be any string"},0.50,98.59999999999999,99.440,1066,10.0,1.0,0.10,1.0,2.0,2.0,"rosebud"] -[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -{"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}} -[] -[1] -[1,2,3,4,5] -[1,"abc",12.30,-] -[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99] -["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","ccccccccccccccccccccccc","dddddddddddddddddddddddddddddddddddddddddddddddddddd"] -{"count":1234,"name":{"aka":"T.E.S.T.","id":123987},"attribute":["random","short","bold",12,{"height":7,"width":64}],"test":{"1":{"2":{"3":{"coord":[1,2]}}}}} -[["A",0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118]] -{} -{"count":1234} -{"count":1234,"name":"test","attribute":"random"} -{"":1234} - -dataType = (18 "NUMBER_VALUE") query = "{'randomNumber'" result(4) = "8427" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (17 "OBJECT_VALUE") query = "" result(254) = "{ \"astring\": \"This is a string\",\n \"number1\": 42,\n \"number2\": -123.45,\n \"anObject\":{\"one\":1,\"two\":{\"obj2.1\":21,\"obj2.2\":22}," UValue::jread_elements = 8 UValue::jread_error = (0 "Ok") -dataType = (17 "OBJECT_VALUE") query = "[1" result(0) = "" UValue::jread_elements = 0 UValue::jread_error = (1 "JSON does not match Query") -dataType = (15 "STRING_VALUE") query = "{'astring'" result(16) = "This is a string" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (18 "NUMBER_VALUE") query = "{'number1'" result(2) = "42" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (18 "NUMBER_VALUE") query = "{'number2'" result(7) = "-123.45" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (17 "OBJECT_VALUE") query = "{'anObject'" result(53) = "{\"one\":1,\"two\":{\"obj2.1\":21,\"obj2.2\":22},\"three\":333}" UValue::jread_elements = 3 UValue::jread_error = (0 "Ok") -dataType = (16 "ARRAY_VALUE") query = "{'anArray'" result(50) = "[0, \"one\", {\"two.0\":20,\"two.1\":21}, 3, [4,44,444]]" UValue::jread_elements = 5 UValue::jread_error = (0 "Ok") -dataType = (0 "NULL_VALUE") query = "{'isnull'" result(4) = "null" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (1 "BOOLEAN_VALUE") query = "{'yes'" result(4) = "true" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (1 "BOOLEAN_VALUE") query = "{'no'" result(5) = "false" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (24 "U_JR_EOBJECT") query = "{'missing'" result(0) = "" UValue::jread_elements = 0 UValue::jread_error = (5 "Object key not found") -dataType = (17 "OBJECT_VALUE") query = "{'anObject'{'two'" result(25) = "{\"obj2.1\":21,\"obj2.2\":22}" UValue::jread_elements = 2 UValue::jread_error = (0 "Ok") -dataType = (18 "NUMBER_VALUE") query = "{'anObject' {'two' {'obj2.2'" result(2) = "22" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (18 "NUMBER_VALUE") query = "{'anObject'{'three'" result(3) = "333" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (15 "STRING_VALUE") query = "{'anArray' [1" result(3) = "one" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (18 "NUMBER_VALUE") query = "{'anArray' [2 {'two.1'" result(2) = "21" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (18 "NUMBER_VALUE") query = "{'anArray' [4 [2" result(3) = "444" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (22 "U_JR_EARRAY") query = "{'anArray' [999" result(0) = "" UValue::jread_elements = 0 UValue::jread_error = (10 "Array element not found (bad index)") -dataType = (17 "OBJECT_VALUE") query = "{3" result(8) = "anObject" UValue::jread_elements = 3 UValue::jread_error = (0 "Ok") -dataType = (17 "OBJECT_VALUE") query = "{'anObject' {1" result(3) = "two" UValue::jread_elements = 1 UValue::jread_error = (0 "Ok") -dataType = (17 "OBJECT_VALUE") query = "{999" result(0) = "" UValue::jread_elements = 8 UValue::jread_error = (11 "Object key not found (bad index)") - -"anArray": = "[0, \"one\", {\"two.0\":20,\"two.1\":21}, 3, [4,44,444]]" -anArray[0] = "0" -anArray[1] = "one" -anArray[2] = "{\"two.0\":20,\"two.1\":21}" -anArray[3] = "3" -anArray[4] = "[4,44,444]" - -anArray[2] objectKey[1] = "two.1" - diff --git a/tests/ulib/test_json.cpp b/tests/ulib/test_json.cpp index b7c43a1e..bbcbcced 100644 --- a/tests/ulib/test_json.cpp +++ b/tests/ulib/test_json.cpp @@ -270,12 +270,24 @@ U_EXPORT main (int argc, char* argv[]) "\"hits\":{\"total\":1,\"max_score\":1.0,\"hits\":[{\"_index\":\"tfb\",\"_type\":\"world\",\"_id\":\"6464\",\"_score\":1.0," "\"_source\":{ \"randomNumber\" : 9342 }}]}}"), filename, content, array, result, result1; - (void) UValue::jread(searchJson, U_STRING_FROM_CONSTANT("{'randomNumber'"), result); + (void) UValue::jfind(searchJson, U_CONSTANT_TO_PARAM("randomNumber"), result); cout.write(buffer, u__snprintf(buffer, sizeof(buffer), "randomNumber = %V\n", result.rep)); result.clear(); + int city; + double pricePoint; + + (void) UValue::jfind(U_STRING_FROM_CONSTANT("{ \"pricePoint\" : 2.48333333333333, \"socialWeight\" : 8.75832720587083, \"gender\" : 0, \"lessThan16\" : false }"), + U_CONSTANT_TO_PARAM("pricePoint"), pricePoint); + + U_INTERNAL_ASSERT_EQUALS(pricePoint, 2.48333333333333) + + (void) UValue::jfind(U_STRING_FROM_CONSTANT("{ \"cityKey\" : 0 }"), U_CONSTANT_TO_PARAM("cityKey"), city); + + U_INTERNAL_ASSERT_EQUALS(city, 0) + testMap(); testVector(); testObject();