#include "utils.h" #include // transform #include #include #include #include #include #include #include // http://c-faq.com/lib/randrange.html int randint(int N) { return rand() / (RAND_MAX / N + 1); } // http://c-faq.com/lib/randrange.html // numbers in the range [M, N] could be generated with something like int randrange(int M, int N) { return M + rand() / (RAND_MAX / (N - M + 1) + 1); } /** * random_activate() * * Is a weight (1-10), * tests if random number is < weight * 10. * * So random_activate(9) happens more frequently * then random_activate(8) or lower. * * This probably needs to be fixed. * We need a better randint(RANGE) code. */ int random_activate(int w) { int r = randint(100); if (r <= w) { return 1; }; return 0; } /** * Display a repr of the given string. * * This converts most \n\r\v\f\t codes, * defaults to \xHH (hex value). */ char *repr(const char *data) { static char buffer[40960]; char *cp; strcpy(buffer, data); cp = buffer; while (*cp != 0) { char c = *cp; if (c == ' ') { cp++; continue; }; /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'), * horizontal tab ('\t'), and vertical tab ('\v') */ if (strchr("\f\n\r\t\v\?", c) != NULL) { memmove(cp + 1, cp, strlen(cp) + 1); *cp = '\\'; cp++; switch (c) { case '\f': *cp = 'f'; cp++; break; case '\n': *cp = 'n'; cp++; break; case '\r': *cp = 'r'; cp++; break; case '\t': *cp = 't'; cp++; break; case '\v': *cp = 'v'; cp++; break; default: *cp = '?'; cp++; break; } continue; } if (c == '\\') { memmove(cp + 1, cp, strlen(cp) + 1); *cp = '\\'; cp += 2; continue; } if (c == '"') { memmove(cp + 1, cp, strlen(cp) + 1); *cp = '\\'; cp += 2; continue; } if (strchr("[()]{}:;,.<>?!@#$%^&*", c) != NULL) { cp++; continue; } if (strchr("0123456789", c) != NULL) { cp++; continue; } if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c) != NULL) { cp++; continue; } // Ok, default to \xHH output. memmove(cp + 3, cp, strlen(cp) + 1); char buffer[10]; // int slen = snprintf(buffer, sizeof(buffer), "\\x%02x", (int)c & 0xff); /* if (slen >= sizeof(buffer)) { ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer)); } */ strncpy(cp, buffer, 4); cp += 4; continue; } return buffer; } /* * strnstr() * * buffer safe version that looks for a string. */ const char *strnstr(const char *source, int len, const char *needle) { int pos; for (pos = 0; pos < len; pos++) { if (source[pos] == needle[0]) { if (strncmp(source + pos, needle, strlen(needle)) == 0) { return source + pos; } } } return NULL; } /* * rstrnstr() Reverse string find in a string * * This obeys the len, and handles nulls in buffer. * find is a c-string (null terminated) */ int rstrnstr(const char *buffer, int len, const char *find) { int flen = strlen(find); if (len < flen) { // I can't find a string in a buffer smaller then it is! return -1; } int pos = len - flen; while (pos > 0) { if (buffer[pos] == find[0]) { // First chars match, check them all. if (strncmp(buffer + pos, find, flen) == 0) { return pos; } } pos--; } return -1; } /* * string_insert() * Inserts a string into a given position. * This safely checks to make sure the buffer isn't overrun. * * buffer is a c null terminated string. */ int string_insert(char *buffer, size_t max_length, size_t pos, const char *insert) { /* assert(max_length > pos); assert(buffer != NULL); assert(insert != NULL); */ if (pos >= max_length) return 0; if (buffer == NULL) return 0; if (insert == NULL) return 0; if (strlen(insert) == 0) return 0; if (pos > strlen(buffer)) return 0; if (strlen(buffer) + strlen(insert) >= max_length) { /* ZF_LOGD("string_insert() failed inserting [%s]", repr(insert)); */ return 0; } memmove(buffer + pos + strlen(insert), buffer + pos, strlen(buffer + pos) + 1); // cp + strlen(display), cp, strlen(cp) + 1); strncpy(buffer + pos, insert, strlen(insert)); // (cp, display, strlen(display)); return 1; // success } void remove_all(std::string &str, char c) { str.erase(std::remove(str.begin(), str.end(), c), str.end()); } int unicode_len(char choad) { /* return length of unicode sequence, or 0 if not a unicode. */ // https://en.wikipedia.org/wiki/UTF-8 // 110xxxxx if ((choad & 0xe0) == 0xc0) { // CHOAD! return 2; } // 1110xxxx if ((choad & 0xf0) == 0xe0) { return 3; } // 11110xxx if ((choad & 0xf8) == 0xf0) { return 4; } return 0; } /* Pascal String Copy. Copy from pascal string, to C String. First char is pascal string length. (Max 255). */ void pcopy(char *pstring, char *str) { int len = (int)*pstring; strncpy(str, pstring + 1, len); str[len] = 0; } /* * tail file, return new lines of text. * * Only handles lines < 256 chars. * Does not handle if the file is closed/unlinked/... * */ std::string &find_new_text(std::ifstream &infile, std::streampos &last_position) { static std::string line; line.clear(); infile.seekg(0, std::ios::end); std::streampos filesize = infile.tellg(); if (filesize == -1) { // Ok, we've failed somehow. Now what? // cout << "SNAP!"; return line; } // check if the new file started // we don't detect if the file has been unlinked/reset if (filesize < last_position) { // cout << "reset! " << filesize << endl; last_position = 0; } while (last_position < filesize) { // this loop -- seems broken. // for (long n = last_position; n < filesize; n++) { infile.seekg(last_position, std::ios::beg); char test[256]; infile.getline(test, sizeof(test)); if (infile.eof()) { // We got EOF instead of something. // Seek back to our last, good, known position // and exit (wait for the rest of the line) infile.seekg(last_position, std::ios::beg); return line; } std::streampos new_pos = infile.tellg(); if (new_pos == -1) return line; last_position = new_pos; line.assign(test); return line; } return line; } void string_toupper(std::string &str) { std::transform(str.begin(), str.end(), str.begin(), ::toupper); } void string_trim(std::string &value) { while (*value.begin() == ' ') value.erase(value.begin()); while (*(value.end() - 1) == ' ') value.erase(value.end() - 1); } std::map read_configfile(std::string filename) { std::ifstream file(filename); std::string line; std::map config; if (!file.is_open()) return config; while (std::getline(file, line)) { if ((line[0] == '#') || (line[0] == ';')) continue; if (line.empty()) continue; // I'm not so sure this part is very good. std::istringstream is_line(line); std::string key; if (std::getline(is_line, key, '=')) { string_trim(key); string_toupper(key); std::string value; if (std::getline(is_line, value)) { string_trim(value); config[key] = value; /* std::cout << "Key: [" << key << "] Value: [" << value << "]" << std::endl; */ } } } return config; } bool replace(std::string &str, const std::string &from, const std::string &to) { size_t start_pos = str.find(from); if (start_pos == std::string::npos) return false; str.replace(start_pos, from.length(), to); return true; } IConv::IConv(const char *to, const char *from) : ic(iconv_open(to, from)) {} IConv::~IConv() { iconv_close(ic); } int IConv::convert(char *input, char *output, size_t outbufsize) { size_t inbufsize = strlen(input); // size_t orig_size = outbufsize; // memset(output, 0, outbufsize); // https://www.gnu.org/savannah-checkouts/gnu/libiconv/documentation/libiconv-1.15/iconv.3.html int r = iconv(ic, &input, &inbufsize, &output, &outbufsize); *output = 0; return r; } static IConv converter("UTF-8", "CP437"); static time_t last_time = 0; std::map CONFIG = read_configfile("hharry.cfg"); /* * harry_level: * * 0 - inactive * 1 - Week 1 (1-7) * 2 - Week 2 (8-14) * 3 - Week 3 (15-21) * 4 - Week 4 (22-31) */ int harry_level(void) { struct tm *tmp; time_t now = time(NULL); static int last = 0; auto search = CONFIG.find("LEVEL"); if (search != CONFIG.end()) { last = stoi(search->second); if (last > 4) { last = 4; } if (last < 0) { last = 0; } return last; } if (last_time < now + 10) { last_time = now; // Do our every 10 second checks here tmp = gmtime(&now); if (tmp->tm_mon != 9) return (last = 0); if (tmp->tm_mday < 8) return (last = 1); if (tmp->tm_mday < 15) return (last = 2); if (tmp->tm_mday < 22) return (last = 3); return (last = 4); } return last; } /* * This is similar to repr, but -- * * It converts high ASCII to UTF8, so it will display correctly * in the logfiles! */ const char *logrepr(const char *input) { static char buffer[10240]; char *cp; strcpy(buffer, input); cp = buffer; while (*cp != 0) { unsigned char c = *cp; if (c == ' ') { cp++; continue; }; /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'), * horizontal tab ('\t'), and vertical tab ('\v') */ if (strchr("\f\n\r\t\v", c) != NULL) { memmove(cp + 1, cp, strlen(cp) + 1); *cp = '\\'; cp++; switch (c) { case '\f': *cp = 'f'; cp++; break; case '\n': *cp = 'n'; cp++; break; case '\r': *cp = 'r'; cp++; break; case '\t': *cp = 't'; cp++; break; case '\v': *cp = 'v'; cp++; break; /* default: *cp = '?'; cp++; break; */ } continue; } if (c == '\\') { memmove(cp + 1, cp, strlen(cp) + 1); *cp = '\\'; cp += 2; continue; } if (c == '"') { memmove(cp + 1, cp, strlen(cp) + 1); *cp = '\\'; cp += 2; continue; } if (strchr("[()]{}:;,.<>?!@#$%^&*", c) != NULL) { cp++; continue; } if (strchr("0123456789", c) != NULL) { cp++; continue; } if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c) != NULL) { cp++; continue; } if ((int)c < 0x20) { // Ok, default to \xHH output. memmove(cp + 3, cp, strlen(cp) + 1); char buffer[10]; // int slen = snprintf(buffer, sizeof(buffer), "\\x%02x", (int)c & 0xff); strncpy(cp, buffer, 4); cp += 4; continue; }; cp++; continue; } static char fancybuffer[16384]; converter.convert(buffer, fancybuffer, sizeof(fancybuffer)); return fancybuffer; }