/* $Id: str.c,v 1.3 2006/11/18 09:20:55 maxim Exp $ * */ #include #include #include #include #include #include #include #include #include #include #include "configure.h" #include "misc.h" #include "settings.h" #if SUPPORT_RUS #include "charsets.h" #endif #include "str.h" int hexDigit(char c) { if ('0' <= c && c <= 'f') { if (c <= '9') return c - '0'; if ('A' <= c) { if (c <= 'F') return c - 'A' + 10; if ('a' <= c) return c - 'a' + 10; } } return -1; } char* unescape(char* str, char plusIsSpace, char isUTF) { char *c, *d; if (!str) return NULL; for (c = str, d = str; *c; c++, d++) { if (*c == '%') { int h, l; if (c[1] == 'u') { int n = 0; int u = 0; for (n = 0, c++; n < 4; n++) { int h = hexDigit(*++c); if (h < 0) { c--; break; } u = (u << 4) + h; } #if SUPPORT_RUS *d = unicode2char(u, WIN); #else *d = u < 0x80 ? u : '?'; #endif } else if ((h = hexDigit(c[1])) >= 0 && (l = hexDigit(c[2])) >= 0) { *d = (h << 4) + l; c += 2; } else { *d = *c; } } else if (plusIsSpace && *c == '+') { *d = ' '; } else if (d != c) { *d = *c; } } *d = 0; #if SUPPORT_RUS if (isUTF) { int n = recode(str, d - str, UTF, WIN); if (n >= 0) str[n] = 0; } #else if (isUTF) message(MESSAGE, "warning: decoding from utf8 is not supported"); #endif return str; } char* unhash(char* str) { char *c, *d; if (!str) return NULL; for (c = str, d = str; *c; c++, d++) { if (c[0] == '&' && c[1] == '#') { char* end; int u = strtol(c + 2, &end, 10); if (*end == ';') { #if SUPPORT_RUS *d = unicode2char(u, WIN); #else *d = u < 0x80 ? u : '?'; #endif c = end; } else { *d = *c; } } else if (d != c) { *d = *c; } } *d = 0; return str; } char* hexDigits = "0123456789ABCDEF"; char* escape(char* string, char plusIsSpace) { static char buffer[HUGE_STR]; char* p; if (!string || !*string) return string; for(p = buffer; *string && p - buffer < HUGE_STR - 3; string++) { if (plusIsSpace && *string == ' ') { *p++ = '+'; } else if (isSafe(*string)) { *p++ = *string; } else { *p++ = '%'; *p++ = hexDigits[(unsigned char)(*string) >> 4]; *p++ = hexDigits[(unsigned char)(*string) & 0xF]; } } *p++ = 0; return buffer; } char* escapeLink(char* string) { static char buffer[LONG_STR]; char* p; if (!string || !*string) return ""; for(p = buffer; *string && p - buffer < LONG_STR - 3; string++) { if (*string != '"' && *string != '<' && *string != '>') { *p++ = *string; } else { *p++ = '%'; *p++ = hexDigits[(unsigned char)(*string) >> 4]; *p++ = hexDigits[(unsigned char)(*string) & 0xF]; } } *p++ = 0; return buffer; } char* quote(char* string) { static char* newstring = NULL; char* s = string - 1; char* c; int cnt = 0; while ((s = strpbrk(s + 1, "<>&\""))) cnt++; if (cnt == 0) return string; c = string; s = newstring = REALLOC(newstring, strlen(string) + cnt * 5 + 1); while (*c) { char* entity; int l; if (*c == '&') {entity = "&"; l = strlen("&");} else if (*c == '<') {entity = "<"; l = strlen("<");} else if (*c == '>') {entity = ">"; l = strlen(">");} else if (*c == '"') {entity = """; l = strlen(""");} else {*s++ = *c++; continue;} memcpy(s, entity, l); s += l; c++; } *s = 0; return newstring; } char* quotes(char* string) { static char* newstring = NULL; char* s = string - 1; char* c; int cnt = 0; while ((s = strpbrk(s + 1, "\""))) cnt++; if (cnt == 0) return string; c = string; s = newstring = REALLOC(newstring, strlen(string) + cnt *2 + 1); while (*c) { char* entity; int l; if (*c == '"') {entity = "\\\""; l = strlen("\\\"");} else {*s++ = *c++; continue;} memcpy(s, entity, l); s += l; c++; } *s = 0; return newstring; } void sql_unescape(char* string, ...) { va_list ap; va_start(ap, string); do { char* s = string; char* start = s; char* bs; while ((bs = strchr(start, '\\'))) { if (s != start) memmove(s, start, bs - start); s += bs - start; *s++ = *++bs; start = bs + 1; } if (s != start) strcpy(s, start); } while ((string = va_arg(ap, char*))); va_end(ap); } void remove_cr(char* string, ...) { va_list ap; va_start(ap, string); do { char* s = string; char* start = s; char* cr; while ((cr = strchr(start, '\r'))) { if (s != start && (cr - start)) memmove(s, start, cr - start); s += cr - start; start = cr + 1; } if (s != start) strcpy(s, start); } while ((string = va_arg(ap, char*))); va_end(ap); } void tr(char* from, char* to, ...) { unsigned char* string, *f, *t; va_list ap; int action; unsigned char table[256]; if (!from || !strlen(from) || !to) return; action = strlen(to) == 0 ? 0 : // delete strlen(to) == 1 ? 1 : // replace by same char 2; // map memset(table, 0, sizeof(table)); for (f = (unsigned char*)from, t = (unsigned char*)to; *f; f++) { switch (action) { case 0: table[*f] = 1; break; case 1: table[*f] = *t; break; case 2: table[*f] = *t++; if (!*t) --t; break; } } va_start(ap, to); while ((string = va_arg(ap, char*))) { unsigned char* s = string; while (*s) { if (table[*s]) { unsigned char* e = s; switch(action) { case 0: // delete while (table[*++e]); memmove(s, e, strlen((char*)e) + 1); break; case 1: // replace by same char while (table[*++e]); memset(s, *to, e - s); break; case 2: // map do { *e = table[*e]; e++; } while (table[*e]); break; } s = e; } else { s++; } } } va_end(ap); } int catstr(char* string, int max_size, ...) { char *str, *s = string; int length = 0; va_list ap; if (!string || max_size <= 0) return 0; va_start(ap, max_size); while ((str = va_arg(ap, char*))) { int l = strlen(str); if (!l) continue; length += l; if (length >= max_size) { *s = 0; debug("catstr overflow (%d >= %d): %s + %s", length, max_size, string, str); *string = 0; return 0; } memcpy(s, str, l); s += l; } va_end(ap); *s = 0; return length; } char* cat_strings(char* string, ...) { char *dest, *str; int length = 0; va_list ap; for (str = string, va_start(ap, string); str; str = va_arg(ap, char*)) length += strlen(str); va_end(ap); dest = calloc(1, length + 1); for (str = string, va_start(ap, string); str; str = va_arg(ap, char*)) strcat(dest, str); va_end(ap); return dest; } char* add_strings(char** string, ...) { char *str; int length = *string ? strlen(*string) : 0; int end = length; va_list ap; va_start(ap, string); while ((str = va_arg(ap, char*))) length += strlen(str); va_end(ap); *string = realloc(*string, length + 1); va_start(ap, string); while ((str = va_arg(ap, char*))) { int l = strlen(str); memcpy(*string + end, str, l); end += l; } va_end(ap); *(*string + end) = 0; return *string; } char* add_string(char** string, char* add) { int length = *string ? strlen(*string) : 0; int l; if (!add) return *string; l = strlen(add); *string = realloc(*string, length + l + 1); memcpy(*string + length, add, l); *(*string + length + l) = 0; return *string; } char* chomp(char* str) { if (str) { int e = strlen(str) - 1; if (e >= 0 && str[e] == '\n') str[e--] = 0; if (e >= 0 && str[e] == '\r') str[e] = 0; } return str; } char* trimSpaces(char* string) { char* s = string + strlen(string) - 1; while (s >= string && isSpace(*s)) *s-- = 0; s = string; while (isSpace(*s)) s++; return s; } char toLower_[256]; void initToLower() { unsigned char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄŨÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß"; unsigned char lower[] = "abcdefghijklmnopqrstuvwxyzàáâãä叿çèéêëìíîïðñòóôõö÷øùúûüýþÿ"; int i; for (i = 0; i < 256; i++) toLower_[i] = i; for (i = 0; upper[i]; i++) toLower_[upper[i]] = lower[i]; } char toLower(int c) { if (!toLower_[1]) initToLower(); return toLower_[c]; } char* strtolower(char* string) { unsigned char* s; if (!toLower_[1]) initToLower(); for (s = (unsigned char*)string; *s; s++) *s = toLower_[*s]; return string; } char isAlNum(char c) { if ('0' <= c) { if (c <= '9') return 1; if ('A' <= c) { if (c <= 'Z') return 1; if ('a' <= c && c <= 'z') return 1; } } return 0; } char isSafe(char c) { if (',' <= c) { if (c <= ':') return YES; if ('A' <= c) { if (c <= 'Z') return YES; if ('^' <= c && c <= 'z') return YES; } } return NO; } char isDigit(char c) { if ('0' <= c && c <= '9') return YES; return NO; } char isSpace(char c) { return (c == ' ' || c == '\n' || c == '\r' || c == '\t'); } char isChar(unsigned char c) { if ('0' <= c) { if (c <= '9') return YES; if (c >= 0xC0 || c == 0xA3 || c == 0xB3 || c == 0xA8 || c == 0xB8) return YES; if ('A' <= c) { if (c <= 'Z') return YES; if ('a' <= c && c <= 'z') return YES; } } return NO; } unsigned hash(char *s) { unsigned int h = 0; /* h = h * 65599 + *s; */ while(*s) h = (h << 16) + (h << 6) - h + (unsigned char) *s++; return h; } #define N_OF_STRINGS 20 char* itoa(int n) { static int call = 0; static char* strings; unsigned u = abs(n); char* str, *c; if (!strings && (!(strings = CALLOC(N_OF_STRINGS*32)))) return ""; call %= N_OF_STRINGS; c = str = strings + 32 * call++; do { *c++ = u%10 + '0'; } while ((u /= 10)); if (n < 0) *c++ = '-'; *c-- = 0; { // reverse string char* s = str; while (s < c) { char t = *s; *s++ = *c; *c-- = t; } } return str; } char* itos(int n) { static int call = 0; static char* strings; unsigned u = abs(n); int p = 0; char* str, *c; if (!strings && (!(strings = CALLOC(N_OF_STRINGS*32)))) return ""; call %= N_OF_STRINGS; c = str = strings + 32 * call++; do { if (++p == 4) {*c++ = ','; p = 1;} *c++ = u%10 + '0'; } while ((u /= 10)); if (n < 0) *c++ = '-'; *c-- = 0; { // reverse string char* s = str; while (s < c) { char t = *s; *s++ = *c; *c-- = t; } } return str; } unsigned string2ip(char* str) { if (str) { unsigned ip; unsigned char* n = (unsigned char*)&ip; int count = 4; while (*str && !isDigit(*str)) str++; while (1) { char* e; n[--count] = strtol(str, &e, 10); if (e == str) return -1; if (count && *e == '.') str = e + 1; else break; } return count ? 0xFFFFFFFF : ip; } else { return 0; } } char* ip2string(unsigned ip) { char *s; unsigned char* n = (unsigned char*)&ip; static int call = 0; static char* strings = NULL; if (!strings && (!(strings = CALLOC(2*16)))) return ""; call &= 1; s = strings + 16 * call++; snprintf(s, 16, "%d.%d.%d.%d", n[3], n[2], n[1], n[0]); return s; } int reverse(char* s) { int l = strlen(s); char* e = s + l - 1; while (s < e) { char t = *s; *s++ = *e; *e-- = t; } return l; } char* copystring(char* string) { char* dest = NULL; if (string) { int length = strlen(string) + 1; dest = (char*) CALLOC(length); if (dest) memcpy(dest, string, length); } return dest; } int split(char* string, char* del, int max_len, ...) { static char* buffer = NULL; char* token, *arg; va_list ap; if (max_len < 1) return FAILED; if (!buffer && !(buffer = CALLOC(LONG_STR))) return FAILED; va_start(ap, max_len); strncpy_(buffer, string, LONG_STR); token = strtok(buffer, del); arg = va_arg(ap, char*); while (token && arg) { strncpy_(arg, token, max_len - 1); token = strtok(NULL, del); arg = va_arg(ap, char*); } while(arg) { *arg = 0; arg = va_arg(ap, char*); } va_end(ap); return OK; } char* fmt(char* format, ...) { va_list ap; static char* string = NULL; if (!string && !(string = CALLOC(LONG_STR))) return NULL; *string = 0; va_start(ap, format); vsnprintf(string, LONG_STR, format, ap); va_end(ap); return string; } char* chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_"; unsigned char* charmap = NULL; char initcharmap() { unsigned char i = 0; unsigned char* c = chars; if ((charmap = CALLOC(256))) while(*c) charmap[*c++] = i++; else return FAILED; return OK; } char* long2str(unsigned u) { static char str[7]; int i = 6; str[i--] = 0; do { str[i] = chars[u & 63]; u >>= 6; } while (i--); return str; } char* longs2str(unsigned u1, unsigned u2) { static char str[13]; int i = 12; str[i--] = 0; do { str[i] = chars[u2 & 63]; u2 >>= 6; } while (i-- > 6); do { str[i] = chars[u1 & 63]; u1 >>= 6; } while (i--); return str; } long str2long(char* str) { unsigned u; unsigned char* c; int i; if (!str || (!charmap && !initcharmap())) return 0; for (u = i = 0, c = str; i < 6 && *c; i++) u = (u << 6) + charmap[*c++]; return u; } char checkEmail(char* email) { char* s = email; while(isAlNum(*s) || *s == '.' || *s == '-' || *s == '_') s++; if (s == email || *s++ != '@') return FAILED; while(isAlNum(*s) || *s == '-') s++; if (*s++ != '.' ) return FAILED; while(isAlNum(*s) || *s == '.' || *s == '-') s++; if (*s) return FAILED; return OK; } char checkPassword(char* password) { char* s = password; while(isAlNum(*s)) s++; return *s ? FAILED : OK; } char checkNick(char* nick) { char* s = nick; while(isAlNum(*s) || *s == '_' || *s == '-' || *s == '/') s++; return *s ? FAILED : OK; } char checkSlice(char* slice) { char* s = slice; while(isAlNum(*s) || *s == '_' || *s == '-' || *s == '.' || *s == '/') s++; return *s ? FAILED : OK; } int stripLast(char* url, int length) { char* s = url + length - 1; do { if (*s == '/') { *s = 0; return s - url; } } while (--s >= url); return 0; } #if 0 struct enc_names_str { char* name; int length; } encodings[] = { /* win -----------------------------*/ {"windows-1251", sizeof("windows-1251") - 1}, // {"windows", sizeof("windows") - 1}, {"cp-1251", sizeof("cp-1251") - 1}, {"cp1251", sizeof("cp1251") - 1}, {"win", sizeof("win") - 1}, /* koi -----------------------------*/ {"koi8-r", sizeof("koi8-r") - 1}, //{"koi8", sizeof("koi8") - 1}, {"koi", sizeof("koi") - 1}, /* cp866 -----------------------------*/ {"ibm866", sizeof("ibm866") - 1}, {"cp-866", sizeof("cp-866") - 1}, {"cp866", sizeof("cp866") - 1}, {"dos", sizeof("dos") - 1}, // {"alt", sizeof("alt") - 1}, /* iso -----------------------------*/ {"iso-8859-5", sizeof("iso-8859-5") - 1}, {"iso8859-5", sizeof("iso8859-5") - 1}, {"iso", sizeof("iso") - 1}, /* mac -----------------------------*/ {"x-mac", sizeof("x-mac") - 1}, {"mac", sizeof("mac") - 1}, /* translit -----------------------------*/ {"translit", sizeof("translit") - 1}, {"koi7", sizeof("koi7") - 1}, // {"lat", sizeof("lat") - 1}, /* -----------------------------*/ {NULL, 0} }; char unifyURL(char* url, char** host, char** query, char canBeShort) { static char origin[MEDIUM_STR]; char* s, *c; char* server; char* path; char f; int i; if(!(url && *url)) return FAILED; for (c = url; *c; c++) { if (*c == '\\') { *c = '/'; } else if (*c == '?') { *c = 0; if (query) *query = c + 1; break; } else if (*c == '#') { *c = 0; break; } } if (c - url > 7 && ((*((int*)url))&0xDFDFDFDF) == 0x70747468) { // "http" if (url[strlen("http")] == ':' && (*((short*)(url + strlen("http:")))) == 0x2F2F) server = url + strlen("http://"); else if (((*((int*)(url + strlen("http"))))&0xDFDFDFDF) == 0x2F2F3A73) // "s://" server = url + strlen("https://"); else if (canBeShort) server = url; else return FAILED; } else if (canBeShort) { server = url; } else { return FAILED; } if ((path = strchr(server, '/'))) { *path = 0; if (!path[1]) path = NULL; } #if 0 if ((c = strrchr(server, '@'))) server = c + 1; unescape(server, NO, NO); if (strchr(server, '.')) strtolower(server); #else unescape(server, NO, NO); if ((c = strchr(server, '@'))) *c = 0; if (strchr(server, '.')) strtolower(server); if (c) *c = '@'; #endif if ((c = strchr(server, ':'))) *c = 0; while(*server && *server == '.') server++; c = server + strlen(server) - 1; while(c >= server && *c == '.') *c-- = 0; if (host) { int l; if (!strchr(server, '.')) return FAILED; l = strlen(server) + 1; if (l > MEDIUM_STR) origin[l = MEDIUM_STR - 1] = 0; *host = memcpy(origin, server, l); } if (strcmp(server, "win-petergof.narod.ru")) { for (i = 0; encodings[i].name; i++) { int l = encodings[i].length; if ((c = strstr(server, encodings[i].name)) && (c == server || c[-1] < '0') && c[l] && c[l] < '0' && strchr(c + ++l, '.')) { if (c > server && c[-1] == '-') c--; strcpy(c, c + l); break; } } } if (!strncmp(server, "www", strlen("www"))) { c = server + strlen("www"); if (isdigit(*c)) while(isdigit(*++c)); if (*c == '.' && strchr(c + 1, '.')) strcpy(url, c + 1); else strcpy(url, server); } else { strcpy(url, server); } if (!*url) return FAILED; c = url; while((c = strchr(c, ' '))) strcpy(c, c + 1); c = url + strlen(url); if (!path) { memcpy(c, "/", 2); return OK; } if (c == path) { *path = '/'; } else { *path = '/'; strcpy(c, path); path = c; } #if 0 if (*url == 'w' && !strncmp(url + 1, "ebwarper.net/", strlen("ebwarper.net/"))) { char* real = NULL; if (strncmp(path, "/ww/", strlen("/ww/")) == 0) real = path + strlen("/ww/"); else if (strncmp(path, "/ww.pl/", strlen("/ww.pl/")) == 0) real = path + strlen("/ww.pl/"); if (real) { char* slash; if (*real == '~' && (slash = strchr(real, '/'))) real = slash + 1; strcpy(url, real); return unifyURL(url, host, query, YES); } } #endif c = unescape(path, NO, NO); while((c = strstr(c, "//"))) strcpy(c, c + 1); c = path++; while((c = strstr(c, "/./"))) strcpy(c, c + 2); f = *path; for (i = 0; encodings[i].name; i++) { if (f == encodings[i].name[0] && strncmp(path, encodings[i].name, encodings[i].length) == 0 && path[encodings[i].length] == '/') { strcpy(path, path + encodings[i].length + 1); f = *path; break; } } #if 0 if (f == 'c' && !strncmp(path, "cgi-bin/mail/", strlen("cgi-bin/mail/"))) { path[strlen("cgi-bin/mail/")] = 0; } // else { #endif s = strrchr(--path, '/'); if (*(++s)) { static char lc[SHORT_STR]; strtolower(strncpy_(lc, s, SHORT_STR)); if (strncmp(lc, "index.", strlen("index.")) == 0 || strncmp(lc, "default.", strlen("default.")) == 0 || strcmp(lc, ".") == 0) *s = 0; } return OK; } #endif char* humanSize(long long size) { static int call = 0; static char string[4][SHORT_STR]; char *s = string[++call % 4]; char *c = "bkMG"; double hsize = size; while (hsize >= 1000 && c[1]) { hsize /= 1024; c++; } if (*c == 'b') snprintf(s, SHORT_STR, "%4lld", size); else if (hsize < 10) snprintf(s, SHORT_STR, "%4.2f%c", hsize, *c); else if (hsize < 100) snprintf(s, SHORT_STR, "%4.1f%c", hsize, *c); else snprintf(s, SHORT_STR, "%4.0f%c", hsize, *c); return s; } char* humanPeriod(int period) { static int call = 0; static char string[4][SHORT_STR]; char *s = string[++call % 4]; char c; if (period < 120) c = 's'; else if ((period = (period + 30)/60) < 120) c = 'm'; else if ((period = (period + 30)/60) < 36) c = 'h'; else {period = (period + 12)/24; c = 'd';} snprintf(s, SHORT_STR, "%d%c", period, c); return s; } char* strncpy_(char* dest, char* src, int maxLength) { int l = strlen(src) + 1; if (l > maxLength) dest[l = maxLength - 1] = 0; return memcpy(dest, src, l); } int snprintf__(char* file, int pos, char* string, int length, char* fmt, ...) { va_list ap; int n; if (length <= 0) { message(ERROR, "no buffer for snprintf on %s:%d \"%s\"", file, pos, fmt); return 0; } va_start(ap, fmt); n = vsnprintf(string, length, fmt, ap); va_end(ap); if (n < 0) { message(ERROR, "snprintf negative on %s:%d \"%s\"", file, pos, fmt); return 0; } else if (n >= length) { message(ERROR, "snprintf overflow on %s:%d \"%s\": %d >= %d", file, pos, fmt, n, length); return length - 1; } else { return n; } }