aboutsummaryrefslogtreecommitdiffstats
path: root/config.h.in (follow)
AgeCommit message (Expand)AuthorFilesLines
2009-11-15event plugin and dbus interface by Ed Martinmichael1-0/+9
2009-10-19driver for Logic Way GmbH ABP08 (serial) and ABP09 (USB) appliance control pa...michael1-0/+3
2009-09-23autoconf patches from PT M.michael1-0/+13
2009-05-11update autoconfmichux1-0/+6
2009-04-15update make filesmichux1-0/+6
2009-04-06update autoconf scriptsmichux1-0/+3
2009-03-25add vnc drivermichux1-0/+6
2009-02-28driver for GX series lcd from Matrix Orbital by Abbas Kosanmichael1-0/+3
2009-02-28GLCD2USB driver from Till Harbaummichael1-0/+3
2008-12-31ported r839 from volker_devmichael1-0/+3
2008-12-27port r817 from volker_devmichael1-0/+9
2008-12-24cleanup & cosmeticsmichael1-0/+3
2008-12-24w1retap plugin by Jonathan Hudsonmichael1-0/+3
2008-12-23hddtemp plugin from Scott Bronsonmichael1-0/+3
2008-11-23fix automake - check for libftdimichux1-0/+3
2008-09-03ULA200 driver by Bernhard Wallemichael1-0/+3
2008-08-03driver for 4D Systems serial displays by Sven Killigmichael1-0/+3
2008-07-15added IRLCD driver by Jean-Philippe Civademichael1-0/+3
2008-07-15picoLCDGraphic driver by Nicu Pavel addedmichael1-0/+3
2008-07-15automake-1.10.1michael1-1/+1
2008-04-12Makefiles again, this time libiconv stuff is fixedmichux1-0/+6
2008-04-12update Makefilesmichux1-0/+3
2008-04-04update autoconfmichux1-9/+6
2008-03-03add new driver (st2205) by Jeroen/Sprite_tmmichux1-0/+6
2007-10-01RDTSC delay and inclusion of asm/msr.h removedmichael1-3/+0
2007-10-01driver for Pertelian display by Andy Powellmichael1-3/+6
2007-06-08Image driver libgd dependancy fixmichael1-0/+3
2007-05-19gps plugin, code by michu / www.neophob.commichael1-0/+6
2007-02-04'Electronic Assembly' driver by Stefan Gmeinermichael1-0/+3
2007-01-20dynamic properties for bars; new 'property_valid()' helpermichael1-0/+3
2007-01-16new driver 'HD44780-I2C'michael1-0/+6
2007-01-14re-bootstrappedmichael1-0/+21
2006-09-15[lcd4linux @ 2006-09-15 19:00:50 by entropy]entropy1-0/+9
2006-09-04[lcd4linux @ 2006-09-04 16:48:32 by siretart]siretart1-2/+5
2006-08-17[lcd4linux @ 2006-08-17 19:11:40 by harbaum]harbaum1-5/+2
2006-08-13[lcd4linux @ 2006-08-13 18:14:03 by harbaum]harbaum1-0/+3
2006-08-13[lcd4linux @ 2006-08-13 09:53:10 by reinelt]reinelt1-2/+5
2006-08-09[lcd4linux @ 2006-08-09 17:25:34 by harbaum]harbaum1-5/+2
2006-08-08[lcd4linux @ 2006-08-08 19:35:21 by reinelt]reinelt1-0/+3
2006-08-08[lcd4linux @ 2006-08-08 19:28:18 by reinelt]reinelt1-2/+5
2006-08-05[lcd4linux @ 2006-08-05 21:08:01 by harbaum]harbaum1-5/+5
2006-06-25[lcd4linux @ 2006-06-25 15:13:00 by reinelt]reinelt1-3/+6
2006-06-20[lcd4linux @ 2006-06-20 08:50:58 by reinelt]reinelt1-2/+5
2006-06-19[lcd4linux @ 2006-06-19 15:12:54 by reinelt]reinelt1-2/+2
2006-04-15[lcd4linux @ 2006-04-15 05:22:52 by reinelt]reinelt1-0/+6
2006-02-19[lcd4linux @ 2006-02-19 15:42:18 by reinelt]reinelt1-0/+3
2006-01-26[lcd4linux @ 2006-01-26 19:26:26 by harbaum]harbaum1-0/+3
2006-01-21[lcd4linux @ 2006-01-21 13:26:43 by reinelt]reinelt1-0/+3
2006-01-18[lcd4linux @ 2006-01-18 11:49:48 by reinelt]reinelt1-0/+3
2006-01-03[lcd4linux @ 2006-01-03 13:20:05 by reinelt]reinelt1-0/+6
an.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* $Id$
 * $URL$
 *
 * hashes (associative arrays)
 *
 * Copyright (C) 2003 Michael Reinelt <michael@reinelt.co.at>
 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * This file is part of LCD4Linux.
 *
 * LCD4Linux 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 2, or (at your option)
 * any later version.
 *
 * LCD4Linux 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, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* 
 * exported functions:
 *
 * void hash_create (HASH *Hash);
 *   initializes hash
 *
 * int hash_age (HASH *Hash, char *key, char **value);
 *   return time of last hash_put
 *
 * void hash_put (HASH *Hash, char *key, char *val);
 *   set an entry in the hash
 *
 * void hash_put_delta (HASH *Hash, char *key, char *val);
 *   set a delta entry in the hash
 *
 * char *hash_get (HASH *Hash, char *key);
 *   fetch an entry from the hash
 *
 * double hash_get_delta (HASH *Hash, char *key, int delay);
 *   fetch a delta antry from the hash
 *
 * double hash_get_regex (HASH *Hash, char *key, int delay);
 *   fetch one or more entries from the hash
 *
 * void hash_destroy (HASH *Hash);
 *   releases hash
 *
 */


