// This file is part of Timmi. // // Timmi is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. #include #include #include #include #include #include #include #include #include #include #include int ERRORLEVEL = WARNING; void debug(DebugLevel level, std::string message) { if (level >= ERRORLEVEL) { std::cerr << DEBUGCHARS[level] << " " << message << std::endl; } } void debug_with_errno(DebugLevel level, const std::string &message, int err) { std::ostringstream stream(""); stream << message << ": " << std::string(strerror(err)); debug(level, stream.str()); } void debug_with_errno(DebugLevel level, const std::string &message) { debug_with_errno(level, message, errno); } Random::Random() { device.open("/dev/urandom", std::ios::binary); } unsigned int Random::rand() { unsigned int rawnum; int c; for (int i = 0; i < sizeof(int); i++) { c = device.get(); if (c < 0) { debug(CRITICAL, "Read from random source failed"); return 0; } *((unsigned char *) &rawnum + i) = c; } return rawnum; } int Random::random_in_range(int min, int max) { // Range is inclusive, rangesize = count of possible values int rangesize = max - min + 1; unsigned int raw = rand(); // Force random range to be divisable by rangesize // Eg. to get random in range [1,3], rangesize = 3 // If INT_MAX = 7, values are forced to range [0, 5] // Thus, results are [1,2,3,1,2,3], yielding uniform distribution while (raw >= (INT_MAX - INT_MAX % rangesize)) { raw = rand(); } return min + raw % rangesize; } int strtoi(std::string str) { std::istringstream stream(str); int tulos = 0; stream >> tulos; return tulos; } std::string strtoupper(std::string str) { std::string result(""); int i; for (i = 0; i < str.size(); i++) { result += toupper(str.at(i)); } return result; } std::string datetostring(std::string format, time_t t) { char buf[128] = {0}; if (t < 0) { t = time(NULL); } strftime(buf, 128, format.c_str(), localtime(&t)); return std::string(buf); } // Returns character set for current locale std::string get_locale_charset() { return std::string(nl_langinfo(CODESET)); } // Simplified iconv interface, doesn't give accurate description of errors // but hides ugly pointer stuff. // Empty encoding name means current locale encoding. // If transliterate is given, unknown chars are replaced with ?. // TODO: Probably really slow, but doesn't matter in this application bool simple_iconv(std::string input_str, std::string input_encoding, std::string &output_str, std::string output_encoding, bool transliterate) { if (input_encoding == "") { input_encoding = get_locale_charset(); } if (output_encoding == "") { output_encoding = get_locale_charset(); } if (transliterate) { output_encoding += "//TRANSLIT"; } iconv_t cd = iconv_open(output_encoding.c_str(), input_encoding.c_str()); if (cd < 0) { debug_with_errno(WARNING, "Iconv_open failed"); return false; } size_t status = 0; size_t ibleft = input_str.length(); size_t obleft = ibleft * 2; // Assume that this is enough char *real_inbuf = new char[ibleft + 1]; // Trailing 0 char *real_outbuf = new char[obleft + 1]; char *inbuf = real_inbuf; // Iconv modifies the pointer value char *outbuf = real_outbuf; // Iconv hasn't marked the input buffer as const, so we assume // it is being changed. // (Instead of uglily casting input_str.c_str() to non-const.) strncpy(inbuf, input_str.c_str(), ibleft); status = iconv(cd, &inbuf, &ibleft, &outbuf, &obleft); *outbuf = 0; output_str = std::string(real_outbuf); delete[] real_outbuf; delete[] real_inbuf; if (iconv_close(cd) != 0) { debug_with_errno(WARNING, "Iconv_close failed"); } return (status != -1); } bool is_valid_utf8(std::string str) { std::string tmp(""); return simple_iconv(str, "UTF-8", tmp, "UTF-8"); }