GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / saslauthd / cfile.c
1 /* Simple Config file API
2  * Dave Eckhardt
3  * Rob Siemborski
4  * Tim Martin (originally in Cyrus distribution)
5  * $Id: cfile.c,v 1.1 2005/01/19 00:11:41 shadow Exp $
6  */
7 /* 
8  * Copyright (c) 2001 Carnegie Mellon University.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer. 
16  *
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
20  *    distribution.
21  *
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
28  *      5000 Forbes Avenue
29  *      Pittsburgh, PA  15213-3890
30  *      (412) 268-4387, fax: (412) 268-7395
31  *      tech-transfer@andrew.cmu.edu
32  *
33  * 4. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by Computing Services
36  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37  *
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.
45  */
46
47 /* cfile_read() has a clumsy error reporting path
48  * so that it doesn't depend on any particular package's
49  * return code space.
50  */
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <ctype.h>
56
57 #include "cfile.h"
58
59 struct cf_keyval {
60     char *key;
61     char *value;
62 };
63
64 struct cfile {
65     struct cf_keyval *kvlist;
66     int n_kv;
67 };
68
69 #define CONFIGLISTGROWSIZE 100
70 #define BIG_ENOUGH 4096
71
72 cfile cfile_read(const char *filename, char *complaint, int complaint_len)
73 {
74     FILE *infile;
75     int lineno = 0;
76     int alloced = 0;
77     char buf[BIG_ENOUGH];
78     char *p, *key;
79     int result;
80     struct cfile *cf;
81
82         if (complaint)
83       complaint[0] = '\0';
84
85     if (!(cf = malloc(sizeof (*cf)))) {
86       /* then strdup() will probably fail, sigh */
87       if (complaint)
88         snprintf(complaint, complaint_len, "cfile_read: no memory");
89       return 0;
90     }
91
92     cf->n_kv = 0;
93     cf->kvlist = 0;
94
95     infile = fopen(filename, "r");
96     if (!infile) {
97       if (complaint)
98         snprintf(complaint, complaint_len, "cfile_read: cannot open %s", filename);
99       cfile_free(cf);
100       return 0;
101     }
102     
103     while (fgets(buf, sizeof(buf), infile)) {
104         lineno++;
105
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;
109
110         key = p;
111         while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
112             if (isupper((int) *p)) *p = tolower(*p);
113             p++;
114         }
115         if (*p != ':') {
116           if (complaint)
117             snprintf(complaint, complaint_len, "%s: line %d: no colon separator", filename, lineno);
118           cfile_free(cf);
119           return 0;
120         }
121         *p++ = '\0';
122
123         while (*p && isspace((int) *p)) p++;
124         
125         if (!*p) {
126           if (complaint)
127             snprintf(complaint, complaint_len, "%s: line %d: keyword %s: no value", filename, lineno, key);
128           cfile_free(cf);
129           return 0;
130         }
131
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) {
137               if (complaint)
138                 snprintf(complaint, complaint_len, "cfile_read: no memory");
139               cfile_free(cf);
140               return 0;
141             }
142         }
143
144         if (!(cf->kvlist[cf->n_kv].key = strdup(key)) ||
145             !(cf->kvlist[cf->n_kv].value = strdup(p))) {
146               if (complaint)
147                 snprintf(complaint, complaint_len, "cfile_read: no memory");
148               cf->n_kv++; /* maybe one strdup() worked */
149               cfile_free(cf);
150               return 0;
151         }
152
153         cf->n_kv++;
154     }
155     fclose(infile);
156
157     return cf;
158 }
159
160 const char *cfile_getstring(cfile cf,const char *key,const char *def)
161 {
162     int opt;
163
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;
168     }
169     return def;
170 }
171
172 int cfile_getint(cfile cf,const char *key,int def)
173 {
174     const char *val = cfile_getstring(cf, key, (char *)0);
175
176     if (!val) return def;
177     if (!isdigit((int) *val) && (*val != '-' || !isdigit((int) val[1]))) return def;
178     return atoi(val);
179 }
180
181 int cfile_getswitch(cfile cf,const char *key,int def)
182 {
183     const char *val = cfile_getstring(cf, key, (char *)0);
184
185     if (!val) return def;
186
187     if (*val == '0' || *val == 'n' ||
188         (*val == 'o' && val[1] == 'f') || *val == 'f') {
189         return 0;
190     }
191     else if (*val == '1' || *val == 'y' ||
192              (*val == 'o' && val[1] == 'n') || *val == 't') {
193         return 1;
194     }
195     return def;
196 }
197
198 void cfile_free(cfile cf)
199 {
200     int opt;
201
202     if (cf->kvlist) {
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);
208         }
209         free(cf->kvlist);
210     }
211     free(cf);
212 }