shash.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * Copyright (c) 1998-1999 Jeremie Miller <jer@jabber.org>
  3. * Copyright (C) 2013 Ole Reinhardt <ole.reinhardt@embedded-it.de>
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. *
  35. */
  36. /* This code is based on
  37. * Based on BSD licensed mdnsd implementation by Jer <jer@jabber.org>
  38. * http://dotlocal.org/mdnsd/
  39. *
  40. * Unfortunately this site is now longer alive. You can still find it at:
  41. * http://web.archive.org/web/20080705131510/http://dotlocal.org/mdnsd/
  42. *
  43. * mdnsd - embeddable Multicast DNS Daemon
  44. * =======================================
  45. *
  46. * "mdnsd" is a very lightweight, simple, portable, and easy to integrate
  47. * open source implementation of Multicast DNS (part of Zeroconf, also called
  48. * Rendezvous by Apple) for developers. It supports both acting as a Query and
  49. * a Responder, allowing any software to participate fully on the .localnetwork
  50. * just by including a few files and calling a few functions. All of the
  51. * complexity of handling the Multicast DNS retransmit timing, duplicate
  52. * suppression, probing, conflict detection, and other facets of the DNS
  53. * protocol is hidden behind a very simple and very easy to use interface,
  54. * described in the header file. The single small c source file has almost no
  55. * dependencies, and is portable to almost any embedded platform.
  56. * Multiple example applications and usages are included in the download,
  57. * including a simple persistent query browser and a tool to advertise .local
  58. * web sites.
  59. *
  60. * The code is licensed under both the GPL and BSD licenses, for use in any
  61. * free software or commercial application. If there is a licensing need not
  62. * covered by either of those, alternative licensing is available upon request.
  63. *
  64. */
  65. /*!
  66. * \file gorp/hash/shash.c
  67. * \brief Simple hastable implementation of a string ==> void* hashtable
  68. * Minimal and efficient
  69. *
  70. * \verbatim
  71. *
  72. * $Id$
  73. *
  74. * \endverbatim
  75. */
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <stdint.h>
  79. #include <gorp/shash.h>
  80. /*!
  81. * \addtogroup xgSHash
  82. */
  83. /*@{*/
  84. typedef struct node_struct
  85. {
  86. char flag;
  87. struct node_struct *next;
  88. char *key;
  89. void *val;
  90. } *SHNODE;
  91. struct string_hash_table_struct
  92. {
  93. int prime;
  94. SHNODE zen;
  95. };
  96. /*!
  97. * \brief Generates a hash code for a string.
  98. *
  99. * This function uses the ELF hashing algorithm as reprinted in
  100. * Andrew Binstock, "Hashing Rehashed," Dr. Dobb's Journal, April 1996.
  101. *
  102. * \param s The string to hash
  103. *
  104. * \return The calculated hash value
  105. */
  106. static int32_t StrToHash(const char *str)
  107. {
  108. /* ELF hash uses uint8_ts and unsigned arithmetic for portability */
  109. const uint8_t *name = (const uint8_t *)str;
  110. uint32_t hash = 0;
  111. uint32_t g;
  112. while (*name) {
  113. /* do some fancy bit calculations on the string */
  114. hash = (hash << 4) + (uint32_t)(*name++);
  115. g = (hash & 0xF0000000UL);
  116. if (g != 0) {
  117. hash ^= (g >> 24);
  118. }
  119. hash &= ~g;
  120. }
  121. return (int32_t)hash;
  122. }
  123. /*!
  124. * \brief Initialise a new hash
  125. *
  126. * \param prime size of the hash (!!! You have to use a _prime_ number (e.g. 5, 7, 11, 13, ...) !!!)
  127. *
  128. * \return pointer to the new hash
  129. */
  130. SHASH SHashInit(int prime)
  131. {
  132. SHASH xnew;
  133. xnew = (SHASH)malloc(sizeof(struct string_hash_table_struct));
  134. xnew->prime = prime;
  135. xnew->zen = (SHNODE)malloc(sizeof(struct node_struct)*prime); /* array of SHNODE size of prime */
  136. memset(xnew->zen, 0, sizeof(struct node_struct)*prime);
  137. return xnew;
  138. }
  139. /*!
  140. * \brief Search the node for the given key in the hash table
  141. *
  142. * \param node starting node to search from
  143. * \param key The key to get
  144. *
  145. * \return The node or NULL of node was not found
  146. */
  147. static SHNODE SHashFindNode(SHNODE node, const char *key)
  148. {
  149. for(; node != 0; node = node->next) {
  150. if((node->key != 0) && (strcmp(key, node->key) == 0)) {
  151. return node;
  152. }
  153. }
  154. return 0;
  155. }
  156. /*!
  157. * \brief Helper function: Add a new entry to the hash table
  158. *
  159. * \param hash The hashtable to insert the new entry in
  160. * \param key The key, under which the value should be entered
  161. * \param val Void* pointer to be saved under 'key' in the hash table
  162. * \param flag If flag != 0 the node memory is freed first and managed by this function
  163. */
  164. static void SHashDoSet(SHASH hash, char *key, void *val, char flag)
  165. {
  166. int32_t i;
  167. SHNODE node;
  168. /* Get the hash index of the key */
  169. i = StrToHash(key) % hash->prime;
  170. /* Does the key just exists? If not, find an empty one */
  171. node = SHashFindNode(&hash->zen[i], key);
  172. if (node == 0) {
  173. for(node = &hash->zen[i]; node != 0; node = node->next) {
  174. if(node->val == 0) {
  175. break;
  176. }
  177. }
  178. }
  179. /* If the key does not exists, create a new node and link into the hash */
  180. if (node == 0) {
  181. node = (SHNODE)malloc(sizeof(struct node_struct));
  182. node->next = hash->zen[i].next;
  183. hash->zen[i].next = node;
  184. }
  185. /* If flag is set, the node memory will be freed first and then reused with the new key / value pair */
  186. if (node->flag) {
  187. free(node->key);
  188. free(node->val);
  189. }
  190. node->flag = flag;
  191. node->key = key;
  192. node->val = val;
  193. }
  194. /*!
  195. * \brief Add a new entry to the hash table
  196. *
  197. * The caller is responsible for the key storage. No copies are made.
  198. * Do not free these valued before calling SHashFree()!!!
  199. *
  200. * If val is set to NULL, the entry is cleared and the memory is reused but
  201. * never freed. The number of keys can only grow up to peak usage.
  202. *
  203. * \param hash The hashtable to insert the new entry in
  204. * \param key The key, under which the value should be entered
  205. * \param val Void* pointer to be saved under 'key' in the hash table
  206. */
  207. void SHashSet(SHASH hash, char *key, void *val)
  208. {
  209. if ((hash == 0) || (key == 0)) {
  210. return;
  211. }
  212. SHashDoSet(hash, key, val, 0);
  213. }
  214. /*!
  215. * \brief Add a new entry to the hash table
  216. *
  217. * Unlike SHashSet() where key and values are managed in the callers memory
  218. * space, here they are copied into the hash table and freed when
  219. * val is 0 or by calling SHashFree().
  220. *
  221. * If val is set to NULL, the entry is cleared and the memory is freed.
  222. *
  223. * \param hash The hashtable to insert the new entry in
  224. * \param key The key, under which the value should be entered
  225. * \param kley Size of the key
  226. * \param val Void* pointer to be saved under 'key' in the hash table
  227. * \param vlen Size of the value
  228. */
  229. void SHashStore(SHASH hash, const char *key, int key_len, void *val, int value_len)
  230. {
  231. char *ckey;
  232. char *cval;
  233. if((hash == 0) || (key == 0) || (key_len == 0)) {
  234. return;
  235. }
  236. ckey = (char*)malloc(key_len+1);
  237. memcpy(ckey, key, key_len);
  238. ckey[key_len] = '\0';
  239. /* Assume the value is a string too and store it with a trailing
  240. zero for safety reasons
  241. */
  242. cval = (void*)malloc(value_len+1);
  243. memcpy(cval, val, value_len);
  244. cval[value_len] = '\0';
  245. SHashDoSet(hash, ckey, cval, 1);
  246. }
  247. /*!
  248. * \brief Retrive a value associated to key from the hash table
  249. *
  250. * Return the value or NULL of the key was not found.
  251. *
  252. * \param hash The hast table to get the value from
  253. * \param key Key to get the value for
  254. * \return pointer to the value, NULL if no key was not found
  255. */
  256. void *SHashGet(SHASH hash, const char *key)
  257. {
  258. SHNODE node;
  259. if ((hash == 0) || (key == 0)) {
  260. return 0;
  261. }
  262. node = SHashFindNode(&hash->zen[StrToHash(key) % hash->prime], key);
  263. if (node == NULL) {
  264. return 0;
  265. }
  266. return node->val;
  267. }
  268. /*!
  269. * \brief Free the hash table and all entries
  270. *
  271. * \param hash The hast table to free
  272. */
  273. void SHashFree(SHASH hash)
  274. {
  275. SHNODE node;
  276. SHNODE temp;
  277. int i;
  278. if(hash == 0) {
  279. return;
  280. }
  281. for (i = 0; i < hash->prime; i++) {
  282. for (node = (&hash->zen[i])->next; node != 0; ) {
  283. temp = node->next;
  284. if (node->flag) {
  285. free(node->key);
  286. free(node->val);
  287. }
  288. free(node);
  289. node = temp;
  290. }
  291. }
  292. free(hash->zen);
  293. free(hash);
  294. }
  295. /*!
  296. * \brief Interate over the hash table and call a callback for each key
  297. * that has a value set.
  298. *
  299. *
  300. * \param hash The hash table to iterate though
  301. * \param cb SHASH_CB callback function
  302. * \param arg An optional user pointer to pass to the callback function
  303. */
  304. void SHashForEach(SHASH hash, SHASH_CB cb, void *arg)
  305. {
  306. int i;
  307. SHNODE node;
  308. if ((hash == 0) || (cb == 0)) {
  309. return;
  310. }
  311. for(i = 0; i < hash->prime; i++) {
  312. for(node = &hash->zen[i]; node != 0; node = node->next) {
  313. if(node->key != 0 && node->val != 0) {
  314. (*cb)(hash, node->key, node->val, arg);
  315. }
  316. }
  317. }
  318. }
  319. /*@}*/