summaryrefslogtreecommitdiff
path: root/libhashtable/libhashtable.c
blob: c4ac2d3c6d101c5a63b5b7f3dafa23452f1aa494 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"

/*
struct entry {//linked list node.
 char *original;
 char *target;
 struct entry *prev;// doubly linked list. why?
 struct entry *next;
};

struct hitem {//dunno why I don't just have this as a linked list.
 struct entry *ll;
};

struct hashtable {
 int kl;//number of keys in the table
 struct hitem **bucket;
 int *keys;
};
*/

unsigned short hash(char *v) {//maybe use a seeded rand()? :) Thanks FreeArtMan
 unsigned short h=0;
 h=((*v)<<8)+(v?*(v+1):0);
 srand(h);
 return rand();
}

void inittable(struct hashtable *ht,int tsize) {
 int i;
 ht->bucket=malloc(sizeof(char *)*tsize);
 ht->kl=0;
 ht->keys=malloc(sizeof(int *)*tsize);
 if(!ht) {
  fprintf(stderr,"malloc error 6 in hash table.\n");
  return;
 }
 for(i=0;i<tsize;i++) {
  ht->bucket[i]=0;
 }
}

//this seems too complicated.
int ht_setkey(struct hashtable *ht,char *key,char *value) {
 unsigned short h=hash(key);
 struct entry *tmp;
 int i;
 for(i=0;i<ht->kl;i++) {
  if(ht->keys[i]==h) break;
 }
 ht->keys[i]=h;
 ht->kl=(ht->kl)>i+1?ht->kl:i+1;
 if(!ht->bucket[h]) { //empty bucket!
  //add this to the list of used buckets so we can easily
  //use that list later for stuff.
  if(!(ht->bucket[h]=malloc(sizeof(struct hitem)))) return 1; 
  ht->bucket[h]->ll=0;
  //we now have a valid hashtable entry and a NULL ll in it.
  //don't bother with the new ll entry yet...
 }
 if((tmp=ll_getentry(ht->bucket[h]->ll,key)) != NULL) {
  //we found this alias in the ll. now to replace the value
  free(tmp->target);
  if(!(tmp->target=strdup(value))) return 2;
  return 0;
 }
 if(ht->bucket[h]->ll == NULL) {
  if(!(ht->bucket[h]->ll=malloc(sizeof(struct entry)))) return 3;
  ht->bucket[h]->ll->next=0;
  ht->bucket[h]->ll->prev=0;
  if(!(ht->bucket[h]->ll->original=strdup(key))) return 4;
  if(!(ht->bucket[h]->ll->target=strdup(value))) return 5;
 } else {
  //go to the end and add another entry to the ll.
  for(tmp=ht->bucket[h]->ll;tmp->next;tmp=tmp->next);
  if(!(tmp->next=malloc(sizeof(struct entry)))) return 6;
  tmp->next->prev=tmp;
  tmp=tmp->next;
  if(!(tmp->original=strdup(key))) return 7;
  if(!(tmp->target=strdup(value))) return 8;
  tmp->next=0;
 }
 return 0;
}

struct entry *ll_getentry(struct entry *start,char *msg) {
 struct entry *m;
 if(!msg) return NULL;
 if(!start) return NULL;
 for(m=start;m;m=m->next) {
  if(!strncmp(msg,m->original,strlen(m->original)) && (msg[strlen(m->original)]==' ' || msg[strlen(m->original)] == 0)) {//this allows !c to get called when using !c2 if !c2 is defined after !c. >_>
   return m;
  }
 }
 return NULL;
}

struct entry *ht_getentry(struct hashtable *ht,char *key) {
 unsigned short h=hash(key);
 if(!ht->bucket[h]) return NULL;
 return ht->bucket[h]->ll;
}

struct entry *ht_getnode(struct hashtable *ht,char *msg) {
 return ll_getentry(ht_getentry(ht,msg),msg);
}

//you'll probably want to use me.
char *ht_getvalue(struct hashtable *ht,char *msg) {
 struct entry *tmp=ll_getentry(ht_getentry(ht,msg),msg);
 return tmp?tmp->target:0;
}