]> git.deb.at Git - pkg/abook.git/blob - options.c
mutt import filter changes
[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         { "sort_field", OT_STR, STR_SORT_FIELD, UL "nick" },
69
70         { NULL }
71 };
72
73 static unsigned char bool_opts[BOOL_MAX];
74 static int int_opts[INT_MAXIMUM];
75 static char *str_opts[STR_MAX];
76
77 static void
78 set_int(enum int_opts opt, int value)
79 {
80         assert(opt >= 0 && opt < INT_MAXIMUM);
81
82         int_opts[opt] = value;
83 }
84
85 static void
86 set_bool(enum bool_opts opt, bool value)
87 {
88         assert(opt >= 0 && opt < BOOL_MAX);
89
90         bool_opts[opt] = value;
91 }
92
93 static void
94 set_str(enum str_opts opt, char *value)
95 {
96         assert(opt >= 0 && opt < STR_MAX);
97
98         if(str_opts[opt])
99                 free(str_opts[opt]);
100
101         str_opts[opt] = strdup(value);
102 }
103
104 int
105 opt_get_int(enum int_opts opt)
106 {
107         assert(opt >= 0 && opt < INT_MAXIMUM);
108
109         return int_opts[opt];
110 }
111
112 bool
113 opt_get_bool(enum bool_opts opt)
114 {
115         assert(opt >= 0 && opt < BOOL_MAX);
116
117         return bool_opts[opt];
118 }
119
120 char *
121 opt_get_str(enum str_opts opt)
122 {
123         assert(opt >= 0 && opt < STR_MAX);
124
125         return str_opts[opt];
126 }
127
128 static void
129 restore_default(struct option *p)
130 {
131         switch(p -> type) {
132                 case OT_BOOL:
133                         set_bool(p -> data, (bool)p -> init);
134                         break;
135                 case OT_INT:
136                         set_int(p -> data, (int)p -> init);
137                         break;
138                 case OT_STR:
139                         if(p -> init)
140                                 set_str(p -> data, (char *) p -> init);
141                         break;
142                 default:
143                         assert(0);
144         }
145 }
146
147 void
148 init_opts()
149 {
150         int i;
151
152         for(i = 0; abook_vars[i].option; i++)
153                 restore_default(&abook_vars[i]);
154 }
155
156 void
157 free_opts()
158 {
159         int i;
160
161         /*
162          * only strings need to be freed
163          */
164         for(i = 0; i < STR_MAX; i++) {
165                 free(str_opts[i]);
166                 str_opts[i] = NULL;
167         }
168 }
169
170 /*
171  * file parsing
172  */
173
174 typedef struct {
175         char *data, *ptr;
176 } buffer;
177
178 static void
179 opt_line_remove_comments(char *p)
180 {
181         bool in_quote = FALSE;
182         bool escape = FALSE;
183
184         assert(p != NULL);
185
186         for(; *p; p++) {
187                 switch(*p) {
188                         case '\"':
189                                 if(!escape) {
190                                         in_quote = !in_quote;
191                                         escape = FALSE;
192                                 }
193                                 break;
194                         case '\\':
195                                 escape = TRUE;
196                                 break;
197                         case '#':
198                                 if(!in_quote) {
199                                         *p = 0;
200                                         return;
201                                 }
202                         default:
203                                 escape = FALSE;
204                 }
205         }
206 }
207
208 void
209 find_token_start(buffer *b)
210 {
211         assert(b);
212         
213         for(; ISSPACE(*b -> ptr); b -> ptr ++);
214 }
215
216 void
217 find_token_end(buffer *b)
218 {
219         assert(b);
220
221         for(find_token_start(b); *(b -> ptr); b -> ptr ++) {
222                 if(ISSPACE(*(b -> ptr))) {
223                         break;
224                 }
225         }
226 }
227
228 static char *
229 opt_set_set_option(char *var, char *p, struct option *opt)
230 {
231         int len;
232         
233         strtrim(p);
234
235         len = strlen(p);
236
237         if(p[len - 1] == '\"' && *p == '\"') {
238                 if(len < 3)
239                         return "invalid value";
240                 p[len - 1] = 0;
241                 p++;
242         }
243
244         switch(opt -> type) {
245                 case OT_STR:
246                         set_str(opt -> data, p);
247                         break;
248                 case OT_INT:
249                         set_int(opt -> data, safe_atoi(p));
250                         break;
251                 case OT_BOOL:
252                         if(!strcasecmp(p, "true") || !strcasecmp(p, "on"))
253                                 set_bool(opt -> data, TRUE);
254                         else if(!strcasecmp(p, "false") ||
255                                         !strcasecmp(p, "off"))
256                                 set_bool(opt -> data, FALSE);
257                         else
258                                 return "invalid value";
259                         break;
260         }
261         
262         return NULL;
263 }
264
265 static char *
266 opt_parse_set(buffer *b)
267 {
268         int i;
269         char *p;
270
271         find_token_start(b);
272         if((p = strchr(b -> ptr, '=')))
273                 *p++ = 0;
274         else
275                 return "invalid value assignment";
276         
277         strtrim(b -> ptr);
278
279         for(i = 0;abook_vars[i].option; i++)
280                 if(!strcmp(abook_vars[i].option, b -> ptr))
281                         return opt_set_set_option(b -> ptr, p, &abook_vars[i]);
282         
283         return "unknown option";
284 }
285
286
287 static struct {
288         char *token;
289         char * (*func) (buffer *line);
290 } opt_parsers[] = {
291         { "set", opt_parse_set },
292         { NULL }
293 };
294
295 static bool
296 opt_parse_line(char *line, int n, char *fn)
297 {
298         int i;
299         char *err = NULL;
300         char *token;
301         buffer b;
302         
303         assert(line && fn);
304
305         b.ptr = line;
306
307         find_token_start(&b);
308         b.data = b.ptr;
309         find_token_end(&b);
310         *b.ptr++ = 0;
311
312         if(!*line)
313                 return FALSE;
314
315         strtrim(b.data);
316         strtrim(b.ptr);
317
318         token = b.data;
319         b.data = b.ptr = b.ptr;
320
321         for(i = 0; opt_parsers[i].token; i++)
322                 if(!strcmp(opt_parsers[i].token, token)) {
323                         if(!(err = opt_parsers[i].func(&b)))
324                                 return FALSE;
325                         break;
326                 }
327         
328         fprintf(stderr, "%s: parse error at line %d: ", fn, n);
329         if(err)
330                 fprintf(stderr, "%s\n", err);
331         else
332                 fprintf(stderr, "unknown token %s\n", token);
333
334         return TRUE;
335 }
336
337 int
338 load_opts(char *filename)
339 {
340         FILE *in;
341         char *line = NULL;
342         int n;
343         int err = 0;
344         
345         if((in = fopen(filename, "r")) == NULL)
346                 return -1;
347
348         
349         for(n = 1;!feof(in); n++) {
350                 line = getaline(in);
351
352                 if(feof(in))
353                         break;
354
355                 if(line && *line) {
356                         opt_line_remove_comments(line);
357                         if(*line)
358                                 err += opt_parse_line(line, n, filename) ? 1:0;
359                 }
360
361                 my_free(line);
362         }
363
364         free(line);
365
366         return err;
367 }
368