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