Mercurial > hg > nnchat
diff util.c @ 413:14b685cdbd2c
Rename files.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 24 May 2012 06:41:07 +0300 |
parents | libnnutil.c@3e64acb433e8 |
children | d015ecbd231d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util.c Thu May 24 06:41:07 2012 +0300 @@ -0,0 +1,739 @@ +/* + * NNChat - Custom chat client for NewbieNudes.com chatrooms + * Written by Matti 'ccr' Hämäläinen + * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) + */ +#include "util.h" + + +#define PUSHCHAR(x) th_vputch(&result, &resSize, &resPos, x) +#define PUSHSTR(x) th_vputs(&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(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]; + int 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, ssize_t pos, int ch) +{ + if (buf->len+1 >= buf->size) return -3; + + if (pos < 0) + return -1; + else if (pos >= buf->len) + buf->data[buf->len++] = ch; + else + buf->data[pos] = ch; + + return 0; +} + + +int nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch) +{ + if (buf->len+1 >= buf->size) return -3; + + if (pos < 0) + return -1; + else 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++; + return 0; +} + + +int nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos) +{ + if (pos < 0) + return -1; + else if (pos < buf->len) + { + memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos); + buf->len--; + return 0; + } + else + return -2; +} + + +void nn_editbuf_clear(nn_editbuf_t *buf) +{ + buf->len = 0; + buf->pos = 0; +} + + +nn_editbuf_t * nn_editbuf_new(ssize_t n) +{ + nn_editbuf_t *res = th_calloc(1, sizeof(nn_editbuf_t)); + + res->data = (char *) th_malloc(n); + res->size = n; + + return res; +} + + +void nn_editbuf_free(nn_editbuf_t *buf) +{ + if (buf != NULL) + { + th_free(buf->data); + th_free(buf); + } +} + + +nn_editbuf_t * nn_editbuf_copy(nn_editbuf_t *src) +{ + nn_editbuf_t *res; + + assert(src != NULL); + + if (src == NULL) return NULL; + + if ((res = nn_editbuf_new(src->size)) == NULL) + return NULL; + + memcpy(res->data, src->data, src->size); + res->pos = res->len = src->len; + + return res; +} + + +char * nn_editbuf_get_string(nn_editbuf_t *buf, ssize_t start, ssize_t end) +{ + char *str; + ssize_t siz; + + if (buf == NULL) + return NULL; + + if (start < 0 || end > buf->len || start >= buf->len) + return NULL; + + if (end < 0) + { + siz = buf->len - start + 1; + } + else 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, ssize_t pos) +{ + assert(buf != NULL); + + if (pos < 0) + buf->pos = 0; + else if (pos >= buf->len) + buf->pos = buf->len; + else + buf->pos = pos; +} + + +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 tolower(name[0]); +} + + +static void nn_user_insert(nn_user_t **list, nn_user_t *node) +{ + node->next = *list; + *list = node; +} + + +nn_user_t *nn_userhash_foreach(const nn_userhash_t *list, int (*func)(const nn_user_t *)) +{ + 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) != 0) + return curr; + curr = curr->next; + } + } + + return NULL; +} + + +nn_user_t *nn_user_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_user_match_do(nn_user_t *list, const char *pattern, size_t len) +{ + nn_user_t *curr = list; + + while (curr != NULL) + { + if (len <= strlen(curr->name) && th_strncasecmp(curr->name, pattern, len) == 0) + return curr; + curr = curr->next; + } + return NULL; +} + + +nn_user_t *nn_user_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 *curr = list->buckets[hash]; + size_t len = strlen(pattern); + + if (current != NULL) + { + nn_user_t *found = NULL; + while (curr != NULL) + { + if (th_strcasecmp(curr->name, current) == 0) + { + if (again) + return curr; + found = curr->next; + break; + } + curr = curr->next; + } + + if (found != NULL && (found = nn_user_match_do(found, pattern, len)) != NULL) + return found; + } + + if ((curr = nn_user_match_do(list->buckets[hash], pattern, len)) != NULL) + return curr; + } + + return NULL; +} + + +nn_userhash_t *nn_userhash_new(void) +{ + return th_calloc(1, 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_user_find(list, name) != NULL) + return 1; + + /* No, we'll add it */ + if ((user = th_calloc(1, 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; +} + + +nn_user_t *nn_user_copy(const nn_user_t *src) +{ + nn_user_t *user; + + if (src == NULL) return NULL; + + if ((user = th_calloc(1, sizeof(nn_user_t))) == NULL) + return NULL; + + /* Copy relevant data */ + user->name = th_strdup(src->name); + user->lastspoke = src->lastspoke; + user->joined = src->joined; + + return user; +} + + +void nn_user_free(nn_user_t *user) +{ + th_free(user->name); + th_free(user); +} + + +void nn_user_free_list(nn_user_t *list) +{ + nn_user_t *next, *curr = list; + + while (curr != NULL) + { + next = curr->next; + nn_user_free(curr); + curr = next; + } +} + +void nn_userhash_free(nn_userhash_t *hash) +{ + int i; + if (hash == NULL) + return; + + for (i = 0; i < NN_NUM_BUCKETS; i++) + { + nn_user_free_list(hash->buckets[i]); + 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_window_t *nn_window_new(const char *id) +{ + nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); + + if (res == NULL) return NULL; + + res->data = th_ringbuf_new(NN_BACKBUF_LEN, th_free); + if (res->data == NULL) + { + th_free(res); + return NULL; + } + + res->id = th_strdup(id); + + return res; +} + + +void nn_window_free(nn_window_t *win) +{ + if (win != NULL) + { + th_ringbuf_free(win->data); + th_free(win->id); + th_free(win); + } +} + + +nn_strtuple_t *nn_strtuple_new(size_t len, char *str) +{ + nn_strtuple_t *tuple = th_calloc(1, 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); +}