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