PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/inlaprog/src/dictionary.c

https://code.google.com/p/inla/
C | 590 lines | 331 code | 72 blank | 187 comment | 94 complexity | 1ceb6a48295c4f0152161f5b9d74d298 MD5 | raw file
  1. /**
  2. @file dictionary.c
  3. @author N. Devillard
  4. @date Aug 2000
  5. @version $Revision: 1.30 $
  6. @brief Implements a dictionary for string variables.
  7. This module implements a simple dictionary object, i.e. a list of string/string associations.
  8. This object is useful to store e.g. informations retrieved from a
  9. configuration file (ini files). */
  10. /*
  11. $Id: dictionary.c,v 1.30 2009/03/30 16:47:04 hrue Exp $
  12. $Author: hrue $
  13. $Date: 2009/03/30 16:47:04 $
  14. $Revision: 1.30 $
  15. */
  16. #include "dictionary.h"
  17. #include "iniparser.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include "strlib.h"
  23. #include "my-fix.h"
  24. #include "GMRFLib/GMRFLib.h"
  25. /** Maximum value size for integers and doubles. */
  26. #define MAXVALSZ 1024
  27. /** Minimal allocated number of entries in a dictionary */
  28. #define DICTMINSZ 512
  29. /** Invalid key token */
  30. #define DICT_INVALID_KEY ((char*)-1)
  31. static void *mem_double(void *ptr, int size)
  32. {
  33. void *newptr = NULL;
  34. newptr = calloc((size_t) (2 * size), 1);
  35. memcpy(newptr, ptr, (size_t) size);
  36. free(ptr);
  37. return newptr;
  38. }
  39. /**
  40. @brief Compute the hash key for a string.
  41. @param key Character string to use for key.
  42. @return 1 unsigned int on at least 32 bits.
  43. This hash function has been taken from an Article in Dr Dobbs Journal.
  44. This is normally a collision-free function, distributing keys evenly.
  45. The key is stored anyway in the struct so that collision can be avoided
  46. by comparing the key itself in last resort.
  47. */
  48. unsigned dictionary_hash(char *key)
  49. {
  50. unsigned hash;
  51. size_t i, len;
  52. len = strlen(key);
  53. for (hash = 0, i = 0; i < len; i++) {
  54. hash += (unsigned) key[i];
  55. hash += (hash << 10);
  56. hash ^= (hash >> 6);
  57. }
  58. hash += (hash << 3);
  59. hash ^= (hash >> 11);
  60. hash += (hash << 15);
  61. return hash;
  62. }
  63. /**
  64. @brief Create a new dictionary object.
  65. @param size Optional initial size of the dictionary.
  66. @return 1 newly allocated dictionary objet.
  67. This function allocates a new dictionary object of given size and returns
  68. it. If you do not know in advance (roughly) the number of entries in the
  69. dictionary, give size=0.
  70. */
  71. dictionary *dictionary_new(int size)
  72. {
  73. int i;
  74. dictionary *d = NULL;
  75. /*
  76. * If no size was specified, allocate space for DICTMINSZ
  77. */
  78. if (size < DICTMINSZ)
  79. size = DICTMINSZ;
  80. if (!(d = (dictionary *) calloc(1, sizeof(dictionary)))) {
  81. return NULL;
  82. }
  83. d->size = size;
  84. d->used = (char *) calloc((size_t) size, sizeof(char));
  85. d->val = (char **) calloc((size_t) size, sizeof(char *));
  86. d->key = (char **) calloc((size_t) size, sizeof(char *));
  87. map_stri_init_hint(&(d->strihash), (size_t) size);
  88. map_ii_init_hint(&(d->iihash), (size_t) size);
  89. for (i = 0; i < size; i++) {
  90. map_ii_set(&(d->iihash), i, 1);
  91. }
  92. return d;
  93. }
  94. /**
  95. @brief Delete a dictionary object
  96. @param d dictionary object to deallocate.
  97. @return void
  98. Deallocate a dictionary object and all memory associated to it.
  99. */
  100. void dictionary_del(dictionary * d)
  101. {
  102. int i;
  103. if (d == NULL)
  104. return;
  105. for (i = 0; i < d->size; i++) {
  106. if (d->key[i] != NULL)
  107. free(d->key[i]);
  108. if (d->val[i] != NULL)
  109. free(d->val[i]);
  110. }
  111. free(d->val);
  112. free(d->key);
  113. free(d->used);
  114. map_stri_free(&(d->strihash));
  115. map_ii_free(&(d->iihash));
  116. free(d);
  117. return;
  118. }
  119. /**
  120. @brief Get a value from a dictionary.
  121. @param d dictionary object to search.
  122. @param key Key to look for in the dictionary.
  123. @param def Default value to return if key not found.
  124. @return 1 pointer to internally allocated character string.
  125. This function locates a key in a dictionary and returns a pointer to its
  126. value, or the passed 'def' pointer if no such key can be found in
  127. dictionary. The returned character pointer points to data internal to the
  128. dictionary object, you should not try to free it or modify it.
  129. */
  130. char *dictionary_get(dictionary * d, char *key, char *def)
  131. {
  132. int i, *ip;
  133. ip = map_stri_ptr(&(d->strihash), key);
  134. if (ip) {
  135. i = *ip;
  136. d->used[i] = 1;
  137. return dictionary_replace_variables(d, d->val[i]);
  138. } else {
  139. return dictionary_replace_variables(d, def);
  140. }
  141. }
  142. /**
  143. @brief Get a value from a dictionary, as a char.
  144. @param d dictionary object to search.
  145. @param key Key to look for in the dictionary.
  146. @param def Default value for the key if not found.
  147. @return char
  148. This function locates a key in a dictionary using dictionary_get,
  149. and returns the first char of the found string.
  150. */
  151. char dictionary_getchar(dictionary * d, char *key, char def)
  152. {
  153. char *v = NULL;
  154. if ((v = dictionary_get(d, key, DICT_INVALID_KEY)) == DICT_INVALID_KEY) {
  155. return def;
  156. } else {
  157. return v[0];
  158. }
  159. }
  160. /**
  161. @brief Get a value from a dictionary, as an int.
  162. @param d dictionary object to search.
  163. @param key Key to look for in the dictionary.
  164. @param def Default value for the key if not found.
  165. @return int
  166. This function locates a key in a dictionary using dictionary_get,
  167. and applies atoi on it to return an int. If the value cannot be found
  168. in the dictionary, the default is returned.
  169. */
  170. int dictionary_getint(dictionary * d, char *key, int def)
  171. {
  172. char *v = NULL;
  173. if ((v = dictionary_get(d, key, DICT_INVALID_KEY)) == DICT_INVALID_KEY) {
  174. return def;
  175. } else {
  176. return atoi(v);
  177. }
  178. }
  179. /**
  180. @brief Get a value from a dictionary, as a double.
  181. @param d dictionary object to search.
  182. @param key Key to look for in the dictionary.
  183. @param def Default value for the key if not found.
  184. @return double
  185. This function locates a key in a dictionary using dictionary_get,
  186. and applies atof on it to return a double. If the value cannot be found
  187. in the dictionary, the default is returned.
  188. */
  189. double dictionary_getdouble(dictionary * d, char *key, double def)
  190. {
  191. char *v = NULL;
  192. if ((v = dictionary_get(d, key, DICT_INVALID_KEY)) == DICT_INVALID_KEY) {
  193. return def;
  194. } else {
  195. return atof(v);
  196. }
  197. }
  198. /**
  199. @brief Set a value in a dictionary.
  200. @param d dictionary object to modify.
  201. @param key Key to modify or add.
  202. @param val Value to add.
  203. @return void
  204. If the given key is found in the dictionary, the associated value is
  205. replaced by the provided one. If the key cannot be found in the
  206. dictionary, it is added to it.
  207. It is Ok to provide a NULL value for val, but NULL values for the dictionary
  208. or the key are considered as errors: the function will return immediately
  209. in such a case.
  210. Notice that if you dictionary_set a variable to NULL, a call to
  211. dictionary_get will return a NULL value: the variable will be found, and
  212. its value (NULL) is returned. In other words, setting the variable
  213. content to NULL is equivalent to deleting the variable from the
  214. dictionary. It is not possible (in this implementation) to have a key in
  215. the dictionary without value.
  216. */
  217. void dictionary_set(dictionary * d, char *key, char *val)
  218. {
  219. int i = 0, *ip = NULL;
  220. if (d == NULL || key == NULL)
  221. return;
  222. ip = map_stri_ptr(&(d->strihash), key);
  223. if (ip) {
  224. i = *ip;
  225. /*
  226. * Found a value: modify and return
  227. */
  228. if (d->val[i] != NULL)
  229. free(d->val[i]);
  230. d->val[i] = val ? strdup(val) : NULL;
  231. map_stri_set(&(d->strihash), d->val[i], 1);
  232. } else {
  233. /*
  234. * Add a new value
  235. */
  236. /*
  237. * See if dictionary needs to grow
  238. */
  239. if (d->n == d->size) {
  240. /*
  241. * Reached maximum size: reallocate blackboard
  242. */
  243. d->used = (char *) mem_double(d->used, (int) (d->size * sizeof(char)));
  244. d->val = (char **) mem_double(d->val, (int) (d->size * sizeof(char *)));
  245. d->key = (char **) mem_double(d->key, (int) (d->size * sizeof(char *)));
  246. for (i = d->size; i < 2 * d->size; i++)
  247. map_ii_set(&(d->iihash), i, 1);
  248. d->size *= 2;
  249. }
  250. int j;
  251. for (j = -1; (j = (int) map_ii_next(&(d->iihash), j)) != -1;) {
  252. i = d->iihash.contents[j].key;
  253. break;
  254. }
  255. assert(d->key[i] == NULL);
  256. if (0) {
  257. /*
  258. * Insert key in the first empty slot
  259. */
  260. for (i = 0; i < d->size; i++) {
  261. if (d->key[i] == NULL) {
  262. /*
  263. * Add key here
  264. */
  265. break;
  266. }
  267. }
  268. }
  269. /*
  270. * Copy key
  271. */
  272. d->key[i] = strdup(key);
  273. d->val[i] = val ? strdup(val) : NULL;
  274. d->used[i] = 0;
  275. map_stri_set(&(d->strihash), d->key[i], i);
  276. map_ii_remove(&(d->iihash), i);
  277. d->n++;
  278. }
  279. return;
  280. }
  281. /**
  282. @brief Delete a key in a dictionary
  283. @param d dictionary object to modify.
  284. @param key Key to remove.
  285. @return void
  286. This function deletes a key in a dictionary. Nothing is done if the
  287. key cannot be found.
  288. */
  289. void dictionary_unset(dictionary * d, char *key)
  290. {
  291. int i, *ip;
  292. if (key == NULL) {
  293. return;
  294. }
  295. ip = map_stri_ptr(&(d->strihash), key);
  296. if (!ip)
  297. return;
  298. map_stri_remove(&(d->strihash), key);
  299. i = *ip;
  300. map_ii_set(&(d->iihash), i, 1);
  301. free(d->key[i]);
  302. d->key[i] = NULL;
  303. if (d->val[i] != NULL) {
  304. free(d->val[i]);
  305. d->val[i] = NULL;
  306. }
  307. d->used[i] = 0;
  308. d->n--;
  309. return;
  310. }
  311. /**
  312. @brief Set a key in a dictionary, providing an int.
  313. @param d Dictionary to update.
  314. @param key Key to modify or add
  315. @param val Integer value to store (will be stored as a string).
  316. @return void
  317. This helper function calls dictionary_set() with the provided integer
  318. converted to a string using %d.
  319. */
  320. void dictionary_setint(dictionary * d, char *key, int val)
  321. {
  322. char sval[MAXVALSZ];
  323. sprintf(sval, "%d", val);
  324. dictionary_set(d, key, sval);
  325. }
  326. /**
  327. @brief Set a key in a dictionary, providing a double.
  328. @param d Dictionary to update.
  329. @param key Key to modify or add
  330. @param val Double value to store (will be stored as a string).
  331. @return void
  332. This helper function calls dictionary_set() with the provided double
  333. converted to a string using %g.
  334. */
  335. void dictionary_setdouble(dictionary * d, char *key, double val)
  336. {
  337. char sval[MAXVALSZ];
  338. sprintf(sval, "%g", val);
  339. dictionary_set(d, key, sval);
  340. }
  341. /**
  342. @brief Dump a dictionary to an opened file pointer.
  343. @param d Dictionary to dump
  344. @param f Opened file pointer.
  345. @return void
  346. Dumps a dictionary onto an opened file pointer. Key pairs are printed out
  347. as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
  348. output file pointers.
  349. */
  350. void dictionary_dump(dictionary * d, FILE * out)
  351. {
  352. int i;
  353. if (d == NULL || out == NULL)
  354. return;
  355. if (d->n < 1) {
  356. fprintf(out, "empty dictionary\n");
  357. return;
  358. }
  359. for (i = 0; i < d->size; i++) {
  360. if (d->key[i]) {
  361. fprintf(out, "%20s\t[%s]\n", d->key[i], d->val[i] ? d->val[i] : "NULL");
  362. }
  363. }
  364. return;
  365. }
  366. char *dictionary_replace_variables(dictionary * d, char *str)
  367. {
  368. /*
  369. * variable-replacement! added by hrue@math.ntnu.no
  370. */
  371. if (!str || str == DICT_INVALID_KEY) {
  372. return str;
  373. }
  374. char *first = NULL, *last = NULL, *newstr = NULL, *envvar = NULL, *var = NULL, *newvar = NULL;
  375. int c, debug = 0;
  376. size_t len;
  377. int i;
  378. if (debug) {
  379. printf("ENTER with string = [%s] strlen=%1lu\n", str, (unsigned long) strlen(str));
  380. }
  381. first = strchr(str, '$');
  382. if (!first) {
  383. return str;
  384. }
  385. last = first + 1;
  386. c = *last;
  387. while (*last && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
  388. c = *++last;
  389. }
  390. len = last - first;
  391. if (debug) {
  392. printf("first %s\n", first);
  393. printf("last %s\n", last);
  394. }
  395. var = (char *) calloc(len + 1, sizeof(char));
  396. var[0] = INIPARSER_SEP;
  397. strncpy(var + 1, first + 1, len);
  398. var[len] = '\0';
  399. if (debug) {
  400. printf("var is [%s]\n", var);
  401. }
  402. int *ip;
  403. ip = map_stri_ptr(&(d->strihash), var);
  404. if (ip) {
  405. i = *ip;
  406. if (debug) {
  407. printf("replace [%s] with [%s]\n", d->key[i], d->val[i]);
  408. }
  409. *first = '\0';
  410. GMRFLib_sprintf(&newstr, "%s%s%s", str, d->val[i], last);
  411. if (debug) {
  412. printf("new string [%s]\n", newstr);
  413. }
  414. return dictionary_replace_variables(d, newstr);
  415. } else {
  416. if (debug)
  417. printf("var not in strhash...\n");
  418. }
  419. if (debug) {
  420. printf("ask for envvar [%s]\n", &var[1]);
  421. }
  422. GMRFLib_sprintf(&newvar, "inla_%s", &var[1]);
  423. envvar = getenv(newvar);
  424. if (envvar) {
  425. *first = '\0';
  426. GMRFLib_sprintf(&newstr, "%s%s%s", str, envvar, last);
  427. if (debug) {
  428. printf("new string [%s]\n", newstr);
  429. }
  430. return dictionary_replace_variables(d, newstr);
  431. } else {
  432. if (debug)
  433. printf("getenv(%s) returns NULL\n", newvar);
  434. }
  435. return str;
  436. }
  437. int dictionary_dump_unused(dictionary * d, FILE * out)
  438. {
  439. /*
  440. * dump unused entries, added by hrue@math.ntnu.no
  441. */
  442. int i, count = 0, first = 1;
  443. if (d == NULL || out == NULL)
  444. return count;
  445. if (d->n < 1) {
  446. fprintf(out, "empty dictionary\n");
  447. return count;
  448. }
  449. for (i = 0; i < d->size; i++) {
  450. if (d->key[i] && !d->used[i] && d->key[i][0] != INIPARSER_SEP && strchr(d->key[i], INIPARSER_SEP) != NULL) {
  451. if (first) {
  452. first = 0;
  453. fprintf(out, "\n\n");
  454. }
  455. fprintf(out, "\tUnused entry [%s]=[%s]\n", d->key[i], d->val[i] ? d->val[i] : "NULL");
  456. count++;
  457. }
  458. }
  459. return count;
  460. }
  461. /* Example code */
  462. #ifdef TESTDIC
  463. #define NVALS 20000
  464. int main(int argc, char *argv[])
  465. {
  466. dictionary *d = NULL;
  467. char *val = NULL;
  468. int i;
  469. char cval[90];
  470. /*
  471. * allocate blackboard
  472. */
  473. printf("allocating...\n");
  474. d = dictionary_new(0);
  475. /*
  476. * Set values in blackboard
  477. */
  478. printf("setting %d values...\n", NVALS);
  479. for (i = 0; i < NVALS; i++) {
  480. sprintf(cval, "%04d", i);
  481. dictionary_set(d, cval, "salut");
  482. }
  483. printf("getting %d values...\n", NVALS);
  484. for (i = 0; i < NVALS; i++) {
  485. sprintf(cval, "%04d", i);
  486. val = dictionary_get(d, cval, DICT_INVALID_KEY);
  487. if (val == DICT_INVALID_KEY) {
  488. printf("cannot get value for key [%s]\n", cval);
  489. }
  490. }
  491. printf("unsetting %d values...\n", NVALS);
  492. for (i = 0; i < NVALS; i++) {
  493. sprintf(cval, "%04d", i);
  494. dictionary_unset(d, cval);
  495. }
  496. if (d->n != 0) {
  497. printf("error deleting values\n");
  498. }
  499. printf("deallocating...\n");
  500. dictionary_del(d);
  501. return 0;
  502. }
  503. #endif