Mercurial > hg > nnchat
view util.c @ 687:e6d60eacf24d
Update to new th_io_fopen() API.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 09 Jul 2018 08:08:50 +0300 |
parents | ceb73b712121 |
children | f3ec1cb11cea |
line wrap: on
line source
/* * NNChat - Custom chat client for NewbieNudes.com chatrooms * Written by Matti 'ccr' Hämäläinen * (C) Copyright 2008-2016 Tecnic Software productions (TNSP) */ #include "util.h" #include <time.h> BOOL str_get_timestamp(char *str, size_t len, const char *fmt) { time_t stamp = time(NULL); struct tm *stamp_tm; if ((stamp_tm = localtime(&stamp)) != NULL) { strftime(str, len, fmt, stamp_tm); return TRUE; } else { str[0] = 0; return FALSE; } } char * str_trim_left(char *buf) { while (*buf != 0 && th_isspace(*buf)) buf++; return buf; } char * str_trim_right(char *buf) { size_t pos; for (pos = strlen(buf) - 1; pos > 0 && th_isspace(buf[pos]); pos--) buf[pos] = 0; return buf; } int str_compare(const void *s1, const void *s2) { return th_strcasecmp((const char *) s1, (const char *) s2); } #define PUSHCHAR(x) th_strbuf_putch(&result, &resSize, &resPos, x) #define PUSHSTR(x) th_strbuf_puts(&result, &resSize, &resPos, x) char *nn_encode_str1(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str) + NN_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { switch (*s) { case 32: PUSHCHAR('+'); break; default: if (th_isalnum(*s)) PUSHCHAR(*s); else { char tmpStr[4]; snprintf(tmpStr, sizeof(tmpStr), "%2X", (unsigned char) *s); PUSHCHAR('%'); PUSHSTR(tmpStr); } break; } s++; } PUSHCHAR(0); return result; } static int nn_get_hexdigit(const int c, const int shift) { int i; if (c >= 'A' && c <= 'F') i = c - 'A' + 10; else if (c >= 'a' && c <= 'f') i = c - 'a' + 10; else if (c >= '0' && c <= '9') i = c - '0'; else return -1; return i << shift; } char *nn_decode_str1(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; int c; if (str == NULL) return NULL; resSize = strlen(str) + NN_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { switch (*s) { case '+': PUSHCHAR(' '); s++; break; case '½': // Escape these .. PUSHCHAR('½'); PUSHCHAR('½'); s++; break; case '\r': PUSHCHAR(' '); s++; break; case '%': s++; if (*s == '%') PUSHCHAR('%'); else if ((c = nn_get_hexdigit(*s, 4)) >= 0) { int i = nn_get_hexdigit(*(++s), 0); if (i >= 0) { PUSHCHAR((char) (c | i)); } else { PUSHCHAR('§'); PUSHCHAR(*s); } } else { PUSHCHAR('§'); PUSHCHAR(*s); } s++; break; default: PUSHCHAR(*s); s++; } } PUSHCHAR(0); return result; } char *nn_strip_tags(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str) + NN_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { if (*s == '<') { while (*s && *s != '>') s++; if (*s == '>') s++; } else PUSHCHAR(*s++); } PUSHCHAR(0); return result; } typedef struct { char c; char *ent; } html_entity_t; static const html_entity_t HTMLEntities[] = { { '<', "<" }, { '>', ">" }, }; static const int numHTMLEntities = sizeof(HTMLEntities) / sizeof(HTMLEntities[0]); char *nn_encode_str2(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str) + NN_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { int i; BOOL found = FALSE; for (i = 0; i < numHTMLEntities; i++) if (HTMLEntities[i].c == *s) { PUSHSTR(HTMLEntities[i].ent); found = TRUE; break; } if (!found) PUSHCHAR(*s); s++; } PUSHCHAR(0); return result; } char *nn_decode_str2(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str); if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { if (*s == '&') { int i; BOOL found = FALSE; for (i = 0; i < numHTMLEntities; i++) { const html_entity_t *ent = &HTMLEntities[i]; size_t len = strlen(ent->ent); if (!strncmp(s, ent->ent, len)) { PUSHCHAR(ent->c); s += len; found = TRUE; break; } } if (!found) PUSHCHAR(*s++); } else PUSHCHAR(*s++); } PUSHCHAR(0); return result; } char *nn_dbldecode_str(const char *str) { char *res, *tmp; if ((tmp = nn_decode_str1(str)) == NULL) return NULL; res = nn_decode_str2(tmp); th_free(tmp); return res; } char *nn_dblencode_str(const char *str) { char *res, *tmp; if ((tmp = nn_encode_str2(str)) == NULL) return NULL; res = nn_encode_str1(tmp); th_free(tmp); return res; } int nn_editbuf_write(nn_editbuf_t *buf, size_t pos, char ch) { if (buf->len+1 >= buf->size) return -3; if (pos >= buf->len) buf->data[buf->len++] = ch; else buf->data[pos] = ch; buf->dirty = TRUE; return 0; } int nn_editbuf_insert(nn_editbuf_t *buf, size_t pos, char ch) { if (buf->len+1 >= buf->size) return -3; if (pos >= buf->len) { buf->data[buf->len] = ch; } else { memmove(&(buf->data[pos+1]), &(buf->data[pos]), buf->len - pos + 1); buf->data[pos] = ch; } buf->len++; buf->dirty = TRUE; return 0; } int nn_editbuf_delete(nn_editbuf_t *buf, size_t pos) { if (pos < buf->len) { memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos); buf->len--; buf->dirty = TRUE; return 0; } else return -2; } void nn_editbuf_clear(nn_editbuf_t *buf) { buf->len = 0; buf->pos = 0; buf->dirty = TRUE; } nn_editbuf_t * nn_editbuf_new(size_t n) { nn_editbuf_t *res = th_malloc0(sizeof(nn_editbuf_t)); res->data = (char *) th_malloc(n); res->size = n; res->dirty = TRUE; return res; } void nn_editbuf_free(nn_editbuf_t *buf) { if (buf != NULL) { th_free(buf->data); th_free(buf); } } void nn_editbuf_copy_to(nn_editbuf_t *dst, const nn_editbuf_t *src) { memcpy(dst->data, src->data, src->size); dst->pos = dst->len = src->len; dst->dirty = TRUE; } nn_editbuf_t * nn_editbuf_copy(const nn_editbuf_t *src) { nn_editbuf_t *res; if (src == NULL) return NULL; if ((res = nn_editbuf_new(src->size)) == NULL) return NULL; nn_editbuf_copy_to(res, src); return res; } char * nn_editbuf_get_string(nn_editbuf_t *buf, size_t start, size_t end) { char *str; size_t siz; if (buf == NULL || end > buf->len || start >= buf->len) return NULL; if (start <= end) siz = end - start + 1; else return NULL; if ((str = th_malloc(siz + 1)) == NULL) return NULL; memcpy(str, buf->data + start, siz); str[siz] = 0; return str; } void nn_editbuf_setpos(nn_editbuf_t *buf, size_t pos) { assert(buf != NULL); if (pos >= buf->len) buf->pos = buf->len; else buf->pos = pos; buf->dirty = TRUE; } static uint8_t nn_hash_user(const char *name) { /* int n = 0; const uint8_t *c = (uint8_t *)name; uint8_t hash = 0xff; while (*c && n < 4) { hash = (hash << 1) ^ tolower(*c); c++; n++; } return (hash & 0xff); */ return (uint8_t) tolower(name[0]); } static void nn_user_insert(nn_user_t **list, nn_user_t *node) { node->next = *list; *list = node; } static void nn_user_free(nn_user_t *user) { th_free(user->name); th_free(user); } nn_user_t *nn_userhash_foreach(const nn_userhash_t *list, int (*func)(const nn_user_t *, void *userdata), void *data) { int i; if (list == NULL) return NULL; for (i = 0; i < NN_NUM_BUCKETS; i++) if (list->buckets[i] != NULL) { nn_user_t *curr = list->buckets[i]; while (curr != NULL) { if (func(curr, data) != 0) return curr; curr = curr->next; } } return NULL; } nn_user_t *nn_userhash_find(const nn_userhash_t *list, const char *name) { uint8_t hash; if (list == NULL) return NULL; hash = nn_hash_user(name); if (list->buckets[hash] != NULL) { nn_user_t *curr = list->buckets[hash]; while (curr != NULL) { if (th_strcasecmp(curr->name, name) == 0) return curr; curr = curr->next; } } return NULL; } static nn_user_t *nn_userhash_match_do(nn_user_t *list, const char *pattern, size_t len) { nn_user_t *node; for (node = list; node != NULL; node = node->next) { if (len <= strlen(node->name) && th_strncasecmp(node->name, pattern, len) == 0) return node; } return NULL; } nn_user_t *nn_userhash_match(const nn_userhash_t *list, const char *pattern, const char *current, BOOL again) { uint8_t hash; if (list == NULL || pattern == NULL) return NULL; hash = nn_hash_user(pattern); if (list->buckets[hash] != NULL) { nn_user_t *node; size_t len = strlen(pattern); if (current != NULL) { for (node = list->buckets[hash]; node != NULL; node = node->next) { if (th_strcasecmp(node->name, current) == 0) { nn_user_t *found; if (again) return node; if ((found = nn_userhash_match_do(node->next, pattern, len)) != NULL) return found; } } } if ((node = nn_userhash_match_do(list->buckets[hash], pattern, len)) != NULL) return node; } return NULL; } nn_userhash_t *nn_userhash_new(void) { return th_malloc0(sizeof(nn_userhash_t)); } int nn_userhash_insert(nn_userhash_t *list, const char *name) { uint8_t hash; nn_user_t *user; // Check arguments if (list == NULL || name == NULL) return -1; // Check if username is already there if (nn_userhash_find(list, name) != NULL) return 1; // No, we'll add it if ((user = th_malloc0(sizeof(nn_user_t))) == NULL) return -3; user->name = th_strdup(name); if (user->name == NULL) return -4; hash = nn_hash_user(name); nn_user_insert(&(list->buckets[hash]), user); return 0; } int nn_userhash_delete(nn_userhash_t *list, const char *name) { uint8_t hash; // Check arguments if (list == NULL || name == NULL) return -1; // Check if username is already there hash = nn_hash_user(name); if (list->buckets[hash] != NULL) { nn_user_t *curr, *prev; curr = list->buckets[hash]; prev = NULL; while (curr != NULL) { if (th_strcasecmp(curr->name, name) == 0) { if (prev) prev->next = curr->next; else list->buckets[hash] = curr->next; nn_user_free(curr); return 0; } else { prev = curr; curr = curr->next; } } } return 1; } void nn_userhash_free(nn_userhash_t *hash) { int i; if (hash == NULL) return; for (i = 0; i < NN_NUM_BUCKETS; i++) { nn_user_t *curr = hash->buckets[i]; while (curr != NULL) { nn_user_t *next = curr->next; nn_user_free(curr); curr = next; } hash->buckets[i] = NULL; } th_free(hash); } char *nn_username_encode(char *str) { unsigned char *c = (unsigned char *) str; if (str == NULL) return NULL; for (; *c ; c++) if (*c == ' ') *c = 255; return str; } char *nn_username_decode(char *str) { unsigned char *c = (unsigned char *) str; if (str == NULL) return NULL; for (; *c ; c++) if (*c == 255) *c = ' '; return str; } nn_strtuple_t *nn_strtuple_new(size_t len, char *str) { nn_strtuple_t *tuple = th_malloc0(sizeof(nn_strtuple_t)); tuple->len = len; tuple->str = str; return tuple; } void nn_strtuple_free(nn_strtuple_t *tuple) { th_free(tuple->str); th_free(tuple); }