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[] =
+{
+    { '<', "&lt;" },
+    { '>', "&gt;" },
+};
+
+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);
+}