X-Git-Url: https://git.deb.at/w?p=pkg%2Fabook.git;a=blobdiff_plain;f=options.c;h=6f75a06db368f215c85f6731b3415222badb2a41;hp=e1a554391b2d2a56313c833de2077ccdf24c4b74;hb=b722eae92e8deb6bd080dea1f2f929a7dd9edddb;hpb=ca9cda9e7096dad72f1335a810314001daca7314 diff --git a/options.c b/options.c index e1a5543..6f75a06 100644 --- a/options.c +++ b/options.c @@ -5,163 +5,554 @@ * by JH * * Copyright (C) Jaakko Heinonen + * */ +#include #include #include -#include -#include "abook_curses.h" -#include "abook.h" +#include +#include #include "options.h" -#ifdef HAVE_CONFIG_H -# include "config.h" +#include "abook.h" +#include "gettext.h" +#include "misc.h" +#include "views.h" +#include "xmalloc.h" + +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 #endif -struct conff_node *abook_config; +#define UL (unsigned long) -static int rcfile_exist(); -static void default_options(); +/* + * option types + */ -extern char *rcfile; +enum opt_type { + OT_BOOL, + OT_STR, + OT_INT +}; -static char * -abook_opt_conff_get_val(char *key) +struct option { + char *option; + enum opt_type type; + unsigned int data; + unsigned long init; +}; + +static struct option abook_vars[] = { + { "autosave", OT_BOOL, BOOL_AUTOSAVE, TRUE }, + + { "show_all_emails", OT_BOOL, BOOL_SHOW_ALL_EMAILS, TRUE }, + { "index_format", OT_STR, STR_INDEX_FORMAT, UL " {name:22} {email:40} {phone:12|workphone|mobile}" }, + { "mutt_command", OT_STR, STR_MUTT_COMMAND, UL "mutt" }, + { "mutt_return_all_emails", OT_BOOL, BOOL_MUTT_RETURN_ALL_EMAILS, + TRUE }, + + { "print_command", OT_STR, STR_PRINT_COMMAND, UL "lpr" }, + + { "www_command", OT_STR, STR_WWW_COMMAND, UL "lynx" }, + + { "address_style", OT_STR, STR_ADDRESS_STYLE, UL "eu" }, + + { "use_ascii_only", OT_BOOL, BOOL_USE_ASCII_ONLY, FALSE }, + + { "add_email_prevent_duplicates", OT_BOOL, BOOL_ADD_EMAIL_PREVENT_DUPLICATES, FALSE }, + { "preserve_fields", OT_STR, STR_PRESERVE_FIELDS, UL "standard" }, + { "sort_field", OT_STR, STR_SORT_FIELD, UL "nick" }, + { "show_cursor", OT_BOOL, BOOL_SHOW_CURSOR, FALSE }, + { "use_mouse", OT_BOOL, BOOL_USE_MOUSE, FALSE }, + { "scroll_speed", OT_INT, INT_SCROLL_SPEED, UL 2 }, + { "use_colors", OT_BOOL, BOOL_USE_COLORS, FALSE }, + { "color_header_fg", OT_STR, STR_COLOR_HEADER_FG, UL "blue" }, + { "color_header_fg", OT_STR, STR_COLOR_HEADER_FG, UL "blue" }, + { "color_header_bg", OT_STR, STR_COLOR_HEADER_BG, UL "red" }, + { "color_footer_fg", OT_STR, STR_COLOR_FOOTER_FG, UL "red" }, + { "color_footer_bg", OT_STR, STR_COLOR_FOOTER_BG, UL "default" }, + { "color_list_even_fg", OT_STR, STR_COLOR_LIST_EVEN_FG, UL "yellow" }, + { "color_list_even_bg", OT_STR, STR_COLOR_LIST_EVEN_BG, UL "default" }, + { "color_list_odd_fg", OT_STR, STR_COLOR_LIST_ODD_FG, UL "default" }, + { "color_list_odd_bg", OT_STR, STR_COLOR_LIST_ODD_BG, UL "default" }, + { "color_list_header_fg", OT_STR, STR_COLOR_LIST_HEADER_FG, UL "white" }, + { "color_list_header_bg", OT_STR, STR_COLOR_LIST_HEADER_BG, UL "blue" }, + { "color_list_highlight_fg", OT_STR, STR_COLOR_LIST_HIGHLIGHT_FG, UL "black" }, + { "color_list_highlight_bg", OT_STR, STR_COLOR_LIST_HIGHLIGHT_BG, UL "green" }, + { "color_tab_border_fg", OT_STR, STR_COLOR_TAB_BORDER_FG, UL "cyan" }, + { "color_tab_border_bg", OT_STR, STR_COLOR_TAB_BORDER_BG, UL "default" }, + { "color_tab_label_fg", OT_STR, STR_COLOR_TAB_LABEL_FG, UL "magenta" }, + { "color_tab_label_bg", OT_STR, STR_COLOR_TAB_LABEL_BG, UL "default" }, + { "color_field_name_fg", OT_STR, STR_COLOR_FIELD_NAME_FG, UL "yellow" }, + { "color_field_name_bg", OT_STR, STR_COLOR_FIELD_NAME_BG, UL "default" }, + { "color_field_value_fg", OT_STR, STR_COLOR_FIELD_VALUE_FG, UL "green" }, + { "color_field_value_bg", OT_STR, STR_COLOR_FIELD_VALUE_BG, UL "default" }, + { NULL } +}; + +static unsigned char bool_opts[BOOL_MAX]; +static int int_opts[INT_MAXIMUM]; +static char *str_opts[STR_MAX]; + +static void +set_int(enum int_opts opt, int value) { - int tried; - char *value = NULL; + assert(opt >= 0 && opt < INT_MAXIMUM); + int_opts[opt] = value; +} - for(tried = 0; tried < 2; ) { - if( ( value = conff_get_value(abook_config, key) ) - == 0 ) { - tried ++; - default_options(); /* try with defaults */ - } else - return value; - } - return NULL; +static void +set_bool(enum bool_opts opt, bool value) +{ + assert(opt >= 0 && opt < BOOL_MAX); + + bool_opts[opt] = value; +} + +static void +set_str(enum str_opts opt, char *value) +{ + assert(opt >= 0 && opt < STR_MAX); + + if(str_opts[opt]) + free(str_opts[opt]); + + str_opts[opt] = xstrdup(value); } int -options_get_int(char *key) +opt_get_int(enum int_opts opt) { - char *value; - int ret; - - if( ( value = abook_opt_conff_get_val(key) ) - == NULL) - return 1; + assert(opt >= 0 && opt < INT_MAXIMUM); - if( !strcasecmp(value, "true") ) - ret = 1; - else - if( !strcasecmp(value, "false") ) - ret = 0; - else - ret = safe_atoi(value); - - return ret; + return int_opts[opt]; } - + +bool +opt_get_bool(enum bool_opts opt) +{ + assert(opt >= 0 && opt < BOOL_MAX); + + return bool_opts[opt]; +} + char * -options_get_str(char *key) +opt_get_str(enum str_opts opt) { - return abook_opt_conff_get_val(key); + assert(opt >= 0 && opt < STR_MAX); + + return str_opts[opt]; } - + +static void +restore_default(struct option *p) +{ + switch(p -> type) { + case OT_BOOL: + set_bool(p -> data, (bool)p -> init); + break; + case OT_INT: + set_int(p -> data, (int)p -> init); + break; + case OT_STR: + if(p -> init) + set_str(p -> data, (char *) p -> init); + break; + default: + assert(0); + } +} + +void +init_opts() +{ + int i; + + for(i = 0; abook_vars[i].option; i++) + restore_default(&abook_vars[i]); +} + void -init_options() +free_opts() +{ + int i; + + /* + * only strings need to be freed + */ + for(i = 0; i < STR_MAX; i++) { + free(str_opts[i]); + str_opts[i] = NULL; + } +} + +/* + * file parsing + */ + +typedef struct { + char *data, *ptr; +} buffer; + +static void +opt_line_remove_comments(char *p) +{ + bool in_quote = FALSE; + bool escape = FALSE; + + assert(p != NULL); + + for(; *p; p++) { + switch(*p) { + case '\"': + if(!escape) + in_quote = !in_quote; + break; + case '\\': + escape = TRUE; + break; + case '#': + if(!in_quote) { + *p = 0; + return; + } + default: + escape = FALSE; + } + } +} + +/* After calling, + * - b->data points to the found token, or NULL is end of parsing + * - b->ptr points to the begining of next token + * + * If the TOKEN_ALLOC option is used, the original string is not mangled + * and memory is allocated for the token. + */ +static char * +get_token(buffer *b, int options) { - abook_config = NULL; + char quote = 0, c; + char *end = NULL; + + assert(b); + + SKIPWS(b->ptr); + if(*b->ptr && strchr("\"'", *b->ptr)) + quote = *(b->ptr++); + b->data = b->ptr; + + while(1) { + if(!(c = *b->ptr)) { + end = b->ptr; + break; + } + + if(!quote && ( + ISSPACE(c) || + ((options & TOKEN_EQUAL) && (c == '=')) || + ((options & TOKEN_COMMA) && (c == ','))) + ) { + end = b->ptr; + break; + } else if(c == quote) { + quote = 0; + end = b->ptr++; + break; + } + + b->ptr++; + } + + if(quote) + return _("quote mismatch"); + + if(options & (TOKEN_EQUAL | TOKEN_COMMA)) + SKIPWS(b->ptr); /* whitespaces can precede the sign */ + + if((options & TOKEN_EQUAL) && (*b->ptr != '=')) + return _("no assignment character found"); - if( rcfile_exist() ) - load_options(); + if((options & TOKEN_COMMA) && *b->ptr && (*b->ptr != ',')) + return _("error in comma separated list"); + + if(b->ptr == b->data) { + b->data = NULL; + return NULL; /* no error, just end of parsing */ + } + + if(options & TOKEN_ALLOC) /* freeing is the caller's responsibility */ + b->data = xstrndup(b->data, end - b->data); else - default_options(); + *end = 0; + + b->ptr++; /* advance to next token */ + SKIPWS(b->ptr); + + return NULL; } +static const char * +opt_set_set_option(char *p, struct option *opt) +{ + int len; -#if 1 -extern int alternative_rcfile; -#endif + assert(p); -void -close_config() + strtrim(p); + len = strlen(p); + + if(*p == '\"' && p[len - 1] == '\"') { + if(len < 3) + return _("invalid value"); + p[len - 1] = 0; + p++; + } + + switch(opt -> type) { + case OT_STR: + set_str(opt -> data, p); + break; + case OT_INT: + set_int(opt -> data, safe_atoi(p)); + break; + case OT_BOOL: + if(!strcasecmp(p, "true") || !strcasecmp(p, "on")) + set_bool(opt -> data, TRUE); + else if(!strcasecmp(p, "false") || + !strcasecmp(p, "off")) + set_bool(opt -> data, FALSE); + else + return _("invalid value"); + break; + default: + assert(0); + } + + return NULL; +} + +static const char * +opt_set_option(char *var, char *p) { -#if 1 - if(!alternative_rcfile) - save_options(); -#endif + int i; + + assert(var); + assert(p); - conff_free_nodes(abook_config); + for(i = 0; abook_vars[i].option; i++) + if(!strcmp(abook_vars[i].option, var)) + return opt_set_set_option(p, &abook_vars[i]); + + return _("unknown option"); } static int -rcfile_exist() +check_options() { - return ( (0 == access(SYSWIDE_RCFILE, F_OK)) || - (0 == access(rcfile, F_OK)) ); -} + char *str; + int err = 0; -void -load_options() -{ - int ret; - - if( (ret = conff_load_file(&abook_config, rcfile, - REPLACE_KEY)) > 0) { - fprintf(stderr, "%s: parse error at line %d\n", rcfile, ret); - exit(1); + str = opt_get_str(STR_PRESERVE_FIELDS); + if(strcasecmp(str, "all") && strcasecmp(str, "none") && + strcasecmp(str, "standard")) { + fprintf(stderr, _("valid values for the 'preserve_fields' " + "option are 'all', 'standard' " + "(default), and 'none'\n")); + restore_default(&abook_vars[STR_PRESERVE_FIELDS]); + err++; } + str = opt_get_str(STR_ADDRESS_STYLE); + if(strcasecmp(str, "eu") && strcasecmp(str, "uk") && + strcasecmp(str, "us")) { + fprintf(stderr, _("valid values for the 'address_style' " + "option are 'eu' (default), 'uk', " + "and 'us'\n")); + restore_default(&abook_vars[STR_ADDRESS_STYLE]); + err++; + } + + return err; +} + +/* + * syntax: set