#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <regex.h>

#include "debug.h"
#include "hash.h"

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif

/* number of slots for delta processing */
#define DELTA_SLOTS 64

/* string buffer chunk size */
#define CHUNK_SIZE 16


/* initialize a new hash table */
void hash_create(HASH * Hash)
{
    Hash->sorted = 0;

    Hash->timestamp.tv_sec = 0;
    Hash->timestamp.tv_usec = 0;

    Hash->nItems = 0;
    Hash->Items = NULL;

    Hash->nColumns = 0;
    Hash->Columns = NULL;

    Hash->delimiter = strdup(" \t\n");
}


/* bsearch compare function for hash items */
static int hash_lookup_item(const void *a, const void *b)
{
    char *key = (char *) a;
    HASH_ITEM *item = (HASH_ITEM *) b;

    return strcasecmp(key, item->key);
}


/* qsort compare function for hash items */
static int hash_sort_item(const void *a, const void *b)
{
    HASH_ITEM *ha = (HASH_ITEM *) a;
    HASH_ITEM *hb = (HASH_ITEM *) b;

    return strcasecmp(ha->key, hb->key);
}


/* bsearch compare function for hash headers */
static int hash_lookup_column(const void *a, const void *b)
{
    char *key = (char *) a;
    HASH_COLUMN *column = (HASH_COLUMN *) b;

    return strcasecmp(key, column->key);
}


/* qsort compare function for hash headers */
static int hash_sort_column(const void *a, const void *b)
{
    HASH_COLUMN *ha = (HASH_COLUMN *) a;
    HASH_COLUMN *hb = (HASH_COLUMN *) b;

    return strcasecmp(ha->key, hb->key);
}


/* split a value into columns and  */
/* return the nth column in a string */
/* WARNING: does return a pointer to a static string!! */
static char *split(const char *val, const int column, const char *delimiter)
{
    static char buffer[256];
    int num;
    size_t len;
    const char *beg, *end;

    if (column < 0)
	return (char *) val;
    if (val == NULL)
	return NULL;

    num = 0;
    len = 0;
    beg = val;
    end = beg;
    while (beg && *beg) {
	while (strchr(delimiter, *beg))
	    beg++;
	end = strpbrk(beg, delimiter);
	if (num++ == column)
	    break;
	beg = end ? end + 1 : NULL;
    }
    if (beg != NULL) {
	len = end ? (size_t) (end - beg) : strlen(beg);
	if (len >= sizeof(buffer))
	    len = sizeof(buffer) - 1;
	strncpy(buffer, beg, len);
    }

    buffer[len] = '\0';
    return buffer;
}


/* search an entry in the hash table: */
/* If the table is flagged "sorted", the entry is looked */
/* up using the bsearch function. If the table is  */
/* unsorted, it will be searched in a linear way */
static HASH_ITEM *hash_lookup(HASH * Hash, const char *key, const int do_sort)
{
    HASH_ITEM *Item = NULL;

    /* maybe sort the array */
    if (do_sort && !Hash->sorted) {
	qsort(Hash->Items, Hash->nItems, sizeof(HASH_ITEM), hash_sort_item);
	Hash->sorted = 1;
    }

    /* no key was passed */
    if (key == NULL)
	return NULL;

    /* lookup using bsearch */
    if (Hash->sorted) {
	Item = bsearch(key, Hash->Items, Hash->nItems, sizeof(HASH_ITEM), hash_lookup_item);
    }

    /* linear search */
    if (Item == NULL) {
	int i;
	for (i = 0; i < Hash->nItems; i++) {
	    if (strcmp(key, Hash->Items[i].key) == 0) {
		Item = &(Hash->Items[i]);
		break;
	    }
	}
    }

    return Item;

}


