#include #include #include #include #include #include #include #include #include #include "MiscSupport.h" void parseUrlRequest(PropertyList &addToHere, std::string fromHere) { fromHere += '&'; while (true) { int messageBreak = fromHere.find('&'); if (messageBreak == -1) { break; } std::string currentPair = fromHere.substr(0, messageBreak); fromHere.erase(0, messageBreak + 1); messageBreak = currentPair.find('='); if (messageBreak > -1) { addToHere[urlDecode(currentPair.substr(0, messageBreak))] = urlDecode(currentPair.substr(messageBreak + 1)); } } } std::string getHostName() { char hostName[100]; const bool error = gethostname(hostName, 100); if (error) return "unknown"; // If the host name is too long, according to the man page, it will be // truncated. Whether or not the truncated name is NULL terminated is // explicitly not defined. hostName[99] = 0; return hostName; } std::string getShortHostName() { return explode(".", getHostName())[0]; } std::string breakOnce(std::string &source, char breakAt) { std::string result; std::string::size_type split = source.find(breakAt); if (split == source.npos) { result = source; source.erase(); } else { result = source.substr(0, split); source.erase(0, split+1); } return result; } long int strtolDefault(const std::string &input, long int defaultValue) { if (input.find((char)0) == input.npos) { // This is a seperate function because some clients start with // c style strings. return strtolDefault(input.c_str(), defaultValue); } else { // An embedded null return defaultValue; } } long int strtolDefault(const char *input, long int defaultValue) { if (!*input) { // Empty string. Without this test, the next test could // give the wrong result. return defaultValue; } char *endptr; errno = 0; long int value = strtol(input, &endptr, 10); if (*endptr) { // We hit a bad character before the end of the string. return defaultValue; } if (errno) return defaultValue; // This only works on proper null-terminated strings. // If a string as an embedded null, that's not a legal number, // be we couldn't deal with that case if we wanted to. return value; } long unsigned int strtoulDefault(const std::string &input, long unsigned int defaultValue) { if (input.find((char)0) == input.npos) { // This is a seperate function because some clients start with // c style strings. return strtoulDefault(input.c_str(), defaultValue); } else { // An embedded null return defaultValue; } } long unsigned int strtoulDefault(const char *input, long unsigned int defaultValue) { if (!*input) { // Empty string. Without this test, the next test could // give the wrong result. return defaultValue; } char *endptr; long int value = strtoul(input, &endptr, 10); if (*endptr) { // We hit a bad character before the end of the string. return defaultValue; } // This only works on proper null-terminated strings. // If a string as an embedded null, that's not a legal number, // be we couldn't deal with that case if we wanted to. return value; } double strtodDefault(const std::string &input, double defaultValue) { if (input.find((char)0) == input.npos) { // This is a seperate function because some clients start with // c style strings. return strtodDefault(input.c_str(), defaultValue); } else { // An embedded null return defaultValue; } } double strtodDefault(const char *input, double defaultValue) { if (!*input) { // Empty string. Without this test, the next test could // give the wrong result. return defaultValue; } char *endptr; double value = strtod(input, &endptr); if (*endptr) { // We hit a bad character before the end of the string. return defaultValue; } // This only works on proper null-terminated strings. // If a string as an embedded null, that's not a legal number, // be we couldn't deal with that case if we wanted to. return value; } long long int strtollDefault(const std::string &input, long long int defaultValue) { if (input.find((char)0) == input.npos) { // This is a seperate function because some clients start with // c style strings. return strtollDefault(input.c_str(), defaultValue); } else { // An embedded null return defaultValue; } } long long int strtollDefault(const char *input, long long int defaultValue) { if (!*input) { // Empty string. Without this test, the next test could // give the wrong result. return defaultValue; } char *endptr; long long int value = strtoll(input, &endptr, 10); if (*endptr) { // We hit a bad character before the end of the string. return defaultValue; } // This only works on proper null-terminated strings. // If a string as an embedded null, that's not a legal number, // be we couldn't deal with that case if we wanted to. return value; } long long unsigned int strtoullDefault(const std::string &input, long long unsigned int defaultValue) { if (input.find((char)0) == input.npos) { // This is a seperate function because some clients start with // c style strings. return strtoullDefault(input.c_str(), defaultValue); } else { // An embedded null return defaultValue; } } long long unsigned int strtoullDefault(const char *input, long long unsigned int defaultValue) { if (!*input) { // Empty string. Without this test, the next test could // give the wrong result. return defaultValue; } char *endptr; long int value = strtoull(input, &endptr, 10); if (*endptr) { // We hit a bad character before the end of the string. return defaultValue; } // This only works on proper null-terminated strings. // If a string as an embedded null, that's not a legal number, // be we couldn't deal with that case if we wanted to. return value; } void nfroma(long int &n, std::string const &s) { // This isn't the most effecient algorithm. But it works. static const long int RARE = std::numeric_limits< long int >::min(); n = strtolDefault(s, RARE); if (n != RARE) return; n = strtolDefault(s, 0); if (n == 0) throw InvalidConversionException(); } void nfroma(double &n, std::string const &s) { static const long double RARE = std::numeric_limits< double >::min(); n = strtodDefault(s, RARE); if (n != RARE) return; n = strtodDefault(s, 0); if (n == 0) throw InvalidConversionException(); } std::string itoa(int i) { char buffer[30]; sprintf(buffer, "%d", i); return buffer; } std::string ltoa(long i) { char buffer[30]; sprintf(buffer, "%ld", i); return buffer; } std::string ultoa(unsigned long i) { char buffer[30]; sprintf(buffer, "%lu", i); return buffer; } std::string lltoa(long long i) { char buffer[45]; sprintf(buffer, "%lld", i); return buffer; } std::string ulltoa(unsigned long long i) { char buffer[45]; sprintf(buffer, "%llu", i); return buffer; } std::string dtoa(double d) { char buffer[30]; sprintf(buffer, "%.15g", d); return buffer; } std::string dtoa(double d, int digits) { char buffer[30]; if (digits > 15) { digits = 15; } else if (digits < 1) { digits = 1; } sprintf(buffer, "%.*g", digits, d); return buffer; } std::string dtoaFixed(double d, int digits) { char buffer[100]; int count = snprintf(buffer, 100, "%.*f", digits, d); if (count >= 100) { // Note: The limit includes the trailing \0. The return value does not // include the \0. So if the return value is equal to the limit, then // one byte was truncated. return dtoa(d); } else { return buffer; } } std::string addCommas(int64_t n) { std::string without = ntoa(n); std::string result; result.reserve(without.size() * 4 / 3); std::string::size_type toDo = without.size(); std::string::const_iterator it = without.begin(); while (toDo) { if ((toDo % 3 == 0) && (toDo != without.size())) result += ','; toDo--; result += *it; it++; } return result; } std::string priceToString(double d) { char buffer[16]; int count = snprintf(buffer, 15, "%.04f", d); if ((count < 2) || (count >= 15)) { return dtoa(d, 13); } if (buffer[count - 1] == '0') { buffer[count - 1] = '\0'; if (buffer[count - 2] == '0') { buffer[count - 2] = '\0'; } } return buffer; } std::string percentToString(double d) { char buffer[16]; int count = snprintf(buffer, 15, "%.02f", d); if ((count < 3) || (count >= 15)) { return dtoa(d, 13); } if (buffer[count - 1] == '0') { buffer[count - 1] = '\0'; if (buffer[count - 2] == '0') { buffer[count - 2] = '\0'; if (buffer[count - 3] == '.') { buffer[count - 3] = '\0'; } } } return buffer; } std::string pointerToString(void const *p) { char buffer[70]; // The output will look like 0x12ab. The 0x is automatic with %p. sprintf(buffer, "%p", p); return buffer; } std::string ctimeString(time_t t) { if (t == 0) { // Otherwise this function wiould return something like // {Wed Dec 31 16:00:00 1969} static const std::string NEVER = "never"; return NEVER; } char buffer[30]; ctime_r(&t, buffer); if (buffer[24]=='\n') { buffer[24]=0; } //return itoa(strlen(buffer)) + ',' + itoa(buffer[strlen(buffer)-1]); return buffer; } std::string cMicroTimeString(int64_t t) { const int64_t RATIO = 1000000; int64_t seconds = t / RATIO; int64_t microseconds = t % RATIO; if (microseconds < 0) { // Integer divide always rounds toward 0. I'm adjusting it so it rounds // toward -infinity. ctime doesn't treat 0 or negative numbers as special. // That's just another valid time. There is no reason to switch between // "10:00:00 + 123µs" to "10:00:01 - 877µs" on a particular date. seconds -= 1; microseconds += RATIO; } std::string result = ctimeString(seconds); result += " +"; result += ntoa(microseconds); result += "µs"; return result; } std::string errorString() { char buffer[256]; buffer[0] = 0; return strerror_r(errno, buffer, 255); } std::string realpathString(std::string const &path) { char buffer[PATH_MAX+1]; char *const result = realpath(path.c_str(), buffer); if (!result) return ""; assert(result == buffer); return buffer; } std::string unmangledName(std::type_info const &type) { size_t length; int status; char *unmangled = abi::__cxa_demangle(type.name(), NULL, &length, &status); if (!unmangled) { switch (status) { case -1: return "-1: A memory allocation failiure occurred."; case -2: return "-2: mangled_name is not a valid name under the C++ ABI mangling rules."; case -3: return "-3: One of the arguments is invalid."; default: return "Unknown error: " + ntoa(status); } } // It seems like length is the amount of space allocated for the string, not // the space used by the string. The string seems to be null terminated. // I'm not 100% sure why the length is returned to us at all. std::string result(unmangled, strnlen(unmangled, length)); free(unmangled); return result; } static int fromHex(char c) { if ((c >= '0') && (c <= '9')) { return (int)(c - '0'); } else if ((c >= 'A') && (c <= 'Z')) { return (int)(c - 'A') + 10; } else if ((c >= 'a') && (c <= 'z')) { return (int)(c - 'a') + 10; } else { return -1; } } std::string urlDecode(std::string input) { int to = 0; int stopCopying = input.length(); int lastPossibleConvert = stopCopying - 3; for (int from = 0; from < stopCopying; from++, to++) { int ldigit, rdigit; if (input[from] == '+') { input[to] = ' '; } else if ((from <= lastPossibleConvert) && (input[from] == '%') && ((ldigit=fromHex(input[from + 1])) > -1) && ((rdigit=fromHex(input[from + 2])) > -1)) { input[to] = (char)((ldigit << 4) + rdigit); from += 2; } else { input[to] = input[from]; } } input.erase(to); return input; } class UrlEncodeHelper { public: std::string encoded[256]; UrlEncodeHelper(bool raw) { for (unsigned int ch = 0; ch < 256; ch++) { if (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || ((ch >= '0') && (ch <= '9')) || (ch == '-') || (ch == '_') || (ch == '.')) { encoded[ch] = std::string(1, ch); } else { char e[10]; sprintf(e, "%%%02x", ch); encoded[ch] = e; } } if (!raw) { encoded[(unsigned char)' '] = "+"; encoded[(unsigned char)'.'] = "."; } } }; std::string urlEncode(std::string input, bool raw) { static const UrlEncodeHelper oldHelper(false); static const UrlEncodeHelper rawHelper(true); UrlEncodeHelper const &helper = (raw?rawHelper:oldHelper); std::string result; result.reserve(input.size() * 3); for (unsigned source = 0; source < input.size(); source++) { result += helper.encoded[(unsigned char)input[source]]; } result.reserve(result.size()); return result; } std::string urlEncode(PropertyList const &input) { std::string result; for (auto const &kvp : input) { if (!result.empty()) result += '&'; result += urlEncode(kvp.first); result += '='; result += urlEncode(kvp.second); } return result; } std::string makeUrlSafe(std::string original) { for (int i = original.length() - 1; i > 0; i--) { char c = original[i]; if ((c < 32) || (c >= 127)) { // Illegal characters. These might confuse the simple communication // protocol we use to talk to the sql translator. This info should // already be url encoded. return ""; } if (c == '*') { // This just helps with the testing and debugging. - -> = and // ^ -> &. This is the way that we can enter a config string // by hand without urlencoding it a second time. original[i] = '='; } else if (c == '^') { original[i] = '&'; } } return original; } void addToUrlEncoded(std::string &result, std::string const &toAdd) { if (toAdd.empty()) // Nothing to add. return; if (result.empty()) // The first data result = toAdd; else { // Add to the result result += '&'; result += toAdd; } } ///////////////////////////////////////////////////////////////////// // TCL quoting ///////////////////////////////////////////////////////////////////// // For the unquoting rules, see http://tmml.sourceforge.net/doc/tcl/Tcl.html std::string tclQuote(const std::string s) { const int inputLength = s.length(); if (inputLength == 0) { return "{}"; } bool requireSlashQuote = false; bool requireBraceQuote = false; unsigned int braceCount = 0; for (int i = 0; (i < inputLength) && !requireSlashQuote; i++) { unsigned char ch = s[i]; if ((ch < 32) || (ch == 127)) { // Quote all unprintable characters. requireSlashQuote = true; } else { switch (ch) { case ' ': case '"': { requireBraceQuote = true; break; } case '\\': { requireBraceQuote = true; if (i + 1 == inputLength) { requireSlashQuote = true; } else { i++; } break; } case '{': { requireBraceQuote = true; braceCount++; break; } case '}': { requireBraceQuote = true; if (braceCount) { braceCount--; } else { requireSlashQuote = true; } break; } } } } if (braceCount) { // The braces did not match. requireSlashQuote = true; } if (requireSlashQuote) { // This is the most comprehensive quoting solution. It can quote // anything. But the input can grow to 4 times the original size. // If applied recursively, the size could double each time. std::string result; result.reserve(s.length() * 4); for (int i = 0; i < inputLength; i++) { unsigned char ch = s[i]; switch (ch) { // Some of this effort is not required. \a does not need // to be quoted at all. \t could be quoted just like a brace // or an unprintable character. We go out of our way here to // make things more readable to a human. Also, sometimes it is // convenient to the programmer to get rid or \n and \r, // so the main input loop can use something simple like a gets(). case '\a': result += "\\a"; break; case '\b': result += "\\b"; break; case '\f': result += "\\f"; break; case '\n': result += "\\n"; break; case '\r': result += "\\r"; break; case '\t': result += "\\t"; break; case '\v': result += "\\v"; break; case ' ': case '"': case '\\': case '{': case '}': result +='\\'; result += ch; break; default: if ((ch < 32) || (ch == 127)) { // By the time we get here we know that we could include the // character as is and TCL would not complain. But this // is convenient to the human reader. char buffer[] = "\\000"; // We always print these in octal and we always use 3 digits. // This is the most precise format used by TCL. 12\0034 will // be four characters long. '1', '2', (char)3, '4'. // 12x034 on the other hand is interpreted as '1', '2', // (int)34. The 0 is ignored. Any number of characters // would be ignored in this position. sprintf(buffer+1, "%03hho", ch); result += buffer; } else { result += ch; } break; } } result.reserve(result.length()); return result; } else if (requireBraceQuote) { return '{' + s + '}'; } else { return s; } } #ifdef UNIT_TEST_TCL // Used for unit testing. static std::string testTcl() { std::string inputs[28]; inputs[0] = "All chars"; for (int j = 0; j < 256; j++) { inputs[1] += (char)j; } // should use slash quoting. See the code for each special case. inputs[2] = "Empty string"; // {} inputs[4] = "Simple value"; inputs[5] = "simple_value"; // simple_value inputs[6] = "Simple list"; inputs[7] = "a b c"; // {a b c} // just add { and } inputs[8] = "Recursive list"; inputs[9] = "{a b} {{c d} {e f}} {} {g h}"; // {{a b} {{c d} {e f}} {} {g h}} // just add { and } inputs[10] = "Fancy recursive list"; inputs[11] = "{a b} \\\\ \\} \\{ {c d}"; // {{a b} \\ \} \{ {c d}} // just add { and } inputs[12] = "Ends with slash"; inputs[13] = "a bc\\"; // a\ bc\\ (avoid compiler warning!) // slash quoting of final slash and space inputs[14] = "Too many opens"; inputs[15] = "{{{}}"; // \{\{\{\}\} inputs[16] = "Too many closes"; inputs[17] = "{{}}}"; // \{\{\}\}\} inputs[18] = "Wrong order"; inputs[19] = "{}}{{}"; // \{\}\}\{\{\} inputs[20] = "Quote and curly"; inputs[21] = "a\"b{c"; // a\"b\{c // Add the slashes // This test case is aimed at a specific bug that was fixed recently. inputs[22] = "Simple value with UTF-8"; inputs[23] = "“Hello_world”"; // “Hello_world” inputs[24] = "Simple list with UTF-8"; inputs[25] = "¡Hola! ¿Què pasa?"; // {¡Hola! ¿Què pasa?} inputs[26] = "UTF-8 and backslash"; inputs[27] = "Don’t stop here {"; // Don’t\ stop\ here\ \{ return tclList(inputs, &inputs[28]); } #include int main(int argc, char *argv[]) { std::cout<= 0; i--) { char &c = s[i]; if ((c >= 'a') and (c <= 'z')) { c += 'A' - 'a'; } } return s; } std::vector< std::string > explode(std::string seperator, std::string s) { std::vector< std::string > result; if (seperator.empty()) { return result; } while (true) { std::string::size_type p = s.find(seperator); if (p == s.npos) { result.push_back(s); return result; } result.push_back(s.substr(0, p)); s = s.substr(p + seperator.size()); } } ///////////////////////////////////////////////////////////////////// // getMicroTime() ///////////////////////////////////////////////////////////////////// int64_t getMicroTime() { timeval inPieces; int error = gettimeofday(&inPieces, NULL); assert(!error); int64_t result = inPieces.tv_sec; result *= 1000000; result += inPieces.tv_usec; return result; }