1/***************************************************
2 * File name: dict.c
3 *
4 * Copyright 200X Gigle Semiconductor as an unpublished work.
5 * All Rights Reserved.
6 *
7 *  The information contained herein is confidential
8 * property of Company. The user, copying, transfer or
9 * disclosure of such information is prohibited except
10 * by express written agreement with Company.
11 *
12 * First written on 03/08/2010 by Toni Homedes i Saun.
13 *
14 ***************************************************/
15/** \file dict.c
16 */
17/** \defgroup dict  Simple Dictionnary
18 *
19 *  \ingroup gigled Gigle Daemon
20 *
21 *  \brief Simple key/value dictionary implementation
22 *
23 *  Simples't possible implementation of a dictionary. Expected number of
24 *  entries is very low (about 10~20) so emphasis has been given to simplicity
25 *  to reduce risk
26 *
27 *  The dictionnary is based on a single linked list and a head pointer.
28 *  Elements are always unshifted at the front of the list; no order is kept.
29 *
30 * $Id: dict.c 245438 2011-03-10 01:54:50Z rnuti $
31 */
32/*@{*/
33
34/***************************************************
35*                 Include section
36***************************************************/
37
38/* FILE-CSTYLED */
39
40#include "dict.h"
41
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47/***************************************************
48 *                 Local Defines Section
49 ***************************************************/
50
51/***************************************************
52 *                 Local Constants Section
53 ***************************************************/
54
55/***************************************************
56 *                 Local Typedefs Section
57 ***************************************************/
58
59/** \brief Dict list node
60 */
61typedef struct s_dict_node {
62  struct s_dict_node *next; /**< \brief Pointer to next node of NULL if NIL */
63  char * key;               /**< \brief Pointer to malloc'ed key copy       */
64  char * value;             /**< \brief Pointer to malloc'ed value copy     */
65}
66  t_dict_node;
67
68/***************************************************
69 *                 Local Variables Section
70 ***************************************************/
71
72/** This macro for easier rewriting */
73#define Dict_head (*(t_dict_node **)dict)
74
75/**************************************************
76 *  Function Prototype Section
77 * Add prototypes for all local functions defined
78 * in this file
79 ***************************************************/
80static t_dict_node *DictInternalFind(dict_hdl_t dict, const char * const key);
81static void DictInternalFreeNode(t_dict_node ** const p);
82
83/***************************************************
84 *  Function Definition Section
85 * Define all public and local functions from now on
86 **************************************************/
87
88/**************************************************
89 * Function name : static t_dict_node *DictInternalFind(const char * const key)
90 * Created by    : Toni Homedes i Saun
91 * Date created  : 03-08-2010
92 * Notes         : Public function
93 *                 Restrictions (pre-conditions)
94 *                 Odd modes (post-conditions)
95 **************************************************/
96/** \brief Searches for given key and returns pointer to the whole node
97 *
98 *  \param[in]  key Pointer to the key to search for
99 *
100 *  \return Pointer to the found node or NULL if not
101 *
102 **************************************************/
103static t_dict_node *DictInternalFind(const dict_hdl_t dict, const char * const key)
104{
105  t_dict_node *p;
106
107  /* run over list looking for key */
108  for (p = Dict_head; p; p = p->next)
109    if (!strcmp(key, p->key))
110      break;
111  return p;
112}
113
114/**************************************************
115 * Function name : static void DictInternalFreeNode(t_dict_node ** const p)
116 * Created by    : Toni Homedes i Saun
117 * Date created  : 03-08-2010
118 * Notes         : Public function
119 *                 Restrictions (pre-conditions)
120 *                 Odd modes (post-conditions)
121 **************************************************/
122/** \brief Frees passed node and related mallocs and relinks list
123 *
124 *  \param[in,out] p Pointer to the pointer holding node to delete
125 *
126 **************************************************/
127static void DictInternalFreeNode(t_dict_node ** const p)
128{
129  if (*p)
130  {
131    t_dict_node *tmp = (*p)->next;
132    free((*p)->key);
133    free((*p)->value);
134    free(*p);
135    *p = tmp;
136  }
137}
138
139/**************************************************
140 * Function name : dict_hdl_t DictNew(void)
141 * Created by    : Toni Homedes i Saun
142 * Date created  : 05-10-2010
143 * Notes         : Public function
144 *                 Restrictions (pre-conditions)
145 *                 Odd modes (post-conditions)
146 **************************************************/
147/** \brief Creates a new Dictionary
148 *
149 *  \return New dictionnary handle
150 *
151 **************************************************/
152dict_hdl_t DictNew(void)
153{
154  t_dict_node * const *dict = malloc(sizeof (t_dict_node*));
155  if (!dict)
156  {
157    perror("Can't get memory for dict handle");
158    exit(EXIT_FAILURE);
159  }
160  Dict_head = NULL;
161  return (dict_hdl_t)dict;
162}
163
164/**************************************************
165 * Function name : static t_dict_node *DictInternalFind(const char * const key)
166 * Created by    : Toni Homedes i Saun
167 * Date created  : 03-08-2010
168 * Notes         : Public function
169 *                 Restrictions (pre-conditions)
170 *                 Odd modes (post-conditions)
171 **************************************************/
172/** \brief Searches for given key and returns pointer to the whole node
173 *
174 *  \param[in]  key Pointer to the key to search for
175 *
176 *  \return Pointer to the found node or NULL if not
177 *
178 **************************************************/
179void DictFree(dict_hdl_t dict)
180{
181  if (dict)
182    DictDoEmpty(dict);
183
184  free((void *)dict);
185}
186
187/**************************************************
188 * Function name : void DictSet(const char * const key, const char * const
189 *                     value)
190 * Created by    : Toni Homedes i Saun
191 * Date created  : 03-08-2010
192 * Notes         : Public function
193 *                 Restrictions (pre-conditions)
194 *                 Odd modes (post-conditions)
195 **************************************************/
196/** \brief Sets given value in the dictionary
197 *
198 *  \param[in] key    Key to store
199 *  \param[in] value  Value to store
200 *
201 **************************************************/
202void DictSet(const dict_hdl_t dict, const char * const key, const char * const
203    value)
204{
205  t_dict_node *node = DictInternalFind(dict, key);
206
207  if (node)
208  {
209    if (strcmp(node->value, value))
210    {
211      free(node->value);
212      node->value = strdup(value);
213    }
214  }
215  else
216  {
217    /* Inset new node in linked list */
218    /* for this application we are assuming we'll never run out of memory */
219    node = malloc(sizeof *node);
220    node->key = strdup(key);
221    node->value = strdup(value);
222    node->next = Dict_head;
223    Dict_head = node;
224  }
225}
226
227/**************************************************
228 * Function name : const char *DictGet(const char * const key)
229 *                     value)
230 * Created by    : Toni Homedes i Saun
231 * Date created  : 03-08-2010
232 * Notes         : Public function
233 *                 Restrictions (pre-conditions)
234 *                 Odd modes (post-conditions)
235 **************************************************/
236/** \brief Gets a key's value from the dictionnary
237 *
238 *  \param[in]  key    Key to store
239 *
240 *  \returns    value if found or NULL if not
241 *
242 **************************************************/
243const char *DictGet(const dict_hdl_t dict, const char * const key)
244{
245  t_dict_node *node = DictInternalFind(dict, key);
246  return node ? node->value : NULL;
247}
248
249/**************************************************
250 * Function name : void DictDelete(const char * const key)
251 * Created by    : Toni Homedes i Saun
252 * Date created  : 03-08-2010
253 * Notes         : Public function
254 *                 Restrictions (pre-conditions)
255 *                 Odd modes (post-conditions)
256 **************************************************/
257/** \brief Deletes given value from the dictionary
258 *
259 *  \param[in] key    Key to delete
260 *
261 **************************************************/
262void DictDelete(const dict_hdl_t dict, const char * const key)
263{
264  t_dict_node **p;
265
266  /* run over list looking for key keeping a * to previous for relinking */
267  for (p = &Dict_head; *p; p = &(*p)->next)
268    if (!strcmp(key, (*p)->key))
269      break;
270
271  DictInternalFreeNode(p);
272}
273
274/**************************************************
275 * Function name : int DictIsEmpty(void)
276 * Created by    : Toni Homedes i Saun
277 * Date created  : 03-08-2010
278 * Notes         : Public function
279 *                 Restrictions (pre-conditions)
280 *                 Odd modes (post-conditions)
281 **************************************************/
282/** \brief Checks if the dictionary is empty
283 *
284 **************************************************/
285int DictIsEmpty(const dict_hdl_t dict)
286{
287  return NULL == Dict_head;
288}
289
290/**************************************************
291 * Function name : void DictDoEmpty(void)
292 * Created by    : Toni Homedes i Saun
293 * Date created  : 03-08-2010
294 * Notes         : Public function
295 *                 Restrictions (pre-conditions)
296 *                 Odd modes (post-conditions)
297 **************************************************/
298/** \brief Empties the dictionary
299 *
300 **************************************************/
301void DictDoEmpty(const dict_hdl_t dict)
302{
303  while (Dict_head)
304  {
305    DictInternalFreeNode(&Dict_head);
306  }
307}
308
309/**************************************************
310 * Function name : void DictMap(void (*fn)(const char *key, const char *value))
311 * Created by    : Toni Homedes i Saun
312 * Date created  : 03-08-2010
313 * Notes         : Public function
314 *                 Restrictions (pre-conditions)
315 *                 Odd modes (post-conditions)
316 **************************************************/
317/** \brief Maps a function on all dictionary entries. Order is random.
318 *
319 *  \param[in]  fn    Fucntion to be mapped
320 *
321 **************************************************/
322void DictMap(const dict_hdl_t dict, void (*fn)(const char *key, const char *value))
323{
324  t_dict_node *p;
325  for (p = Dict_head; p; p = p->next)
326    fn(p->key, p->value);
327}
328
329/**************************************************
330 * Function name : dict_iterator_t DictIteratorNew(dict_hdl_t dict)
331 *                     value)
332 * Created by    : Toni Homedes i Saun
333 * Date created  : 06-10-2010
334 * Notes         : Public function
335 *                 Restrictions (pre-conditions)
336 *                 Odd modes (post-conditions)
337 **************************************************/
338/** \brief Create a new Dict Iterator
339 *
340 *  \param[in] dict   Dictionnary
341 *
342 **************************************************/
343dict_iterator_t DictIteratorNew(dict_hdl_t dict)
344{
345  t_dict_node ** const iterator = malloc(sizeof (t_dict_node*));
346  if (!iterator)
347  {
348    perror("Can't get memory for iterator handle");
349    exit(EXIT_FAILURE);
350  }
351  *iterator = Dict_head;
352  return (dict_iterator_t)iterator;
353}
354
355/**************************************************
356 * Function name : void DictSet(const char * const key, const char * const
357 *                     value)
358 * Created by    : Toni Homedes i Saun
359 * Date created  : 06-10-2010
360 * Notes         : Public function
361 *                 Restrictions (pre-conditions)
362 *                 Odd modes (post-conditions)
363 **************************************************/
364/** \brief Destroys given iterator
365 *
366 *  \param[in] iterator Iterator to destroy
367 *
368 **************************************************/
369void DictIteratorFree(dict_iterator_t iterator)
370{
371  free((void *)iterator);
372}
373
374/**************************************************
375 * Function name : const char *DictIteratorKey(dict_iterator_t iterator)
376 * Created by    : Toni Homedes i Saun
377 * Date created  : 06-10-2010
378 * Notes         : Public function
379 *                 Restrictions (pre-conditions)
380 *                 Odd modes (post-conditions)
381 **************************************************/
382/** \brief Returns key for given iterator
383 *
384 *  \param[in] iterator Iterator to use
385 *
386 **************************************************/
387const char *DictIteratorKey(dict_iterator_t iterator)
388{
389  t_dict_node **p = (t_dict_node **)iterator;
390
391  return *p ? (*p)->key : NULL;
392}
393
394/**************************************************
395 * Function name : void DictSet(const char * const key, const char * const
396 *                     value)
397 * Created by    : Toni Homedes i Saun
398 * Date created  : 06-10-2010
399 * Notes         : Public function
400 *                 Restrictions (pre-conditions)
401 *                 Odd modes (post-conditions)
402 **************************************************/
403/** \brief Advances given iterator
404 *
405 *  \param[in] iterator Iterator to advance
406 *
407 **************************************************/
408int DictIteratorAdvance(dict_iterator_t iterator)
409{
410  t_dict_node **p = (t_dict_node **)iterator;
411
412  if (*p)
413    *p = (*p)->next;
414
415  return *p != NULL;
416}
417
418/*@}*/
419