]> git.deb.at Git - pkg/abook.git/blob - options.c
Imported Upstream version 0.5.5
[pkg/abook.git] / options.c
1
2 /*
3  * $Id: options.c,v 1.27 2005/09/21 16:50:31 jheinonen Exp $
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 "gettext.h"
19 #include "misc.h"
20 #include "xmalloc.h"
21
22 #ifndef FALSE
23 #       define FALSE    0
24 #endif
25 #ifndef TRUE
26 #       define TRUE     1
27 #endif
28
29 #define UL      (unsigned long)
30
31 /*
32  * option types
33  */
34
35 enum opt_type {
36         OT_BOOL,
37         OT_STR,
38         OT_INT
39 };
40
41 struct option {
42         char *option;
43         enum opt_type type;
44         unsigned int data;
45         unsigned long init;
46 };
47
48 static struct option abook_vars[] = {
49         { "autosave", OT_BOOL, BOOL_AUTOSAVE, TRUE },
50
51         { "show_all_emails", OT_BOOL, BOOL_SHOW_ALL_EMAILS, TRUE },
52         { "emailpos", OT_INT, INT_EMAILPOS, 25 },
53         { "extra_column", OT_STR, STR_EXTRA_COLUMN, UL "phone" },
54         { "extra_alternative", OT_STR, STR_EXTRA_ALTERNATIVE, UL "-1" },
55         { "extrapos", OT_INT, INT_EXTRAPOS, 65 },
56
57         { "mutt_command", OT_STR, STR_MUTT_COMMAND, UL "mutt" },
58         { "mutt_return_all_emails", OT_BOOL, BOOL_MUTT_RETURN_ALL_EMAILS,
59                 TRUE },
60
61         { "print_command", OT_STR, STR_PRINT_COMMAND, UL "lpr" },
62
63         { "www_command", OT_STR, STR_WWW_COMMAND, UL "lynx" },
64
65         { "address_style", OT_STR, STR_ADDRESS_STYLE, UL "eu" },
66
67         { "use_ascii_only", OT_BOOL, BOOL_USE_ASCII_ONLY, FALSE },
68
69         { "add_email_prevent_duplicates", OT_BOOL, BOOL_ADD_EMAIL_PREVENT_DUPLICATES, FALSE },
70         { "sort_field", OT_STR, STR_SORT_FIELD, UL "nick" },
71         { "show_cursor", OT_BOOL, BOOL_SHOW_CURSOR, FALSE },
72
73         { NULL }
74 };
75
76 static unsigned char bool_opts[BOOL_MAX];
77 static int int_opts[INT_MAXIMUM];
78 static char *str_opts[STR_MAX];
79
80 static void
81 set_int(enum int_opts opt, int value)
82 {
83         assert(opt >= 0 && opt < INT_MAXIMUM);
84
85         int_opts[opt] = value;
86 }
87
88 static void
89 set_bool(enum bool_opts opt, bool value)
90 {
91         assert(opt >= 0 && opt < BOOL_MAX);
92
93         bool_opts[opt] = value;
94 }
95
96 static void
97 set_str(enum str_opts opt, char *value)
98 {
99         assert(opt >= 0 && opt < STR_MAX);
100
101         if(str_opts[opt])
102                 free(str_opts[opt]);
103
104         str_opts[opt] = xstrdup(value);
105 }
106
107 int
108 opt_get_int(enum int_opts opt)
109 {
110         assert(opt >= 0 && opt < INT_MAXIMUM);
111
112         return int_opts[opt];
113 }
114
115 bool
116 opt_get_bool(enum bool_opts opt)
117 {
118         assert(opt >= 0 && opt < BOOL_MAX);
119
120         return bool_opts[opt];
121 }
122
123 char *
124 opt_get_str(enum str_opts opt)
125 {
126         assert(opt >= 0 && opt < STR_MAX);
127
128         return str_opts[opt];
129 }
130
131 static void
132 restore_default(struct option *p)
133 {
134         switch(p -> type) {
135                 case OT_BOOL:
136                         set_bool(p -> data, (bool)p -> init);
137                         break;
138                 case OT_INT:
139                         set_int(p -> data, (int)p -> init);
140                         break;
141                 case OT_STR:
142                         if(p -> init)
143                                 set_str(p -> data, (char *) p -> init);
144                         break;
145                 default:
146                         assert(0);
147         }
148 }
149
150 void
151 init_opts()
152 {
153         int i;
154
155         for(i = 0; abook_vars[i].option; i++)
156                 restore_default(&abook_vars[i]);
157 }
158
159 void
160 free_opts()
161 {
162         int i;
163
164         /*
165          * only strings need to be freed
166          */
167         for(i = 0; i < STR_MAX; i++) {
168                 free(str_opts[i]);
169                 str_opts[i] = NULL;
170         }
171 }
172
173 /*
174  * file parsing
175  */
176
177 typedef struct {
178         char *data, *ptr;
179 } buffer;
180
181 static void
182 opt_line_remove_comments(char *p)
183 {
184         bool in_quote = FALSE;
185         bool escape = FALSE;
186
187         assert(p != NULL);
188
189         for(; *p; p++) {
190                 switch(*p) {
191                         case '\"':
192                                 if(!escape)
193                                         in_quote = !in_quote;
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                 free(line);
392                 line = NULL;
393         }
394
395         free(line);
396
397         return err;
398 }
399