]> gitweb.fperrin.net Git - iftop.git/blob - cfgfile.c
gitignore
[iftop.git] / cfgfile.c
1 /*
2  * cfgfile.c:
3  *
4  * Copyright (c) 2003 DecisionSoft Ltd.
5  *
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <stdlib.h>
12
13 #include "stringmap.h"
14 #include "iftop.h"
15 #include "options.h"
16 #include "cfgfile.h"
17
18 #define CONFIG_TYPE_STRING 0
19 #define CONFIG_TYPE_BOOL   1
20 #define CONFIG_TYPE_INT    2
21
22 #define MAX_CONFIG_LINE     2048
23
24 char * config_directives[] = {
25         "interface", 
26         "dns-resolution",
27         "port-resolution",
28         "filter-code",
29         "show-bars", 
30         "promiscuous",
31         "hide-source",
32         "hide-destination",
33         "use-bytes",
34         "bandwidth-unit",
35         "sort", 
36         "line-display", 
37         "show-totals", 
38         "log-scale", 
39         "max-bandwidth",
40         "net-filter", 
41         "net-filter6", 
42         "link-local",
43         "port-display", 
44         "timed-output",
45         "no-curses",
46         "num-lines",
47         NULL
48 };
49
50 stringmap config;
51
52 extern options_t options ;
53
54 int is_cfgdirective_valid(const char *s) {
55     int t;
56     for (t = 0; config_directives[t] != NULL; t++)
57        if (strcmp(s, config_directives[t]) == 0) return 1;
58     return 0;
59 }
60
61 int config_init() {
62     config = stringmap_new();
63     return config != NULL;
64 }
65
66 /* read_config_file:
67  * Read a configuration file consisting of key: value tuples, returning a
68  * stringmap of the results. Prints errors to stderr, rather than using
69  * syslog, since this file is called at program startup. Returns 1 on success
70  * or 0 on failure. */
71 int read_config_file(const char *f, int whinge) {
72     int ret = 0;
73     FILE *fp;
74     char *line;
75     int i = 1;
76
77     line = xmalloc(MAX_CONFIG_LINE);
78
79     fp = fopen(f, "rt");
80     if (!fp) {
81         if(whinge) fprintf(stderr, "%s: %s\n", f, strerror(errno)); 
82         goto fail;
83     }
84
85     while (fgets(line, MAX_CONFIG_LINE, fp)) {
86         char *key, *value, *r;
87
88         for (r = line + strlen(line) - 1; r > line && *r == '\n'; *(r--) = 0);
89
90         /* Get continuation lines. Ugly. */
91         while (*(line + strlen(line) - 1) == '\\') {
92             if (!fgets(line + strlen(line) - 1, MAX_CONFIG_LINE - strlen(line), fp))
93                 break;
94             for (r = line + strlen(line) - 1; r > line && *r == '\n'; *(r--) = 0);
95         }
96
97         /* Strip comment. */
98         key = strpbrk(line, "#\n");
99         if (key) *key = 0;
100
101         /*    foo  : bar baz quux
102          * key^    ^value          */
103         key = line + strspn(line, " \t");
104         value = strchr(line, ':');
105
106         if (value) {
107             /*    foo  : bar baz quux
108              * key^  ^r ^value         */
109             ++value;
110
111             r = key + strcspn(key, " \t:");
112             if (r != key) {
113                 item *I;
114                 *r = 0;
115
116                 /*    foo\0: bar baz quux
117                  * key^      ^value      ^r */
118                 value += strspn(value, " \t");
119                 r = value + strlen(value) - 1;
120                 while (strchr(" \t", *r) && r > value) --r;
121                 *(r + 1) = 0;
122
123                 /* (Removed check for zero length value.) */
124
125                 /* Check that this is a valid key. */
126                 if (!is_cfgdirective_valid(key))
127                     fprintf(stderr, "%s:%d: warning: unknown directive \"%s\"\n", f, i, key);
128                 else if ((I = stringmap_insert(config, key, item_ptr(xstrdup(value)))))
129                     /* Don't warn of repeated directives, because they
130                      * may have been specified via the command line
131                      * Previous option takes precedence.
132                      */
133                     fprintf(stderr, "%s:%d: warning: repeated directive \"%s\"\n", f, i, key);
134             }
135         }
136
137         memset(line, 0, MAX_CONFIG_LINE); /* security paranoia */
138
139         ++i;
140     }
141
142     ret = 1;
143
144 fail:
145     if (fp) fclose(fp);
146     if (line) xfree(line);
147
148     return ret;
149 }
150
151 int config_get_int(const char *directive, int *value) {
152     stringmap S;
153     char *s, *t;
154
155     if (!value) return -1;
156
157     S = stringmap_find(config, directive);
158     if (!S) return 0;
159
160     s = (char*)S->d.v;
161     if (!*s) return -1;
162     errno = 0;
163     *value = strtol(s, &t, 10);
164     if (*t) return -1;
165
166     return errno == ERANGE ? -1 : 1;
167 }
168
169 /* config_get_float:
170  * Get an integer value from a config string. Returns 1 on success, -1 on
171  * failure, or 0 if no value was found. */
172 int config_get_float(const char *directive, float *value) {
173     stringmap S;
174     char *s, *t;
175
176     if (!value) return -1;
177
178     if (!(S = stringmap_find(config, directive)))
179         return 0;
180
181     s = (char*)S->d.v;
182     if (!*s) return -1;
183     errno = 0;
184     *value = strtod(s, &t);
185     if (*t) return -1;
186
187     return errno == ERANGE ? -1 : 1;
188 }
189
190 /* config_get_string;
191  * Get a string value from the config file. Returns NULL if it is not
192  * present. */
193 char *config_get_string(const char *directive) {
194     stringmap S;
195
196     S = stringmap_find(config, directive);
197     if (S) return (char*)S->d.v;
198     else return NULL;
199 }
200
201 /* config_get_bool:
202  * Get a boolean value from the config file. Returns false if not present. */
203 int config_get_bool(const char *directive) {
204     char *s;
205
206     s = config_get_string(directive);
207     if (s && (strcmp(s, "yes") == 0 || strcmp(s, "true") == 0))
208         return 1;
209     else
210         return 0;
211 }
212
213 /* config_get_enum:
214  * Get an enumeration value from the config file. Returns false if not 
215  * present or an invalid value is found. */
216 int config_get_enum(const char *directive, config_enumeration_type *enumeration, int *value) {
217     char *s;
218     config_enumeration_type *t;
219     s = config_get_string(directive);
220     if(s) {
221         for(t = enumeration; t->name; t++) {
222             if(strcmp(s,t->name) == 0) {
223                 *value = t->value;
224                 return 1;
225             }
226         }
227         fprintf(stderr,"Invalid enumeration value \"%s\" for directive \"%s\"\n", s, directive);
228     }
229     return 0;
230 }
231
232 /* config_set_string; Sets a value in the config, possibly overriding
233  * an existing value
234  */
235 void config_set_string(const char *directive, const char* s) {
236     stringmap S;
237
238     S = stringmap_find(config, directive);
239     if (S) {
240       xfree(S->d.v);
241       S->d = item_ptr(xstrdup(s));
242     }
243     else {
244       stringmap_insert(config, directive, item_ptr(xstrdup(s)));
245     }
246 }
247
248 int read_config(char *file, int whinge_on_error) {
249     return read_config_file(file, whinge_on_error);
250 }