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>
30 #include "utils_fbhash.h"
31 #include "utils_avltree.h"
45 static void fbh_free_tree (c_avl_tree_t *tree) /* {{{ */
57 status = c_avl_pick (tree, (void *) &key, (void *) &value);
66 } /* }}} void fbh_free_tree */
68 static int fbh_read_file (fbhash_t *h) /* {{{ */
72 struct flock fl = { 0 };
76 fh = fopen (h->filename, "r");
81 fl.l_whence = SEEK_SET;
82 /* TODO: Lock file? -> fcntl */
84 status = fcntl (fileno (fh), F_SETLK, &fl);
91 tree = c_avl_create ((int (*) (const void *, const void *)) strcmp);
98 /* Read `fh' into `tree' */
99 while (fgets (buffer, sizeof (buffer), fh) != NULL) /* {{{ */
108 buffer[sizeof (buffer) - 1] = 0;
109 len = strlen (buffer);
111 /* Remove trailing newline characters. */
113 && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r')))
119 /* Seek first non-space character */
121 while ((*key != 0) && isspace ((int) *key))
124 /* Skip empty lines and comments */
125 if ((key[0] == 0) || (key[0] == '#'))
128 /* Seek first colon */
129 value = strchr (key, ':');
133 /* Null-terminate `key'. */
137 /* Skip leading whitespace */
138 while ((*value != 0) && isspace ((int) *value))
141 /* Skip lines without value */
145 key_copy = strdup (key);
146 value_copy = strdup (value);
148 if ((key_copy == NULL) || (value_copy == NULL))
155 status = c_avl_insert (tree, key_copy, value_copy);
163 DEBUG ("utils_fbhash: fbh_read_file: key = %s; value = %s;",
165 } /* }}} while (fgets) */
169 fbh_free_tree (h->tree);
173 } /* }}} int fbh_read_file */
175 static int fbh_check_file (fbhash_t *h) /* {{{ */
177 struct stat statbuf = { 0 };
180 status = stat (h->filename, &statbuf);
184 if (h->mtime >= statbuf.st_mtime)
187 status = fbh_read_file (h);
189 h->mtime = statbuf.st_mtime;
192 } /* }}} int fbh_check_file */
197 fbhash_t *fbh_create (const char *file) /* {{{ */
205 h = calloc (1, sizeof (*h));
209 h->filename = strdup (file);
210 if (h->filename == NULL)
217 pthread_mutex_init (&h->lock, /* attr = */ NULL);
219 status = fbh_check_file (h);
228 } /* }}} fbhash_t *fbh_create */
230 void fbh_destroy (fbhash_t *h) /* {{{ */
235 pthread_mutex_destroy (&h->lock);
237 fbh_free_tree (h->tree);
238 } /* }}} void fbh_destroy */
240 char *fbh_get (fbhash_t *h, const char *key) /* {{{ */
246 if ((h == NULL) || (key == NULL))
252 pthread_mutex_lock (&h->lock);
254 /* TODO: Checking this every time may be a bit much..? */
257 status = c_avl_get (h->tree, key, (void *) &value);
260 assert (value != NULL);
261 value_copy = strdup (value);
264 pthread_mutex_unlock (&h->lock);
267 } /* }}} char *fbh_get */
269 /* vim: set sw=2 sts=2 et fdm=marker : */