/* return the age in milliseconds of an entry from the hash table */
/* or from the hash table itself if key is NULL */
/* returns -1 if entry does not exist */
int hash_age(HASH * Hash, const char *key)
{
    HASH_ITEM *Item;
    struct timeval now, *timestamp;

    if (key == NULL) {
	timestamp = &(Hash->timestamp);
    } else {
	Item = hash_lookup(Hash, key, 1);
	if (Item == NULL)
	    return -1;
	timestamp = &(Item->Slot[Item->index].timestamp);
    }

    gettimeofday(&now, NULL);

    return (now.tv_sec - timestamp->tv_sec) * 1000 + (now.tv_usec - timestamp->tv_usec) / 1000;
}


/* add an entry to the column header table */
void hash_set_column(HASH * Hash, const int number, const char *column)
{
    if (Hash == NULL)
	return;

    Hash->nColumns++;
    Hash->Columns = realloc(Hash->Columns, Hash->nColumns * sizeof(HASH_COLUMN));
    Hash->Columns[Hash->nColumns - 1].key = strdup(column);
    Hash->Columns[Hash->nColumns - 1].val = number;

    qsort(Hash->Columns, Hash->nColumns, sizeof(HASH_COLUMN), hash_sort_column);

}


/* fetch a column number by column header */
static int hash_get_column(HASH * Hash, const char *key)
{
    HASH_COLUMN *Column;

    if (key == NULL || *key == '\0')
	return -1;

    Column = bsearch(key, Hash->Columns, Hash->nColumns, sizeof(HASH_COLUMN), hash_lookup_column);
    if (Column == NULL)
	return -1;

    return Column->val;
}


/* set column delimiters */
void hash_set_delimiter(HASH * Hash, const char *delimiter)
{
    if (Hash->delimiter != NULL)
	free(Hash->delimiter);
    Hash->delimiter = strdup(delimiter);
}


/* get a string from the hash table */
char *hash_get(HASH * Hash, const char *key, const char *column)
{
    HASH_ITEM *Item;
    int c;

    Item = hash_lookup(Hash, key, 1);
    if (Item == NULL)
	return NULL;

    c = hash_get_column(Hash, column);
    return split(Item->Slot[Item->index].value, c, Hash->delimiter);
}


/* get a delta value from the delta table */
double hash_get_delta(HASH * Hash, const char *key, const char *column, const int delay)
{
    HASH_ITEM *Item;
    HASH_SLOT *Slot1, *Slot2;
    int i, c;
    double v1, v2;
    double dv, dt;
    struct timeval now, end;

    /* lookup item */
    Item = hash_lookup(Hash, key, 1);
    if (Item == NULL)
	return 0.0;

    /* this is the "current" Slot */
    Slot1 = &(Item->Slot[Item->index]);

    /* fetch column number */
    c = hash_get_column(Hash, column);

    /* if delay is zero, return absolute value */
    if (delay == 0)
	return atof(split(Slot1->value, c, Hash->delimiter));

    /* prepare timing values */
    now = Slot1->timestamp;
    end.tv_sec = now.tv_sec;
    end.tv_usec = now.tv_usec - 1000 * delay;
    while (end.tv_usec < 0) {
	end.tv_sec--;
	end.tv_usec += 1000000;
    }

    /* search delta slot */
    Slot2 = &(Item->Slot[Item->index]);
    for (i = 1; i < Item->nSlot; i++) {
	Slot2 = &(Item->Slot[(Item->index + i) % Item->nSlot]);
	if (Slot2->timestamp.tv_sec == 0)
	    break;
	if (timercmp(&(Slot2->timestamp), &end, <))
	    break;
    }

    /* empty slot => try the one before */
    if (Slot2->timestamp.tv_sec == 0) {
	i--;
	Slot2 = &(Item->Slot[(Item->index + i) % Item->nSlot]);
    }

    /* not enough slots available... */
    if (i == 0)
	return 0.0;

    /* delta value, delta time */
    v1 = atof(split(Slot1->value, c, Hash->delimiter));
    v2 = atof(split(Slot2->value, c, Hash->delimiter));
    dv = v1 - v2;
    dt = (Slot1->timestamp.tv_sec - Slot2->timestamp.tv_sec)
	+ (Slot1->timestamp.tv_usec - Slot2->timestamp.tv_usec) / 1000000.0;

    if (dt > 0.0 && dv >= 0.0)
	return dv / dt;
    return 0.0;
}


