]> git.deb.at Git - pkg/abook.git/blob - options.c
- i18n support
[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 "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                                         escape = FALSE;
195                                 }
196                                 break;
197                         case '\\':
198                                 escape = TRUE;
199                                 break;
200                         case '#':
201                                 if(!in_quote) {
202                                         *p = 0;
203                                         return;
204                                 }
205                         default:
206                                 escape = FALSE;
207                 }
208         }
209 }
210
211 void
212 find_token_start(buffer *b)
213 {
214         assert(b);
215
216         for(; ISSPACE(*b -> ptr); b -> ptr ++);
217 }
218
219 void
220 find_token_end(buffer *b)
221 {
222         assert(b);
223
224         for(find_token_start(b); *(b -> ptr); b -> ptr ++) {
225                 if(ISSPACE(*(b -> ptr))) {
226                         break;
227                 }
228         }
229 }
230
231 static char *
232 opt_set_set_option(char *var, char *p, struct option *opt)
233 {
234         int len;
235
236         strtrim(p);
237
238         len = strlen(p);
239
240         if(p[len - 1] == '\"' && *p == '\"') {
241                 if(len < 3)
242                         return _("invalid value");
243                 p[len - 1] = 0;
244                 p++;
245         }
246
247         switch(opt -> type) {
248                 case OT_STR:
249                         set_str(opt -> data, p);
250                         break;
251                 case OT_INT:
252                         set_int(opt -> data, safe_atoi(p));
253                         break;
254                 case OT_BOOL:
255                         if(!strcasecmp(p, "true") || !strcasecmp(p, "on"))
256                                 set_bool(opt -> data, TRUE);
257                         else if(!strcasecmp(p, "false") ||
258                                         !strcasecmp(p, "off"))
259                                 set_bool(opt -> data, FALSE);
260                         else
261                                 return _("invalid value");
262                         break;
263                 default:
264                         assert(0);
265         }
266
267         return NULL;
268 }
269
270 static char *
271 opt_parse_set(buffer *b)
272 {
273         int i;
274         char *p;
275
276         find_token_start(b);
277         if((p = strchr(b -> ptr, '=')))
278                 *p++ = 0;
279         else
280                 return _("invalid value assignment");
281
282         strtrim(b -> ptr);
283
284         for(i = 0;abook_vars[i].option; i++)
285                 if(!strcmp(abook_vars[i].option, b -> ptr))
286                         return opt_set_set_option(b -> ptr, p, &abook_vars[i]);
287
288         return _("unknown option");
289 }
290
291 #include "database.h" /* needed for change_custom_field_name */
292
293 static char *
294 opt_parse_customfield(buffer *b)
295 {
296         char *p, num[5];
297         int n;
298         size_t len;
299
300         find_token_start(b);
301         p = b -> ptr;
302         find_token_end(b);
303
304         memset(num, 0, sizeof(num));
305
306         len = (b -> ptr - p);
307         strncpy(num, p, min(sizeof(num) - 1, len));
308         n = safe_atoi(num);
309
310         find_token_start(b);
311
312         if(change_custom_field_name(b->ptr, n) == -1)
313                 return _("invalid custom field number");
314
315         return NULL;
316 }
317
318 static struct {
319         char *token;
320         char * (*func) (buffer *line);
321 } opt_parsers[] = {
322         { "set", opt_parse_set },
323         { "customfield", opt_parse_customfield },
324         { NULL }
325 };
326
327 static bool
328 opt_parse_line(char *line, int n, char *fn)
329 {
330         int i;
331         char *err = NULL;
332         char *token;
333         buffer b;
334
335         assert(line && fn);
336
337         b.ptr = line;
338
339         find_token_start(&b);
340         b.data = b.ptr;
341         find_token_end(&b);
342         *b.ptr++ = 0;
343
344         if(!*line)
345                 return FALSE;
346
347         strtrim(b.data);
348         strtrim(b.ptr);
349
350         token = b.data;
351         b.data = b.ptr = b.ptr;
352
353         for(i = 0; opt_parsers[i].token; i++)
354                 if(!strcmp(opt_parsers[i].token, token)) {
355                         if(!(err = opt_parsers[i].func(&b)))
356                                 return FALSE;
357                         break;
358                 }
359
360         fprintf(stderr, _("%s: parse error at line %d: "), fn, n);
361         if(err)
362                 fprintf(stderr, "%s\n", err);
363         else
364                 fprintf(stderr, _("unknown token %s\n"), token);
365
366         return TRUE;
367 }
368
369 int
370 load_opts(char *filename)
371 {
372         FILE *in;
373         char *line = NULL;
374         int n;
375         int err = 0;
376
377         if((in = fopen(filename, "r")) == NULL)
378                 return -1;
379
380
381         for(n = 1;!feof(in); n++) {
382                 line = getaline(in);
383
384                 if(feof(in))
385                         break;
386
387                 if(line && *line) {
388                         opt_line_remove_comments(line);
389                         if(*line)
390                                 err += opt_parse_line(line, n, filename) ? 1:0;
391                 }
392
393                 free(line);
394                 line = NULL;
395         }
396
397         free(line);
398
399         return err;
400 }
401