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