1 /**
2  * Hash table to be used by DinkC's 'sp_custom' function
3 
4  * Copyright (C) 2008, 2009  Sylvain Beucler
5 
6  * This file is part of GNU FreeDink
7 
8  * GNU FreeDink is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 3 of the
11  * License, or (at your option) any later version.
12 
13  * GNU FreeDink is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17 
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see
20  * <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "log.h"
32 #include "dinkc_sp_custom.h"
33 
34 # include <stdbool.h>
35 struct str_int
36 {
37   char key[200]; // same size as slist[0][]
38   int val;
39 };
40 
41 /* Auxiliary functions for hash */
dinkc_sp_custom_hasher(const void * x,size_t tablesize)42 static size_t dinkc_sp_custom_hasher(const void *x, size_t tablesize)
43 {
44   return hash_string(((struct str_int*)x)->key, tablesize);
45   // We could also call 'hash_pjw' from module 'hash-pjw'
46 }
dinkc_sp_custom_comparator(const void * a,const void * b)47 static bool dinkc_sp_custom_comparator(const void* a, const void* b)
48 {
49   return !strcmp(((struct str_int*)a)->key,
50 		 ((struct str_int*)b)->key);
51 }
52 
53 /**
54  * Return a new hash table
55  */
dinkc_sp_custom_new()56 dinkc_sp_custom dinkc_sp_custom_new()
57 {
58   Hash_tuning* default_tuner = NULL;
59   int start_size = 10;
60 
61   return hash_initialize(start_size, default_tuner,
62 			 dinkc_sp_custom_hasher, dinkc_sp_custom_comparator,
63 			 free);
64 }
65 
66 /**
67  * Free all memory
68  */
dinkc_sp_custom_free(dinkc_sp_custom hash)69 void dinkc_sp_custom_free(dinkc_sp_custom hash)
70 {
71   hash_free(hash);
72 }
73 
dinkc_sp_custom_clear(dinkc_sp_custom hash)74 void dinkc_sp_custom_clear(dinkc_sp_custom hash)
75 {
76   hash_clear(hash);
77 }
78 
79 /**
80  * Create a new int value for key 'key', or replace existing value if
81  * 'key' is already mapped.
82  */
dinkc_sp_custom_set(dinkc_sp_custom hash,char key[200],int val)83 void dinkc_sp_custom_set(dinkc_sp_custom hash, char key[200], int val)
84 {
85   struct str_int search;
86   strcpy(search.key, key);
87   void* slot = hash_lookup(hash, &search);
88   if (slot != NULL)
89     {
90       ((struct str_int*)slot)->val = val;
91     }
92   else
93     {
94       struct str_int* newslot = malloc(sizeof(struct str_int));
95       strcpy(newslot->key, key);
96       ((struct str_int*)newslot)->val = val;
97       if (hash_insert(hash, newslot) == NULL)
98 	{
99 	  log_fatal("sp_custom: Not enough memory to add value '%s'", key);
100 	  exit(EXIT_FAILURE);
101 	}
102     }
103 }
104 
105 /**
106  * Get the int value associated with 'key'. Returns -1 if not found
107  * (DinkC limitation: no way to return NULL or similar).
108  */
dinkc_sp_custom_get(dinkc_sp_custom hash,char key[200])109 int dinkc_sp_custom_get(dinkc_sp_custom hash, char key[200])
110 {
111   struct str_int search;
112   strcpy(search.key, key);
113   void* slot = hash_lookup(hash, &search);
114   if (slot != NULL)
115     return ((struct str_int*)slot)->val;
116   else
117     return -1;
118 }
119 
120 
121 #ifdef TEST
122 
main(void)123 int main(void)
124 {
125   dinkc_sp_custom myhash = dinkc_sp_custom_new();
126 
127   dinkc_sp_custom_set(myhash, "foo", -1);
128   dinkc_sp_custom_set(myhash, "foo", 3);
129   dinkc_sp_custom_set(myhash, "foo", -1);
130   dinkc_sp_custom_set(myhash, "foo", 4);
131 
132   dinkc_sp_custom_set(myhash, "bar", 34);
133 
134   printf("foo: %d\n", dinkc_sp_custom_get(myhash, "foo"));
135   printf("bar: %d\n", dinkc_sp_custom_get(myhash, "bar"));
136 
137   dinkc_sp_custom_clear(myhash);
138   printf("foo (after clear): %d\n", dinkc_sp_custom_get(myhash, "foo"));
139 
140   dinkc_sp_custom_free(myhash);
141   return 0;
142 }
143 
144 #endif
145