/* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2005 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* numhash.c
*
* NUMBER HASH functions
*
* functions to add a number to database/hash
* and functions to retrieve them
*
* notes: read header file
*
* Kalle Marjola for project Kannel 1999-2000
*/
#include
#include
#include
#include
#include "gwlib/gwlib.h"
#include "numhash.h"
#define NUMHASH_AUTO_HASH -1
/* set of pre-calculated prime numbers for hash generation... */
static int primes[] = {
101, 503, 1009, 2003, 3001, 5003, 7001,
10007, 20011, 30011, 40009, 50021, 60013, 70001, 80021, 90001,
100003, 150001, 200003, 300007, 400009, 500009, 600011, 700001,
800011, 900001, 1000003, 1100009, 1200007, 1300021, 1400017, 1500007,
1600033, 1700021, 1800017, 1900009, 2000003, 3000017, 4000037, 5000111,
6000101, 7000127, 8000051, -1
};
struct numhash_table {
struct numhash_number *numbers;
long number_total;
long table_size;
struct numhash_number **hash;
long hash_size;
}; /* Numhash */
struct numhash_number {
long key; /* (hopefully) unique key */
struct numhash_number *next; /* next in hash table, if any */
};
struct nh_entry {
Numhash *hash;
struct nh_entry *next;
};
struct numhashes {
struct nh_entry *first;
struct nh_entry *last;
}; /* Multitable */
static int precision = 9; /* the precision (last numbers) used */
/*
* add new item (number) to hash table
*/
static int add_item(Numhash *table, struct numhash_number *nro)
{
if (table->hash[nro->key % table->hash_size]) { /* conflict */
struct numhash_number *ptr = table->hash[nro->key % table->hash_size];
if (ptr->key == nro->key)
goto duplicate;
while(ptr->next) {
ptr = ptr->next;
if (ptr->key == nro->key)
goto duplicate;
}
ptr->next = nro; /* put as last of the linkage */
} else
table->hash[nro->key % table->hash_size] = nro;
return 0;
duplicate:
warning(0, "Duplicate number %ld!", nro->key);
return -1;
}
/* Add a new number to number list and hash
* Return 0 if all went ok, -1 if out of room
*/
static int numhash_add_number(Numhash *table, char *nro)
{
struct numhash_number *newnro;
if (table->number_total == table->table_size) {
error(0, "Table limit %ld reached, cannot add %s!",
table->table_size, nro);
return -1;
}
newnro = &table->numbers[table->number_total++]; /* take the next free */
newnro->key = numhash_get_char_key(nro);
newnro->next = NULL;
add_item(table, newnro);
return 0;
}
/* Init the number table and hash table with given sizes
*/
static Numhash *numhash_init(int max_numbers, int hash_size)
{
Numhash *ntable = NULL;
ntable = gw_malloc(sizeof(Numhash));
if (hash_size > 0)
ntable->hash_size = hash_size;
else if (hash_size == NUMHASH_AUTO_HASH) {
int i;
for(i=0 ; primes[i] > 0; i++) {
ntable->hash_size = primes[i];
if (ntable->hash_size > max_numbers)
break;
}
} else {
gw_free(ntable);
return NULL;
}
ntable->hash = gw_malloc(ntable->hash_size * sizeof(struct numhash_number *));
memset(ntable->hash, 0, sizeof(struct numhash_number *) * ntable->hash_size);
ntable->table_size = max_numbers;
ntable->numbers = gw_malloc(ntable->table_size * sizeof(struct numhash_number));
ntable->number_total = 0;
/* set our accuracy according to the size of long int
* Ok, we call this many times if we use multiple tables, but
* that is not a problem...
*/
if (sizeof(long)>=8) precision = 18;
else if (sizeof(long)>=4) precision = 9;
return ntable;
}
/*------------------------------------------------------
* PUBLIC FUNCTIONS
*/
int numhash_find_number(Numhash *table, Octstr *nro)
{
long key = numhash_get_key(nro);
if (key<0) return key;
return numhash_find_key(table, key);
}
int numhash_find_key(Numhash *table, long key)
{
struct numhash_number *ptr;
ptr = table->hash[key % table->hash_size];
while (ptr) {
if (ptr->key == key) return 1;
ptr = ptr->next;
}
return 0; /* not found */
}
long numhash_get_key(Octstr *nro)
{
long key;
if (!nro) return -1;
if (octstr_len(nro) > precision)
key = atoi(octstr_get_cstr(nro) + octstr_len(nro) -precision);
else
key = atoi(octstr_get_cstr(nro));
return key;
}
long numhash_get_char_key(char *nro)
{
int len;
long key;
if (!nro) return -1;
len = strlen(nro);
if (len > precision)
key = atoi(nro + len -precision);
else
key = atoi(nro);
return key;
}
void numhash_destroy(Numhash *table)
{
if (table == NULL)
return;
gw_free(table->numbers);
gw_free(table->hash);
gw_free(table);
}
double numhash_hash_fill(Numhash *table, int *longest)
{
int i, l, max = 0, tot = 0;
struct numhash_number *ptr;
for (i=0; i < table->hash_size; i++)
if (table->hash[i]) {
tot++;
ptr = table->hash[i];
for (l=0; ptr->next; ptr = ptr->next)
l++;
if (l > max)
max = l;
}
if (longest != NULL)
*longest = max;
return (double)(tot*100.0/(table->hash_size));
}
int numhash_size(Numhash *table)
{
return table->number_total;
}
Numhash *numhash_create(char *seek_url)
{
int loc, lines = 0;
List *request_headers, *reply_headers;
Octstr *url, *final_url, *reply_body;
Octstr *type, *charset;
unsigned char *data, *ptr, numbuf[100];
int status;
Numhash *table;
url = octstr_create(seek_url);
request_headers = gwlist_create();
status = http_get_real(HTTP_METHOD_GET, url, request_headers, &final_url,
&reply_headers, &reply_body);
octstr_destroy(url);
octstr_destroy(final_url);
gwlist_destroy(request_headers, NULL);
if (status != HTTP_OK) {
http_destroy_headers(reply_headers);
octstr_destroy(reply_body);
error(0, "Cannot load numhash!");
return NULL;
}
http_header_get_content_type(reply_headers, &type, &charset);
octstr_destroy(charset);
http_destroy_headers(reply_headers);
if (octstr_str_compare(type, "text/plain") != 0) {
octstr_destroy(reply_body);
error(0, "Strange content type <%s> for numhash - expecting 'text/plain'"
", operatiom fails", octstr_get_cstr(type));
octstr_destroy(type);
return NULL;
}
octstr_destroy(type);
ptr = data = octstr_get_cstr(reply_body);
while(*ptr) {
if (*ptr == '\n') lines++;
ptr++;
}
debug("numhash", 0, "Total %d lines in %s", lines, seek_url);
table = numhash_init(lines+10, NUMHASH_AUTO_HASH); /* automatic hash */
/* now, parse the number information */
lines = 0;
while((ptr = strchr(data, '\n'))) { /* each line is ended with linefeed */
*ptr = '\0';
while(*data != '\0' && isspace(*data))
data++;
if (*data != '#') {
loc = 0;
while (*data != '\0') {
if (isdigit(*data))
numbuf[loc++] = *data;
else if (*data == ' ' || *data == '+' || *data == '-')
;
else break;
data++;
}
if (loc) {
numbuf[loc] = '\0';
numhash_add_number(table, numbuf);
lines++;
}
else
warning(0, "Corrupted line '%s'", data);
}
data = ptr+1; /* next row... */
}
octstr_destroy(reply_body);
info(0, "Read from <%s> total of %ld numbers", seek_url, table->number_total);
return table;
}