1 /*******************************************************************************
2  * Copyright (c) 2013-2017, Andrés Martinelli <andmarti@gmail.com              *
3  * All rights reserved.                                                        *
4  *                                                                             *
5  * This file is a part of SC-IM                                                *
6  *                                                                             *
7  * SC-IM is a spreadsheet program that is based on SC. The original authors    *
8  * of SC are James Gosling and Mark Weiser, and mods were later added by       *
9  * Chuck Martin.                                                               *
10  *                                                                             *
11  * Redistribution and use in source and binary forms, with or without          *
12  * modification, are permitted provided that the following conditions are met: *
13  * 1. Redistributions of source code must retain the above copyright           *
14  *    notice, this list of conditions and the following disclaimer.            *
15  * 2. Redistributions in binary form must reproduce the above copyright        *
16  *    notice, this list of conditions and the following disclaimer in the      *
17  *    documentation and/or other materials provided with the distribution.     *
18  * 3. All advertising materials mentioning features or use of this software    *
19  *    must display the following acknowledgement:                              *
20  *    This product includes software developed by Andrés Martinelli            *
21  *    <andmarti@gmail.com>.                                                    *
22  * 4. Neither the name of the Andrés Martinelli nor the                        *
23  *   names of other contributors may be used to endorse or promote products    *
24  *   derived from this software without specific prior written permission.     *
25  *                                                                             *
26  * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY            *
27  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED   *
28  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE      *
29  * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY           *
30  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES  *
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;*
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  *
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE       *
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
36  *******************************************************************************/
37 
38 /**
39  * \file dictionary.c
40  * \author Andrés Martinelli <andmarti@gmail.com>
41  * \date 2017-07-18
42  * \brief Dictionary implementation using malloc
43  */
44 
45 #include <stdlib.h>
46 #include <string.h>
47 #include "dictionary.h"
48 
49 /**
50  * \brief TODO Document create_dictionary()
51  *
52  * \return dictionary
53  */
54 
create_dictionary()55 struct dictionary * create_dictionary() {
56    struct dictionary * d = malloc(sizeof(struct dictionary));
57    d->len = 0;
58    d->list = NULL;
59 
60    return d;
61 }
62 
63 /**
64  * \brief TODO Document put()
65  *
66  * \param[in] d
67  * \param[in] k
68  * \param[in] v
69  *
70  * \return none
71  */
72 
put(struct dictionary * d,const char * k,const char * v)73 void put(struct dictionary * d, const char * k, const char * v) {
74    struct nlist *nl, **p_nl;
75 
76    if (*k == 0) return;
77 
78    // locate the key position
79    for (p_nl = &d->list; *p_nl; p_nl = &(*p_nl)->next) {
80       nl = *p_nl;
81       int cmp = strcmp(k, nl->key);
82       if (cmp > 0) continue;
83       if (cmp < 0) break;
84 
85       // Duplicated keys are not allowed.
86       // If an existing key is inserted, the value is overwritten.
87       free(nl->val);
88       nl->val = strdup(v);
89       nl->intval = atoi(v);
90       return;
91    }
92 
93    // The key doesn't exists, Create it.
94    nl = malloc(sizeof(struct nlist));
95    nl->key = strdup(k);
96    nl->val = strdup(v);
97    nl->intval = atoi(v);
98    nl->next = *p_nl;
99    *p_nl = nl;
100    d->len++;
101 }
102 
103 /**
104  * \brief TODO Document destroy_dictionary()
105  *
106  * \param[in] d
107  *
108  * \return none
109  */
110 
destroy_dictionary(struct dictionary * d)111 void destroy_dictionary(struct dictionary * d) {
112    struct nlist * nl;
113    struct nlist * n_next;
114 
115    nl = d->list;
116    while (nl != NULL) {
117        n_next = nl->next;
118        free(nl->key);
119        free(nl->val);
120        free(nl);
121        nl = n_next;
122    }
123 
124    free(d);
125    return;
126 }
127 
128 /**
129  * \brief Get the size in bytes needed to export a dictionary
130  *
131  * \param[in] d
132  *
133  * \return count
134  */
135 
get_dict_buffer_size(struct dictionary * d)136 int get_dict_buffer_size(struct dictionary * d) {
137    struct nlist * nl;
138    int count = 0;
139 
140    for (nl = d->list; nl != NULL; nl = nl->next) {
141       /* <key> + '=' + <val> + '\n' */
142       count += strlen(nl->key) + 1 + strlen(nl->val) + 1;
143    }
144    return count;
145 }
146 
147 /**
148  * \brief Get the string value for KEY
149  *
150  * \param[in] d
151  * \param[in] key
152  *
153  * \return value for the key
154  */
155 
get(struct dictionary * d,const char * key)156 char * get(struct dictionary * d, const char * key) {
157    struct nlist * nl;
158 
159    for (nl = d->list; nl != NULL; nl = nl->next) {
160       int cmp = strcmp(key, nl->key);
161       if (cmp > 0) continue;
162       if (cmp < 0) break;
163       return nl->val;
164    }
165    return NULL;
166 }
167 
168 /**
169  * \brief Get the integer value for KEY
170  *
171  * \param[in] d
172  * \param[in] key
173  *
174  * \return value for the key
175  */
176 
get_int(struct dictionary * d,const char * key)177 int get_int(struct dictionary * d, const char * key) {
178    struct nlist * nl;
179 
180    for (nl = d->list; nl != NULL; nl = nl->next) {
181       int cmp = strcmp(key, nl->key);
182       if (cmp > 0) continue;
183       if (cmp < 0) break;
184       return nl->intval;
185    }
186    return 0;
187 }
188 
189 /* Get the key name from a value
190 char * get_key_name(struct dictionary * d, const char * value) {
191    struct nlist * nl;
192 
193    for (nl = d->list; nl != NULL; nl = nl->next) {
194        if (! strcmp(nl->val, value))
195            return nl->key;
196    }
197    return NULL;
198 }
199 */
200 
201 
202 /**
203  * \brief Save key/value pairs in D dictionary from a string STR
204  *
205  * \param[in] d
206  * \param[in] str
207  * \param[in] split_on_blanks
208  *
209  * \return dictionary
210  */
211 
parse_str(struct dictionary * d,const char * str,int split_on_blanks)212 void parse_str(struct dictionary *d, const char *str, int split_on_blanks) {
213     char key[90];
214     char value[90];
215     int i;
216 
217     while (*str != 0) {
218         /* remove leading field separators */
219         if (*str == ' ' || *str == '\n') {
220             str++;
221             continue;
222         }
223 
224         /* collect the key */
225         i = 0;
226         for (;;) {
227             if (*str == '=') {
228                 /* we are done with the key */
229                 key[i] = 0;
230                 break;
231             }
232             if (*str == 0 || *str == '\n' || (split_on_blanks && *str == ' ')) {
233                 /* got only a key: pretend the value is 1 */
234                 key[i] = 0;
235                 put(d, key, "1");
236                 break;
237             }
238             if (*str == ' ') {
239                 /* spaces in the key are invalid */
240                 return;
241             }
242 
243             key[i++] = *str++;
244 
245             if (i >= sizeof(key)) {
246                 /* won't have room for final '\0' */
247                 return;
248             }
249         }
250 
251         if (*str != '=') {
252             /* no value to collect */
253             continue;
254         }
255 	str++;
256 
257         /* collect the value */
258         i = 0;
259         for (;;) {
260             if (*str == 0 || *str == '\n' || (split_on_blanks && *str == ' ')) {
261                 /* we are done with the value */
262                 value[i] = 0;
263                 put(d, key, value);
264                 break;
265             }
266 
267             value[i++] = *str++;
268 
269             if (i >= sizeof(value)) {
270                 /* won't have room for final '\0' */
271                 return;
272             }
273         }
274     }
275 }
276