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