/* get a delta value from the delta table */
/* key may contain regular expressions, and the sum  */
/* of all matching entries is returned. */
double hash_get_regex(HASH * Hash, const char *key, const char *column, const int delay)
{
    double sum;
    regex_t preg;
    int i, err;

    err = regcomp(&preg, key, REG_ICASE | REG_NOSUB);
    if (err != 0) {
	char buffer[32];
	regerror(err, &preg, buffer, sizeof(buffer));
	error("error in regular expression: %s", buffer);
	regfree(&preg);
	return 0.0;
    }

    /* force the table to be sorted by requesting anything */
    hash_lookup(Hash, NULL, 1);

    sum = 0.0;
    for (i = 0; i < Hash->nItems; i++) {
	if (regexec(&preg, Hash->Items[i].key, 0, NULL, 0) == 0) {
	    sum += hash_get_delta(Hash, Hash->Items[i].key, column, delay);
	}
    }
    regfree(&preg);
    return sum;
}


/* insert a key/val pair into the hash table */
/* If the entry does already exist, it will be overwritten, */
/* and the table stays sorted (if it has been before). */
/* Otherwise, the entry is appended at the end, and  */
/* the table will be flagged 'unsorted' afterwards */

static HASH_ITEM *hash_set(HASH * Hash, const char *key, const char *value, const int delta)
{
    HASH_ITEM *Item;
    HASH_SLOT *Slot;
    int size;

    Item = hash_lookup(Hash, key, 0);

    if (Item == NULL) {

	/* add entry */
	Hash->sorted = 0;
	Hash->nItems++;
	Hash->Items = realloc(Hash->Items, Hash->nItems * sizeof(HASH_ITEM));

	Item = &(Hash->Items[Hash->nItems - 1]);
	Item->key = strdup(key);
	Item->index = 0;
	Item->nSlot = delta;
	Item->Slot = malloc(Item->nSlot * sizeof(HASH_SLOT));
	memset(Item->Slot, 0, Item->nSlot * sizeof(HASH_SLOT));

    } else {

	/* maybe enlarge delta table */
	if (Item->nSlot < delta) {
	    Item->nSlot = delta;
	    Item->Slot = realloc(Item->Slot, Item->nSlot * sizeof(HASH_SLOT));
	}

    }

    if (Item->nSlot > 1) {
	/* move the pointer to the next free slot, wrap around if necessary */
	if (--Item->index < 0)
	    Item->index = Item->nSlot - 1;
    }

    /* create entry */
    Slot = &(Item->Slot[Item->index]);
    size = strlen(value) + 1;

    /* maybe enlarge value buffer */
    if (size > Slot->size) {
	/* buffer is either empty or too small */
	/* allocate memory in multiples of CHUNK_SIZE */
	Slot->size = CHUNK_SIZE * (size / CHUNK_SIZE + 1);
	Slot->value = realloc(Slot->value, Slot->size);
    }

    /* set value */
    strcpy(Slot->value, value);

    /* set timestamps */
    gettimeofday(&(Hash->timestamp), NULL);
    Slot->timestamp = Hash->timestamp;

    return Item;
}


/* insert a string into the hash table */
/* without delta processing */
void hash_put(HASH * Hash, const char *key, const char *value)
{
    hash_set(Hash, key, value, 1);
}


/* insert a string into the hash table */
/* with delta processing */
void hash_put_delta(HASH * Hash, const char *key, const char *value)
{
    hash_set(Hash, key, value, DELTA_SLOTS);
}


void hash_destroy(HASH * Hash)
{
    int i;

    if (Hash->Items) {

	/* free all headers */
	for (i = 0; i < Hash->nColumns; i++) {
	    if (Hash->Columns[i].key)
		free(Hash->Columns[i].key);
	}

	/* free header table */
	free(Hash->Columns);

	/* free all items */
	for (i = 0; i < Hash->nItems; i++) {
	    if (Hash->Items[i].key)
		free(Hash->Items[i].key);
	    if (Hash->Items[i].Slot)
		free(Hash->Items[i].Slot);
	}

	/* free items table */
	free(Hash->Items);
    }

    Hash->sorted = 0;
    Hash->nItems = 0;
    Hash->Items = NULL;
}