2 * collectd - src/utils_fbhash.c
3 * Copyright (C) 2009 Florian octo Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Florian octo Forster <octo at collectd.org>
31 #include "utils_avltree.h"
32 #include "utils_fbhash.h"
45 static void fbh_free_tree(c_avl_tree_t *tree) /* {{{ */
56 status = c_avl_pick(tree, (void *)&key, (void *)&value);
65 } /* }}} void fbh_free_tree */
67 static int fbh_read_file(fbhash_t *h) /* {{{ */
71 struct flock fl = {0};
75 fh = fopen(h->filename, "r");
80 fl.l_whence = SEEK_SET;
81 /* TODO: Lock file? -> fcntl */
83 status = fcntl(fileno(fh), F_SETLK, &fl);
89 tree = c_avl_create((int (*)(const void *, const void *))strcmp);
95 /* Read `fh' into `tree' */
96 while (fgets(buffer, sizeof(buffer), fh) != NULL) /* {{{ */
105 buffer[sizeof(buffer) - 1] = 0;
106 len = strlen(buffer);
108 /* Remove trailing newline characters. */
110 ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r'))) {
115 /* Seek first non-space character */
117 while ((*key != 0) && isspace((int)*key))
120 /* Skip empty lines and comments */
121 if ((key[0] == 0) || (key[0] == '#'))
124 /* Seek first colon */
125 value = strchr(key, ':');
129 /* Null-terminate `key'. */
133 /* Skip leading whitespace */
134 while ((*value != 0) && isspace((int)*value))
137 /* Skip lines without value */
141 key_copy = strdup(key);
142 value_copy = strdup(value);
144 if ((key_copy == NULL) || (value_copy == NULL)) {
150 status = c_avl_insert(tree, key_copy, value_copy);
157 DEBUG("utils_fbhash: fbh_read_file: key = %s; value = %s;", key, value);
158 } /* }}} while (fgets) */
162 fbh_free_tree(h->tree);
166 } /* }}} int fbh_read_file */
168 static int fbh_check_file(fbhash_t *h) /* {{{ */
170 struct stat statbuf = {0};
173 status = stat(h->filename, &statbuf);
177 if (h->mtime >= statbuf.st_mtime)
180 status = fbh_read_file(h);
182 h->mtime = statbuf.st_mtime;
185 } /* }}} int fbh_check_file */
190 fbhash_t *fbh_create(const char *file) /* {{{ */
198 h = calloc(1, sizeof(*h));
202 h->filename = strdup(file);
203 if (h->filename == NULL) {
209 pthread_mutex_init(&h->lock, /* attr = */ NULL);
211 status = fbh_check_file(h);
219 } /* }}} fbhash_t *fbh_create */
221 void fbh_destroy(fbhash_t *h) /* {{{ */
226 pthread_mutex_destroy(&h->lock);
228 fbh_free_tree(h->tree);
229 } /* }}} void fbh_destroy */
231 char *fbh_get(fbhash_t *h, const char *key) /* {{{ */
237 if ((h == NULL) || (key == NULL))
243 pthread_mutex_lock(&h->lock);
245 /* TODO: Checking this every time may be a bit much..? */
248 status = c_avl_get(h->tree, key, (void *)&value);
250 assert(value != NULL);
251 value_copy = strdup(value);
254 pthread_mutex_unlock(&h->lock);
257 } /* }}} char *fbh_get */