summaryrefslogtreecommitdiff
path: root/src/core/wee-infolist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/wee-infolist.c')
-rw-r--r--src/core/wee-infolist.c708
1 files changed, 708 insertions, 0 deletions
diff --git a/src/core/wee-infolist.c b/src/core/wee-infolist.c
new file mode 100644
index 000000000..64d4cb8a7
--- /dev/null
+++ b/src/core/wee-infolist.c
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2003-2008 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* wee-infolist.c: manages info lists */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "wee-log.h"
+#include "wee-string.h"
+#include "wee-infolist.h"
+
+
+struct t_infolist *weechat_infolists = NULL;
+struct t_infolist *last_weechat_infolist = NULL;
+
+
+/*
+ * infolist_new: create a new weechat infolist
+ */
+
+struct t_infolist *
+infolist_new ()
+{
+ struct t_infolist *new_infolist;
+
+ new_infolist = malloc (sizeof (*new_infolist));
+ if (new_infolist)
+ {
+ new_infolist->items = NULL;
+ new_infolist->last_item = NULL;
+ new_infolist->ptr_item = NULL;
+
+ new_infolist->prev_infolist = last_weechat_infolist;
+ new_infolist->next_infolist = NULL;
+ if (weechat_infolists)
+ last_weechat_infolist->next_infolist = new_infolist;
+ else
+ weechat_infolists = new_infolist;
+ last_weechat_infolist = new_infolist;
+ }
+
+ return new_infolist;
+}
+
+/*
+ * infolist_new_item: create a new item in an infolist
+ */
+
+struct t_infolist_item *
+infolist_new_item (struct t_infolist *infolist)
+{
+ struct t_infolist_item *new_item;
+
+ new_item = malloc (sizeof (*new_item));
+ if (new_item)
+ {
+ new_item->vars = NULL;
+ new_item->last_var = NULL;
+ new_item->fields = NULL;
+
+ new_item->prev_item = infolist->last_item;
+ new_item->next_item = NULL;
+ if (infolist->items)
+ infolist->last_item->next_item = new_item;
+ else
+ infolist->items = new_item;
+ infolist->last_item = new_item;
+ }
+
+ return new_item;
+}
+
+/*
+ * infolist_new_var_integer: create a new integer variable in an item
+ */
+
+struct t_infolist_var *
+infolist_new_var_integer (struct t_infolist_item *item,
+ const char *name, int value)
+{
+ struct t_infolist_var *new_var;
+
+ if (!item || !name || !name[0])
+ return NULL;
+
+ new_var = malloc (sizeof (*new_var));
+ if (new_var)
+ {
+ new_var->name = strdup (name);
+ new_var->type = INFOLIST_INTEGER;
+ new_var->value = malloc (sizeof (int));
+ if (new_var->value)
+ *((int *)new_var->value) = value;
+
+ new_var->prev_var = item->last_var;
+ new_var->next_var = NULL;
+ if (item->vars)
+ item->last_var->next_var = new_var;
+ else
+ item->vars = new_var;
+ item->last_var = new_var;
+ }
+
+ return new_var;
+}
+
+/*
+ * infolist_new_var_string: create a new string variable in an item
+ */
+
+struct t_infolist_var *
+infolist_new_var_string (struct t_infolist_item *item,
+ const char *name, const char *value)
+{
+ struct t_infolist_var *new_var;
+
+ if (!item || !name || !name[0])
+ return NULL;
+
+ new_var = malloc (sizeof (*new_var));
+ if (new_var)
+ {
+ new_var->name = strdup (name);
+ new_var->type = INFOLIST_STRING;
+ new_var->value = (value) ? strdup (value) : NULL;
+
+ new_var->prev_var = item->last_var;
+ new_var->next_var = NULL;
+ if (item->vars)
+ item->last_var->next_var = new_var;
+ else
+ item->vars = new_var;
+ item->last_var = new_var;
+ }
+
+ return new_var;
+}
+
+/*
+ * infolist_new_var_pointer: create a new pointer variable in an item
+ */
+
+struct t_infolist_var *
+infolist_new_var_pointer (struct t_infolist_item *item,
+ const char *name, void *pointer)
+{
+ struct t_infolist_var *new_var;
+
+ if (!item || !name || !name[0])
+ return NULL;
+
+ new_var = malloc (sizeof (*new_var));
+ if (new_var)
+ {
+ new_var->name = strdup (name);
+ new_var->type = INFOLIST_POINTER;
+ new_var->value = pointer;
+
+ new_var->prev_var = item->last_var;
+ new_var->next_var = NULL;
+ if (item->vars)
+ item->last_var->next_var = new_var;
+ else
+ item->vars = new_var;
+ item->last_var = new_var;
+ }
+
+ return new_var;
+}
+
+/*
+ * infolist_new_var_buffer: create a new buffer variable in an item
+ */
+
+struct t_infolist_var *
+infolist_new_var_buffer (struct t_infolist_item *item,
+ const char *name, void *pointer, int size)
+{
+ struct t_infolist_var *new_var;
+
+ if (!item || !name || !name[0] || (size <= 0))
+ return NULL;
+
+ new_var = malloc (sizeof (*new_var));
+ if (new_var)
+ {
+ new_var->name = strdup (name);
+ new_var->type = INFOLIST_BUFFER;
+ new_var->value = malloc (size);
+ if (new_var->value)
+ memcpy (new_var->value, pointer, size);
+ new_var->size = size;
+
+ new_var->prev_var = item->last_var;
+ new_var->next_var = NULL;
+ if (item->vars)
+ item->last_var->next_var = new_var;
+ else
+ item->vars = new_var;
+ item->last_var = new_var;
+ }
+
+ return new_var;
+}
+
+/*
+ * infolist_new_var_time: create a new time variable in an item
+ */
+
+struct t_infolist_var *
+infolist_new_var_time (struct t_infolist_item *item,
+ const char *name, time_t time)
+{
+ struct t_infolist_var *new_var;
+
+ if (!item || !name || !name[0])
+ return NULL;
+
+ new_var = malloc (sizeof (*new_var));
+ if (new_var)
+ {
+ new_var->name = strdup (name);
+ new_var->type = INFOLIST_TIME;
+ new_var->value = malloc (sizeof (time_t));
+ if (new_var->value)
+ *((time_t *)new_var->value) = time;
+
+ new_var->prev_var = item->last_var;
+ new_var->next_var = NULL;
+ if (item->vars)
+ item->last_var->next_var = new_var;
+ else
+ item->vars = new_var;
+ item->last_var = new_var;
+ }
+
+ return new_var;
+}
+
+/*
+ * infolist_valid: check if an infolist pointer exists
+ * return 1 if list exists
+ * 0 if list is not found
+ */
+
+int
+infolist_valid (struct t_infolist *infolist)
+{
+ struct t_infolist *ptr_infolist;
+
+ for (ptr_infolist = weechat_infolists; ptr_infolist;
+ ptr_infolist = ptr_infolist->next_infolist)
+ {
+ if (ptr_infolist == infolist)
+ return 1;
+ }
+
+ /* list not found */
+ return 0;
+}
+
+/*
+ * infolist_next: return next item for an infolist
+ * if current item pointer is NULL,
+ * then return first item of infolist
+ */
+
+struct t_infolist_item *
+infolist_next (struct t_infolist *infolist)
+{
+ if (!infolist->ptr_item)
+ {
+ infolist->ptr_item = infolist->items;
+ return infolist->ptr_item;
+ }
+ infolist->ptr_item = infolist->ptr_item->next_item;
+ return infolist->ptr_item;
+}
+
+/*
+ * infolist_prev: return previous item for an infolist
+ * if current item pointer is NULL,
+ * then return last item of infolist
+ */
+
+struct t_infolist_item *
+infolist_prev (struct t_infolist *infolist)
+{
+ if (!infolist->ptr_item)
+ {
+ infolist->ptr_item = infolist->last_item;
+ return infolist->ptr_item;
+ }
+ infolist->ptr_item = infolist->ptr_item->prev_item;
+ return infolist->ptr_item;
+}
+
+/*
+ * infolist_reset_item_cursor: reset pointer to current item in infolist
+ */
+
+void
+infolist_reset_item_cursor (struct t_infolist *infolist)
+{
+ infolist->ptr_item = NULL;
+}
+
+/*
+ * infolist_fields: get list of fields for current infolist item
+ */
+
+char *
+infolist_fields (struct t_infolist *infolist)
+{
+ struct t_infolist_var *ptr_var;
+ int length;
+
+ if (!infolist || !infolist->ptr_item)
+ return NULL;
+
+ /* list of fields already asked ? if yes, just return string */
+ if (infolist->ptr_item->fields)
+ return infolist->ptr_item->fields;
+
+ length = 0;
+ for (ptr_var = infolist->ptr_item->vars;
+ ptr_var; ptr_var = ptr_var->next_var)
+ {
+ length += strlen (ptr_var->name) + 3;
+ }
+
+ infolist->ptr_item->fields = malloc (length + 1);
+ if (!infolist->ptr_item->fields)
+ return NULL;
+
+ infolist->ptr_item->fields[0] = '\0';
+ for (ptr_var = infolist->ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ switch (ptr_var->type)
+ {
+ case INFOLIST_INTEGER:
+ strcat (infolist->ptr_item->fields, "i:");
+ break;
+ case INFOLIST_STRING:
+ strcat (infolist->ptr_item->fields, "s:");
+ break;
+ case INFOLIST_POINTER:
+ strcat (infolist->ptr_item->fields, "p:");
+ break;
+ case INFOLIST_BUFFER:
+ strcat (infolist->ptr_item->fields, "b:");
+ break;
+ case INFOLIST_TIME:
+ strcat (infolist->ptr_item->fields, "t:");
+ break;
+ }
+ strcat (infolist->ptr_item->fields, ptr_var->name);
+ if (ptr_var->next_var)
+ strcat (infolist->ptr_item->fields, ",");
+ }
+
+ return infolist->ptr_item->fields;
+}
+
+/*
+ * infolist_integer: get an integer variable value in current infolist item
+ */
+
+int
+infolist_integer (struct t_infolist *infolist, const char *var)
+{
+ struct t_infolist_var *ptr_var;
+
+ if (!infolist || !infolist->ptr_item || !var || !var[0])
+ return 0;
+
+ for (ptr_var = infolist->ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ if (string_strcasecmp (ptr_var->name, var) == 0)
+ {
+ if (ptr_var->type == INFOLIST_INTEGER)
+ return *((int *)ptr_var->value);
+ else
+ return 0;
+ }
+ }
+
+ /* variable not found */
+ return 0;
+}
+
+/*
+ * infolist_string: get a string variable value in current list item
+ */
+
+char *
+infolist_string (struct t_infolist *infolist, const char *var)
+{
+ struct t_infolist_var *ptr_var;
+
+ if (!infolist || !infolist->ptr_item || !var || !var[0])
+ return NULL;
+
+ for (ptr_var = infolist->ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ if (string_strcasecmp (ptr_var->name, var) == 0)
+ {
+ if (ptr_var->type == INFOLIST_STRING)
+ return (char *)ptr_var->value;
+ else
+ return NULL;
+ }
+ }
+
+ /* variable not found */
+ return NULL;
+}
+
+/*
+ * infolist_pointer: get a pointer variable value in current infolist item
+ */
+
+void *
+infolist_pointer (struct t_infolist *infolist, const char *var)
+{
+ struct t_infolist_var *ptr_var;
+
+ if (!infolist || !infolist->ptr_item || !var || !var[0])
+ return NULL;
+
+ for (ptr_var = infolist->ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ if (string_strcasecmp (ptr_var->name, var) == 0)
+ {
+ if (ptr_var->type == INFOLIST_POINTER)
+ return ptr_var->value;
+ else
+ return NULL;
+ }
+ }
+
+ /* variable not found */
+ return NULL;
+}
+
+/*
+ * infolist_buffer: get a buffer variable value in current infolist item
+ * size is used to return size of buffer
+ */
+
+void *
+infolist_buffer (struct t_infolist *infolist, const char *var,
+ int *size)
+{
+ struct t_infolist_var *ptr_var;
+
+ if (!infolist || !infolist->ptr_item || !var || !var[0])
+ return NULL;
+
+ for (ptr_var = infolist->ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ if (string_strcasecmp (ptr_var->name, var) == 0)
+ {
+ if (ptr_var->type == INFOLIST_BUFFER)
+ {
+ *size = ptr_var->size;
+ return ptr_var->value;
+ }
+ else
+ return NULL;
+ }
+ }
+
+ /* variable not found */
+ return NULL;
+}
+
+/*
+ * infolist_time: get a time variable value in current infolist item
+ */
+
+time_t
+infolist_time (struct t_infolist *infolist, const char *var)
+{
+ struct t_infolist_var *ptr_var;
+
+ if (!infolist || !infolist->ptr_item || !var || !var[0])
+ return 0;
+
+ for (ptr_var = infolist->ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ if (string_strcasecmp (ptr_var->name, var) == 0)
+ {
+ if (ptr_var->type == INFOLIST_TIME)
+ return *((time_t *)ptr_var->value);
+ else
+ return 0;
+ }
+ }
+
+ /* variable not found */
+ return 0;
+}
+
+/*
+ * infolist_var_free: free an infolist variable
+ */
+
+void
+infolist_var_free (struct t_infolist_item *item,
+ struct t_infolist_var *var)
+{
+ struct t_infolist_var *new_vars;
+
+ /* remove var */
+ if (item->last_var == var)
+ item->last_var = var->prev_var;
+ if (var->prev_var)
+ {
+ (var->prev_var)->next_var = var->next_var;
+ new_vars = item->vars;
+ }
+ else
+ new_vars = var->next_var;
+
+ if (var->next_var)
+ (var->next_var)->prev_var = var->prev_var;
+
+ /* free data */
+ if (var->name)
+ free (var->name);
+ if (((var->type == INFOLIST_INTEGER)
+ || (var->type == INFOLIST_STRING)
+ || (var->type == INFOLIST_BUFFER)
+ || (var->type == INFOLIST_TIME))
+ && var->value)
+ {
+ free (var->value);
+ }
+
+ free (var);
+
+ item->vars = new_vars;
+}
+
+/*
+ * infolist_item_free: free an infolist item
+ */
+
+void
+infolist_item_free (struct t_infolist *infolist,
+ struct t_infolist_item *item)
+{
+ struct t_infolist_item *new_items;
+
+ /* remove var */
+ if (infolist->last_item == item)
+ infolist->last_item = item->prev_item;
+ if (item->prev_item)
+ {
+ (item->prev_item)->next_item = item->next_item;
+ new_items = infolist->items;
+ }
+ else
+ new_items = item->next_item;
+
+ if (item->next_item)
+ (item->next_item)->prev_item = item->prev_item;
+
+ /* free data */
+ while (item->vars)
+ {
+ infolist_var_free (item, item->vars);
+ }
+ if (item->fields)
+ free (item->fields);
+
+ free (item);
+
+ infolist->items = new_items;
+}
+
+/*
+ * infolist_free: free an infolist
+ */
+
+void
+infolist_free (struct t_infolist *infolist)
+{
+ struct t_infolist *new_weechat_infolists;
+
+ /* remove list */
+ if (last_weechat_infolist == infolist)
+ last_weechat_infolist = infolist->prev_infolist;
+ if (infolist->prev_infolist)
+ {
+ (infolist->prev_infolist)->next_infolist = infolist->next_infolist;
+ new_weechat_infolists = weechat_infolists;
+ }
+ else
+ new_weechat_infolists = infolist->next_infolist;
+
+ if (infolist->next_infolist)
+ (infolist->next_infolist)->prev_infolist = infolist->prev_infolist;
+
+ /* free data */
+ while (infolist->items)
+ {
+ infolist_item_free (infolist, infolist->items);
+ }
+
+ free (infolist);
+
+ weechat_infolists = new_weechat_infolists;
+}
+
+/*
+ * infolist_print_log: print infolists infos in log (usually for crash dump)
+ */
+
+void
+infolist_print_log ()
+{
+ struct t_infolist *ptr_infolist;
+ struct t_infolist_item *ptr_item;
+ struct t_infolist_var *ptr_var;
+
+ for (ptr_infolist = weechat_infolists; ptr_infolist;
+ ptr_infolist = ptr_infolist->next_infolist)
+ {
+ log_printf ("");
+ log_printf ("[infolist (addr:0x%x)]", ptr_infolist);
+ log_printf (" items. . . . . . . . . : 0x%x", ptr_infolist->items);
+ log_printf (" last_item. . . . . . . : 0x%x", ptr_infolist->last_item);
+ log_printf (" ptr_item . . . . . . . : 0x%x", ptr_infolist->ptr_item);
+ log_printf (" prev_infolist. . . . . : 0x%x", ptr_infolist->prev_infolist);
+ log_printf (" next_infolist. . . . . : 0x%x", ptr_infolist->next_infolist);
+
+ for (ptr_item = ptr_infolist->items; ptr_item;
+ ptr_item = ptr_item->next_item)
+ {
+ log_printf ("");
+ log_printf (" [item (addr:0x%x)]", ptr_item);
+ log_printf (" vars . . . . . . . . . : 0x%x", ptr_item->vars);
+ log_printf (" last_var . . . . . . . : 0x%x", ptr_item->last_var);
+ log_printf (" prev_item. . . . . . . : 0x%x", ptr_item->prev_item);
+ log_printf (" next_item. . . . . . . : 0x%x", ptr_item->next_item);
+
+ for (ptr_var = ptr_item->vars; ptr_var;
+ ptr_var = ptr_var->next_var)
+ {
+ log_printf ("");
+ log_printf (" [var (addr:0x%x)]", ptr_var);
+ log_printf (" name . . . . . . . . : '%s'", ptr_var->name);
+ log_printf (" type . . . . . . . . : %d", ptr_var->type);
+ switch (ptr_var->type)
+ {
+ case INFOLIST_INTEGER:
+ log_printf (" value (integer). . . : %d", *((int *)ptr_var->value));
+ break;
+ case INFOLIST_STRING:
+ log_printf (" value (string) . . . : '%s'", (char *)ptr_var->value);
+ break;
+ case INFOLIST_POINTER:
+ log_printf (" value (pointer). . . : 0x%x", ptr_var->value);
+ break;
+ case INFOLIST_BUFFER:
+ log_printf (" value (buffer) . . . : 0x%x", ptr_var->value);
+ log_printf (" size of buffer . . . : %d", ptr_var->size);
+ break;
+ case INFOLIST_TIME:
+ log_printf (" value (time) . . . . : %ld", *((time_t *)ptr_var->value));
+ break;
+ }
+ log_printf (" prev_var . . . . . . : 0x%x", ptr_var->prev_var);
+ log_printf (" next_var . . . . . . : 0x%x", ptr_var->next_var);
+ }
+ }
+ }
+}