]> git.deb.at Git - pkg/abook.git/blob - options.c
e9885a98aa9b8e1d5b0e86e70aa60753f390027a
[pkg/abook.git] / options.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  *
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <assert.h>
16 #include "options.h"
17 #include "abook.h"
18 #include "misc.h"
19
20 #ifndef FALSE
21 #       define FALSE    0
22 #endif
23 #ifndef TRUE
24 #       define TRUE     1
25 #endif
26
27 #define UL      (unsigned long)
28
29 /*
30  * option types
31  */
32
33 enum opt_type {
34         OT_BOOL,
35         OT_STR,
36         OT_INT
37 };
38
39 struct option {
40         char *option;
41         enum opt_type type;
42         unsigned int data;
43         unsigned long init;
44 };
45
46 static struct option abook_vars[] = {
47         { "autosave", OT_BOOL, BOOL_AUTOSAVE, TRUE },
48
49         { "show_all_emails", OT_BOOL, BOOL_SHOW_ALL_EMAILS, TRUE },
50         { "emailpos", OT_INT, INT_EMAILPOS, 25 },
51         { "extra_column", OT_STR, STR_EXTRA_COLUMN, UL "phone" },
52         { "extra_alternative", OT_STR, STR_EXTRA_ALTERNATIVE, UL "-1" },
53         { "extrapos", OT_INT, INT_EXTRAPOS, 65 },
54
55         { "mutt_command", OT_STR, STR_MUTT_COMMAND, UL "mutt" },
56         { "mutt_return_all_emails", OT_BOOL, BOOL_MUTT_RETURN_ALL_EMAILS,
57                 TRUE },
58         
59         { "print_command", OT_STR, STR_PRINT_COMMAND, UL "lpr" },
60
61         { "www_command", OT_STR, STR_WWW_COMMAND, UL "lynx" },
62         
63         { "address_style", OT_STR, STR_ADDRESS_STYLE, UL "eu" },
64
65         { "use_ascii_only", OT_BOOL, BOOL_USE_ASCII_ONLY, FALSE },
66
67         { "add_email_prevent_duplicates", OT_BOOL, BOOL_ADD_EMAIL_PREVENT_DUPLICATES, FALSE },
68
69         { NULL }
70 };
71
72 static unsigned char bool_opts[BOOL_MAX];
73 static int int_opts[INT_MAXIMUM];
74 static char *str_opts[STR_MAX];
75
76 static void
77 set_int(enum int_opts opt, int value)
78 {
79         assert(opt >= 0 && opt < INT_MAXIMUM);
80
81         int_opts[opt] = value;
82 }
83
84 static void
85 set_bool(enum bool_opts opt, bool value)
86 {
87         assert(opt >= 0 && opt < BOOL_MAX);
88
89         bool_opts[opt] = value;
90 }
91
92 static void
93 set_str(enum str_opts opt, char *value)
94 {
95         assert(opt >= 0 && opt < STR_MAX);
96
97         if(str_opts[opt])
98                 free(str_opts[opt]);
99
100         str_opts[opt] = strdup(value);
101 }
102
103 int
104 opt_get_int(enum int_opts opt)
105 {
106         assert(opt >= 0 && opt < INT_MAXIMUM);
107
108         return int_opts[opt];
109 }
110
111 bool
112 opt_get_bool(enum bool_opts opt)
113 {
114         assert(opt >= 0 && opt < BOOL_MAX);
115
116         return bool_opts[opt];
117 }
118
119 char *
120 opt_get_str(enum str_opts opt)
121 {
122         assert(opt >= 0 && opt < STR_MAX);
123
124         return str_opts[opt];
125 }
126
127 static void
128 restore_default(struct option *p)
129 {
130         switch(p -> type) {
131                 case OT_BOOL:
132                         set_bool(p -> data, (bool)p -> init);
133                         break;
134                 case OT_INT:
135                         set_int(p -> data, (int)p -> init);
136                         break;
137                 case OT_STR:
138                         if(p -> init)
139                                 set_str(p -> data, (char *) p -> init);
140                         break;
141                 default:
142                         assert(0);
143         }
144 }
145
146 void
147 init_opts()
148 {
149         int i;
150
151         for(i = 0; abook_vars[i].option; i++)
152                 restore_default(&abook_vars[i]);
153 }
154
155 void
156 free_opts()
157 {
158         int i;
159
160         /*
161          * only strings need to be freed
162          */
163         for(i = 0; i < STR_MAX; i++) {
164                 free(str_opts[i]);
165                 str_opts[i] = NULL;
166         }
167 }
168
169 /*
170  * file parsing
171  */
172
173 typedef struct {
174         char *data, *ptr;
175 } buffer;
176
177 static void
178 opt_line_remove_comments(char *p)
179 {
180         bool in_quote = FALSE;
181         bool escape = FALSE;
182
183         assert(p != NULL);
184
185         for(; *p; p++) {
186                 switch(*p) {
187                         case '\"':
188                                 if(!escape) {
189                                         in_quote = !in_quote;
190                                         escape = FALSE;
191                                 }
192                                 break;
193                         case '\\':
194                                 escape = TRUE;
195                                 break;
196                         case '#':
197                                 if(!in_quote) {
198                                         *p = 0;
199                                         return;
200                                 }
201                         default:
202                                 escape = FALSE;
203                 }
204         }
205 }
206
207 void
208 find_token_start(buffer *b)
209 {
210         assert(b);
211         
212         for(; ISSPACE(*b -> ptr); b -> ptr ++);
213 }
214
215 void
216 find_token_end(buffer *b)
217 {
218         assert(b);
219
220         for(find_token_start(b); *(b -> ptr); b -> ptr ++) {
221                 if(ISSPACE(*(b -> ptr))) {
222                         break;
223                 }
224         }
225 }
226
227 static char *
228 opt_set_set_option(char *var, char *p, struct option *opt)
229 {
230         int len;
231         
232         strtrim(p);
233
234         len = strlen(p);
235
236         if(p[len - 1] == '\"' && *p == '\"') {
237                 if(len < 3)
238                         return "invalid value";
239                 p[len - 1] = 0;
240                 p++;
241         }
242
243         switch(opt -> type) {
244                 case OT_STR:
245                         set_str(opt -> data, p);
246                         break;
247                 case OT_INT:
248                         set_int(opt -> data, safe_atoi(p));
249                         break;
250                 case OT_BOOL:
251                         if(!strcasecmp(p, "true") || !strcasecmp(p, "on"))
252                                 set_bool(opt -> data, TRUE);
253                         else if(!strcasecmp(p, "false") ||
254                                         !strcasecmp(p, "off"))
255                                 set_bool(opt -> data, FALSE);
256                         else
257                                 return "invalid value";
258                         break;
259         }
260         
261         return NULL;
262 }
263
264 static char *
265 opt_parse_set(buffer *b)
266 {
267         int i;
268         char *p;
269
270         find_token_start(b);
271         if((p = strchr(b -> ptr, '=')))
272                 *p++ = 0;
273         else
274                 return "invalid value assignment";
275         
276         strtrim(b -> ptr);
277
278         for(i = 0;abook_vars[i].option; i++)
279                 if(!strcmp(abook_vars[i].option, b -> ptr))
280                         return opt_set_set_option(b -> ptr, p, &abook_vars[i]);
281         
282         return "unknown option";
283 }
284
285
286 static struct {
287         char *token;
288         char * (*func) (buffer *line);
289 } opt_parsers[] = {
290         { "set", opt_parse_set },
291         { NULL }
292 };
293
294 static bool
295 opt_parse_line(char *line, int n, char *fn)
296 {
297         int i;
298         char *err = NULL;
299         char *token;
300         buffer b;
301         
302         assert(line && fn);
303
304         b.ptr = line;
305
306         find_token_start(&b);
307         b.data = b.ptr;
308         find_token_end(&b);
309         *b.ptr++ = 0;
310
311         if(!*line)
312                 return FALSE;
313
314         strtrim(b.data);
315         strtrim(b.ptr);
316
317         token = b.data;
318         b.data = b.ptr = b.ptr;
319
320         for(i = 0; opt_parsers[i].token; i++)
321                 if(!strcmp(opt_parsers[i].token, token)) {
322                         if(!(err = opt_parsers[i].func(&b)))
323                                 return FALSE;
324                         break;
325                 }
326         
327         fprintf(stderr, "%s: parse error at line %d: ", fn, n);
328         if(err)
329                 fprintf(stderr, "%s\n", err);
330         else
331                 fprintf(stderr, "unknown token %s\n", token);
332
333         return TRUE;
334 }
335
336 int
337 load_opts(char *filename)
338 {
339         FILE *in;
340         char *line = NULL;
341         int n;
342         int err = 0;
343         
344         if((in = fopen(filename, "r")) == NULL)
345                 return -1;
346
347         
348         for(n = 1;!feof(in); n++) {
349                 line = getaline(in);
350
351                 if(feof(in))
352                         break;
353
354                 if(line && *line) {
355                         opt_line_remove_comments(line);
356                         if(*line)
357                                 err += opt_parse_line(line, n, filename) ? 1:0;
358                 }
359
360                 my_free(line);
361         }
362
363         free(line);
364
365         return err;
366 }
367