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