1 /* Simple Config file API
4 * Tim Martin (originally in Cyrus distribution)
5 * $Id: cfile.c,v 1.1 2005/01/19 00:11:41 shadow Exp $
8 * Copyright (c) 2001 Carnegie Mellon University. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
22 * 3. The name "Carnegie Mellon University" must not be used to
23 * endorse or promote products derived from this software without
24 * prior written permission. For permission or any other legal
25 * details, please contact
26 * Office of Technology Transfer
27 * Carnegie Mellon University
29 * Pittsburgh, PA 15213-3890
30 * (412) 268-4387, fax: (412) 268-7395
31 * tech-transfer@andrew.cmu.edu
33 * 4. Redistributions of any form whatsoever must retain the following
35 * "This product includes software developed by Computing Services
36 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
38 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
39 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
40 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
41 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
42 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
43 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
44 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47 /* cfile_read() has a clumsy error reporting path
48 * so that it doesn't depend on any particular package's
65 struct cf_keyval *kvlist;
69 #define CONFIGLISTGROWSIZE 100
70 #define BIG_ENOUGH 4096
72 cfile cfile_read(const char *filename, char *complaint, int complaint_len)
85 if (!(cf = malloc(sizeof (*cf)))) {
86 /* then strdup() will probably fail, sigh */
88 snprintf(complaint, complaint_len, "cfile_read: no memory");
95 infile = fopen(filename, "r");
98 snprintf(complaint, complaint_len, "cfile_read: cannot open %s", filename);
103 while (fgets(buf, sizeof(buf), infile)) {
106 if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
107 for (p = buf; *p && isspace((int) *p); p++);
108 if (!*p || *p == '#') continue;
111 while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
112 if (isupper((int) *p)) *p = tolower(*p);
117 snprintf(complaint, complaint_len, "%s: line %d: no colon separator", filename, lineno);
123 while (*p && isspace((int) *p)) p++;
127 snprintf(complaint, complaint_len, "%s: line %d: keyword %s: no value", filename, lineno, key);
132 if (cf->n_kv == alloced) {
133 alloced += CONFIGLISTGROWSIZE;
134 cf->kvlist=realloc((char *)cf->kvlist,
135 alloced * sizeof(struct cf_keyval));
136 if (cf->kvlist==NULL) {
138 snprintf(complaint, complaint_len, "cfile_read: no memory");
144 if (!(cf->kvlist[cf->n_kv].key = strdup(key)) ||
145 !(cf->kvlist[cf->n_kv].value = strdup(p))) {
147 snprintf(complaint, complaint_len, "cfile_read: no memory");
148 cf->n_kv++; /* maybe one strdup() worked */
160 const char *cfile_getstring(cfile cf,const char *key,const char *def)
164 for (opt = 0; opt < cf->n_kv; opt++) {
165 if (*key == cf->kvlist[opt].key[0] &&
166 !strcmp(key, cf->kvlist[opt].key))
167 return cf->kvlist[opt].value;
172 int cfile_getint(cfile cf,const char *key,int def)
174 const char *val = cfile_getstring(cf, key, (char *)0);
176 if (!val) return def;
177 if (!isdigit((int) *val) && (*val != '-' || !isdigit((int) val[1]))) return def;
181 int cfile_getswitch(cfile cf,const char *key,int def)
183 const char *val = cfile_getstring(cf, key, (char *)0);
185 if (!val) return def;
187 if (*val == '0' || *val == 'n' ||
188 (*val == 'o' && val[1] == 'f') || *val == 'f') {
191 else if (*val == '1' || *val == 'y' ||
192 (*val == 'o' && val[1] == 'n') || *val == 't') {
198 void cfile_free(cfile cf)
203 for (opt = 0; opt < cf->n_kv; opt++) {
204 if (cf->kvlist[opt].key)
205 free(cf->kvlist[opt].key);
206 if (cf->kvlist[opt].value)
207 free(cf->kvlist[opt].value);