From c38bc4bc5254bd5925d8567e7ff1554a7844b8c7 Mon Sep 17 00:00:00 2001 From: Jaakko Heinonen Date: Mon, 18 Mar 2002 10:30:14 +0000 Subject: [PATCH 1/1] new configuration system --- ChangeLog | 1 + Makefile.am | 4 +- Makefile.in | 16 +-- TODO | 1 + abook.c | 30 ++-- abook.h | 2 + abook_rl.c | 5 +- conff.c | 208 --------------------------- conff.h | 54 ------- database.c | 22 ++- edit.c | 24 +++- filter.c | 5 +- list.c | 10 +- list.h | 4 +- misc.c | 32 ----- options.c | 398 +++++++++++++++++++++++++++++++++++++++------------- options.h | 57 ++++++-- ui.c | 4 +- ui.h | 2 +- 19 files changed, 417 insertions(+), 462 deletions(-) delete mode 100644 conff.c delete mode 100644 conff.h diff --git a/ChangeLog b/ChangeLog index cde9daf..7cad6e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,5 @@ 2002-xx-xx + - options.c rewritten (new mutt style rc file support) - added a spec file for rpm support - bugfixes diff --git a/Makefile.am b/Makefile.am index e2273be..46ca605 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ bin_PROGRAMS = abook -abook_SOURCES = abook.c database.c filter.c list.c misc.c conff.c \ +abook_SOURCES = abook.c database.c filter.c list.c misc.c \ options.c edit.c ldif.c ui.c getname.c \ getopt.c getopt1.c abook_rl.c \ - abook.h database.h filter.h list.h misc.h help.h conff.h \ + abook.h database.h filter.h list.h misc.h help.h \ options.h edit.h ldif.h abook_curses.h ui.h getname.h \ getopt.h abook_rl.h diff --git a/Makefile.in b/Makefile.in index bbfc365..d209d76 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,10 +68,10 @@ VERSION = @VERSION@ bin_PROGRAMS = abook -abook_SOURCES = abook.c database.c filter.c list.c misc.c conff.c \ +abook_SOURCES = abook.c database.c filter.c list.c misc.c \ options.c edit.c ldif.c ui.c getname.c \ getopt.c getopt1.c abook_rl.c \ - abook.h database.h filter.h list.h misc.h help.h conff.h \ + abook.h database.h filter.h list.h misc.h help.h \ options.h edit.h ldif.h abook_curses.h ui.h getname.h \ getopt.h abook_rl.h @@ -88,8 +88,8 @@ DEFS = @DEFS@ -I. -I$(srcdir) -I. CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -abook_OBJECTS = abook.o database.o filter.o list.o misc.o conff.o \ -options.o edit.o ldif.o ui.o getname.o getopt.o getopt1.o abook_rl.o +abook_OBJECTS = abook.o database.o filter.o list.o misc.o options.o \ +edit.o ldif.o ui.o getname.o getopt.o getopt1.o abook_rl.o abook_LDADD = $(LDADD) abook_DEPENDENCIES = abook_LDFLAGS = @@ -107,10 +107,10 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = gtar GZIP_ENV = --best -DEP_FILES = .deps/abook.P .deps/abook_rl.P .deps/conff.P \ -.deps/database.P .deps/edit.P .deps/filter.P .deps/getname.P \ -.deps/getopt.P .deps/getopt1.P .deps/ldif.P .deps/list.P .deps/misc.P \ -.deps/options.P .deps/ui.P +DEP_FILES = .deps/abook.P .deps/abook_rl.P .deps/database.P \ +.deps/edit.P .deps/filter.P .deps/getname.P .deps/getopt.P \ +.deps/getopt1.P .deps/ldif.P .deps/list.P .deps/misc.P .deps/options.P \ +.deps/ui.P SOURCES = $(abook_SOURCES) OBJECTS = $(abook_OBJECTS) diff --git a/TODO b/TODO index eaddd22..f344b0b 100644 --- a/TODO +++ b/TODO @@ -3,4 +3,5 @@ - new file format (xml?) - new configuration system (maybe not yet in 0.5) - custom views, keybindings + - update man pages diff --git a/abook.c b/abook.c index fd3e336..101dd69 100644 --- a/abook.c +++ b/abook.c @@ -103,7 +103,8 @@ init_abook() { set_filenames(); check_abook_directory(); - init_options(); + init_opts(); + load_opts(rcfile); signal(SIGKILL, quit_abook_sig); signal(SIGTERM, quit_abook_sig); @@ -121,7 +122,7 @@ init_abook() if(load_database(datafile) || !statusline_ask_boolean( "If you continue all changes will " "be lost. Do you want to continue?", FALSE)) { - close_config(); + free_opts(); /*close_database();*/ close_ui(); exit(1); @@ -135,12 +136,12 @@ init_abook() void quit_abook() { - if( options_get_int("autosave") ) + if( opt_get_bool(BOOL_AUTOSAVE) ) save_database(); else if( statusline_ask_boolean("Save database", TRUE) ) save_database(); - close_config(); + free_opts(); close_database(); close_ui(); @@ -404,7 +405,7 @@ static void quit_mutt_query(int status) { close_database(); - close_config(); + free_opts(); exit(status); } @@ -417,7 +418,7 @@ muttq_print_item(FILE *file, int item) split_emailstr(item, emails); - for(i = 0; i < (options_get_int("mutt_return_all_emails") ? + for(i = 0; i < (opt_get_bool(BOOL_MUTT_RETURN_ALL_EMAILS) ? MAX_EMAILS : 1) ; i++) if( *emails[i] ) fprintf(file, "%s\t%s\t%s\n", emails[i], @@ -458,7 +459,8 @@ static void init_mutt_query() { set_filenames(); - init_options(); + init_opts(); + load_opts(rcfile); if( load_database(datafile) ) { printf("Cannot open database\n"); @@ -506,7 +508,7 @@ void launch_mutt(int item) { char *cmd = NULL, *mailstr = NULL; - char *mutt_command = options_get_str("mutt_command"); + char *mutt_command = opt_get_str(STR_MUTT_COMMAND); if(mutt_command == NULL || !*mutt_command) return; @@ -550,7 +552,7 @@ launch_wwwbrowser(int item) if( database[item][URL] ) cmd = mkstr("%s '%s'", - options_get_str("www_command"), + opt_get_str(STR_WWW_COMMAND), safe_str(database[item][URL])); else return; @@ -633,7 +635,8 @@ convert(char *srcformat, char *srcfile, char *dstformat, char *dstfile) #endif set_filenames(); - init_options(); + init_opts(); + load_opts(rcfile); switch( import_file(srcformat, srcfile) ) { case -1: @@ -663,7 +666,7 @@ convert(char *srcformat, char *srcfile, char *dstformat, char *dstfile) } close_database(); - close_config(); + free_opts(); exit(ret); } @@ -700,8 +703,9 @@ init_add_email() { set_filenames(); atexit(free_filenames); - init_options(); - atexit(close_config); + init_opts(); + load_opts(rcfile); + atexit(free_opts); /* * we don't actually care if loading fails or not diff --git a/abook.h b/abook.h index d9f401c..790d052 100644 --- a/abook.h +++ b/abook.h @@ -26,6 +26,8 @@ int strncasecmp (const char *, const char *, size_t); #define DIR_IN_HOME ".abook" #define DATAFILE "addressbook" +#define RCFILE "abookrc" + /* * some "abookwide" useful macros */ diff --git a/abook_rl.c b/abook_rl.c index 43ab31a..f5d05ca 100644 --- a/abook_rl.c +++ b/abook_rl.c @@ -120,9 +120,8 @@ abook_readline(WINDOW *w, int y, int x, char *s, int limit, bool use_completion) ret = readline(NULL); - if(rl_cancelled) { - if(ret) - free(ret); + if(rl_cancelled && ret) { + free(ret); ret = NULL; } diff --git a/conff.c b/conff.c deleted file mode 100644 index 80e9c5f..0000000 --- a/conff.c +++ /dev/null @@ -1,208 +0,0 @@ - -/* - * - * $Id$ - * - * Copyright (C) Jaakko Heinonen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include "misc.h" -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "conff.h" - -#ifndef DEBUG -# define NDEBUG 1 -#else -# undef NDEBUG -#endif - -#include - -#ifdef _AIX -int strcasecmp (const char *, const char *); -int strncasecmp (const char *, const char *, size_t); -#endif - -#define COMMENT_CHAR '#' - -static void -conff_free_node(struct conff_node *node) -{ - free(node -> value); - free(node -> key); - free(node); -} - -/* - * conff_add_key - * - * returns 0 if the key was successfully added - */ - -int -conff_add_key(struct conff_node **ptr, char *key, char *value, int flags) -{ - struct conff_node *new_item, *next = NULL; - int replace = 0; - - assert(key != NULL && value != NULL); - - for(; *ptr; ptr = &( (*ptr) -> next) ) - if(!strcasecmp(key, (*ptr) -> key ) ) { - if (flags & REPLACE_KEY) { - replace = 1; - break; - } else - return 1; - } - - if( (new_item = (struct conff_node *)malloc(sizeof(struct conff_node))) - == NULL ) - return 5; - - if(replace) { - next = (*ptr) -> next; - conff_free_node(*ptr); - } - - new_item -> key = strdup(key); - new_item -> value = strdup(value); - new_item -> next = next; - - *ptr = new_item; - - return 0; -} - -char * -conff_get_value(struct conff_node *node, char *key) -{ - - assert(key != NULL); - - for(; node ; node = node -> next) { - if(!strcasecmp(node -> key, key)) - return node -> value; - } - - return NULL; /* not found */ -} - -void -conff_free_nodes(struct conff_node *node) -{ - if(node != NULL) { - conff_free_nodes( node -> next ); - conff_free_node( node ); - } -} - -#ifdef DEBUG -void -print_values(struct conff_node *node) -{ - for(;node; node = node -> next) - fprintf(stderr, "%s - %s\n", node -> key, node -> value); -} -#endif - -void -conff_remove_key(struct conff_node **node, char *key) -{ - assert(key != NULL); - - for(; *node; node = &((*node) -> next) ) { - if(!strcasecmp(key, (*node) -> key ) ) { - struct conff_node *tmp = *node; - *node = (*node) -> next; - conff_free_node(tmp); - return; - } - } -} - -int -conff_save_file(struct conff_node *node, char *filename) -{ - FILE *out; - - assert(filename != NULL); - - if (!(out = fopen(filename, "w"))) - return -1; - - for(; node; node = node -> next) - fprintf(out, "%s=%s\n", node -> key, node -> value); - - fputc('\n', out); - fclose(out); - - return 0; -} - -int -conff_load_file(struct conff_node **node, char *filename, int flags) -{ - FILE *in; - char *line = NULL, *tmp; - int i = 0; - - assert(filename != NULL); - - if (!(in = fopen(filename, "r"))) - return -1; - - for(;;) { - i++; - - line = getaline(in); - if( feof(in) ) - break; - if(!line) - continue; - - strtrim(line); - - if(*line == '\n' || *line == '\0' || *line == COMMENT_CHAR) { - free(line); - continue; - } - - if ( (tmp = strchr(line, '=') )) { - *tmp++ = 0; - conff_add_key(node, strtrim(line), strtrim(tmp), flags); - } else { -/* fprintf(stderr, "parse error2,line #%d\n",i);*/ - fclose(in); - free(line); - return i; - } - free(line); - } - - free(line); - fclose(in); - - return 0; -} - diff --git a/conff.h b/conff.h deleted file mode 100644 index 26963c9..0000000 --- a/conff.h +++ /dev/null @@ -1,54 +0,0 @@ - -/* - * - * $Id$ - * - * Copyright (C) Jaakko Heinonen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _CONFF_H -#define _CONFF_H - -#include - - -struct conff_node -{ - char *key, *value; - - struct conff_node *next; -}; - - -int conff_add_key(struct conff_node **ptr, char *key, - char *value, int flags); -char *conff_get_value(struct conff_node *node, char *key); -#ifdef DEBUG -void print_values(struct conff_node *root); -#endif -void conff_free_nodes(struct conff_node *node); -void conff_remove_key(struct conff_node **node, char *key); -int conff_save_file(struct conff_node *node, char *filename); -int conff_load_file(struct conff_node **node, - char *filename, int flags); -char *strtrim(char *); - - -#define DONT_REPLACE_KEY 0 -#define REPLACE_KEY 1 - -#endif diff --git a/database.c b/database.c index 8b22602..70e5a1c 100644 --- a/database.c +++ b/database.c @@ -13,6 +13,7 @@ #include #include #include "abook.h" +#include #include "database.h" #include "list.h" #include "misc.h" @@ -318,21 +319,14 @@ remove_selected_items() char * get_surname(char *s) { - int i, a; - int len = strlen(s); - char *name = strdup(s); + char *p = s + strlen(s); - for( a = 0, i = len - 1; i >= 0; i--, a++ ) { - name[a] = s[i]; - if(name[a] == ' ') - break; - } - - name[ a ] = 0; + assert(s != NULL); - revstr(name); + while(p > s && *(p - 1) != ' ') + p--; - return name; + return strdup(p); } static int @@ -401,13 +395,13 @@ find_item(char *str, int start, int search_fields[]) return -2; /* error */ findstr = strdup(str); - findstr = strupper(findstr); + findstr = strlower(findstr); e.item = start - 1; /* must be "real start" - 1 */ db_enumerate_items(e) { for( i = 0; search_fields[i] >= 0; i++ ) { tmp = safe_strdup(database[e.item][search_fields[i]]); - if( tmp && strstr(strupper(tmp), findstr) ) { + if( tmp && strstr(strlower(tmp), findstr) ) { ret = e.item; goto out; } diff --git a/edit.c b/edit.c index 9403975..d8e3278 100644 --- a/edit.c +++ b/edit.c @@ -182,6 +182,21 @@ editor_print_data(int tab, int item) } } +/* + * function: change_field + * + * parameters: + * (char *msg) + * message to display as a prompt + * (char **field) + * a pointer to a pointer which will point a new string. if the latter + * pointer != NULL it will be freed (if user doesn't cancel) + * + * returns (int) + * a nonzero value if user has cancelled and zero if user has typed a + * valid string + */ + static int change_field(char *msg, char **field) { @@ -246,12 +261,9 @@ edit_emails(char c, int item) split_emailstr(item, emails); field = strdup(emails[email_num]); - if(change_field("E-mail: ", &field)) { -#ifdef DEBUG - fprintf(stderr, "change_field = TRUE\n"); -#endif - return; - } + if(change_field("E-mail: ", &field)) + return; /* user cancelled ( C-g ) */ + if(field) { strncpy(emails[email_num], field, MAX_EMAIL_LEN); fix_email_str(emails[email_num]); diff --git a/filter.c b/filter.c index d98ad11..08f49b0 100644 --- a/filter.c +++ b/filter.c @@ -783,11 +783,12 @@ ldif_export_database(FILE *out, struct db_enumerator e) static void html_export_write_head(FILE *out, int extra_column); static void html_export_write_tail(FILE *out); +extern int extra_column; + static int html_export_database(FILE *out, struct db_enumerator e) { char tmp[MAX_EMAILSTR_LEN]; - int extra_column = options_get_int("extra_column"); if( items < 1 ) return 2; @@ -1398,7 +1399,7 @@ text_export_database(FILE * out, struct db_enumerator e) char emails[MAX_EMAILS][MAX_EMAIL_LEN]; int j; char *realname = get_real_name(); - char *style = options_get_str("address_style"); + char *style = opt_get_str(STR_ADDRESS_STYLE); fprintf(out, "-----------------------------------------\n%s's address book\n" diff --git a/list.c b/list.c index 5bb6753..d349209 100644 --- a/list.c +++ b/list.c @@ -35,14 +35,14 @@ extern struct abook_field abook_fields[]; WINDOW *list = NULL; static int -init_extra_field(char *option_name) +init_extra_field(enum str_opts option) { int i, ret = -1; char *option_str; assert(option_name != NULL); - option_str = options_get_str(option_name); + option_str = opt_get_str(option); if(option_str && *option_str) { for(i = 0; i < ITEM_FIELDS; i++) { @@ -69,8 +69,8 @@ init_list() * init extra_column and extra alternative */ - extra_column = init_extra_field("extra_column"); - extra_alternative = init_extra_field("extra_alternative"); + extra_column = init_extra_field(STR_EXTRA_COLUMN); + extra_alternative = init_extra_field(STR_EXTRA_ALTERNATIVE); } void @@ -131,7 +131,7 @@ print_list_line(int i, int line, int highlight) mvwaddch(list, line, 0, '*' ); mvwaddnstr(list, line, NAMEPOS, database[i][NAME], NAMELEN); - if( options_get_int( "show_all_emails" ) ) + if( opt_get_bool(BOOL_SHOW_ALL_EMAILS) ) mvwaddnstr(list, line, EMAILPOS, database[i][EMAIL], real_emaillen); else { diff --git a/list.h b/list.h index d638979..cdffe73 100644 --- a/list.h +++ b/list.h @@ -36,8 +36,8 @@ enum { #define LIST_COLS COLS #define NAMEPOS 2 -#define EMAILPOS options_get_int("emailpos") -#define EXTRAPOS options_get_int("extrapos") +#define EMAILPOS opt_get_int(INT_EMAILPOS) +#define EXTRAPOS opt_get_int(INT_EXTRAPOS) #define NAMELEN (EMAILPOS-NAMEPOS -1) #define EMAILLEN (EXTRAPOS-EMAILPOS -1) diff --git a/misc.c b/misc.c index 7bf2f8f..fa67f0c 100644 --- a/misc.c +++ b/misc.c @@ -32,38 +32,6 @@ #include -char * -revstr(char *str) -{ - char *s, *s2; - - assert(str != NULL); - - s = s2 = strdup(str); - - while( *str ) - str++; - - while( *s ) - *--str = *s++; - - free(s2); - return str; -} - -char * -strupper(char *str) -{ - char *tmp = str; - - assert(str != NULL); - - while( ( *str = toupper( *str ) ) ) - str++; - - return tmp; -} - char * strlower(char *str) { diff --git a/options.c b/options.c index ad06711..82aae49 100644 --- a/options.c +++ b/options.c @@ -5,163 +5,359 @@ * 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 "misc.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 }, + { "emailpos", OT_INT, INT_EMAILPOS, 25 }, + { "extra_column", OT_STR, STR_EXTRA_COLUMN, UL "phone" }, + { "extra_alternative", OT_STR, STR_EXTRA_ALTERNATIVE, UL "-1" }, + { "extrapos", OT_INT, INT_EXTRAPOS, 65 }, + + { "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 }, + + { NULL } +}; + +static unsigned char bool_opts[BOOL_MAX]; +static int int_opts[INT_MAX]; +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_MAX); + 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] = strdup(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_MAX); - 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 < STR_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_options() +init_opts() { - abook_config = NULL; + int i; - if( rcfile_exist() ) - load_options(); - else - default_options(); + for(i = 0; abook_vars[i].option; i++) + restore_default(&abook_vars[i]); } +void +free_opts() +{ + int i; -#if 1 -extern bool alternative_rcfile; -#endif + /* + * only strings need to be freed + */ + for(i = 0; i < STR_MAX; i++) { + free(str_opts[i]); + str_opts[i] = NULL; + } +} -void -close_config() +/* + * file parsing + */ + +static void +opt_line_remove_comments(char *p) { -#if 1 - if(!alternative_rcfile) - save_options(); -#endif + bool in_quote = FALSE; + bool escape = FALSE; + + assert(p != NULL); + + for(; *p; p++) { + switch(*p) { + case '\"': + if(!escape) { + in_quote = !in_quote; + escape = FALSE; + } + break; + case '\\': + escape = TRUE; + break; + case '#': + if(!in_quote) { + *p = 0; + return; + } + default: + escape = FALSE; + } + } +} + +static char * +get_token_start(char *p) +{ + assert(p); + + for(; ISSPACE(*p); p++); - conff_free_nodes(abook_config); + return p; } -static int -rcfile_exist() +static char * +get_token_end(char *p) { - return ( (0 == access(SYSWIDE_RCFILE, F_OK)) || - (0 == access(rcfile, F_OK)) ); + assert(p); + + for(p = get_token_start(p); *p; p++) { + if(ISSPACE(*p)) { + break; + } + } + + return p; } -void -load_options() +static char * +opt_set_set_option(char *var, char *p, struct option *opt) { - int ret; + int len; - if( (ret = conff_load_file(&abook_config, rcfile, - REPLACE_KEY)) > 0) { - fprintf(stderr, "%s: parse error at line %d\n", rcfile, ret); - exit(1); + strtrim(p); + + len = strlen(p); + + if(p[len - 1] == '\"' && *p == '\"') { + if(len < 3) + return "invalid value"; + p[len - 1] = 0; + p++; } - if( (ret = conff_load_file(&abook_config, SYSWIDE_RCFILE, - DONT_REPLACE_KEY )) > 0) { - fprintf(stderr, "%s: parse error at line %d\n", - SYSWIDE_RCFILE, ret); - exit(1); + 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; } + + return NULL; } -#if 1 -void -save_options() +static char * +opt_parse_set(char *p) { - if( rcfile_exist() ) /* don't overwrite existing config */ - return; + char *var; + int i; - conff_save_file(abook_config, rcfile); + var = get_token_start(p); + if((p = strchr(var, '='))) + *p++ = 0; + else + return "invalid value assignment"; + + strtrim(var); + + for(i = 0;abook_vars[i].option; i++) + if(!strcmp(abook_vars[i].option, var)) + return opt_set_set_option(var, p, &abook_vars[i]); + + return "unknown option"; } -#endif -static void -options_add_key(char *key, char *value) + +static struct { + char *token; + char * (*func) (char *line); +} opt_parsers[] = { + { "set", opt_parse_set }, + { NULL } +}; + +static bool +opt_parse_line(char *line, int n, char *fn) { - const int flags = DONT_REPLACE_KEY; + int i; + char *p; + char *err = NULL; + + assert(line && fn); + + line = get_token_start(line); + p = get_token_end(line); + *p++ = 0; + + if(!*line) + return FALSE; - conff_add_key(&abook_config, key, value, flags); + strtrim(line); + strtrim(p); + + for(i = 0; opt_parsers[i].token; i++) + if(!strcmp(opt_parsers[i].token, line)) { + if(!(err = opt_parsers[i].func(p))) + return FALSE; + break; + } + + fprintf(stderr, "%s: parse error at line %d: ", fn, n); + if(err) + fprintf(stderr, "%s\n", err); + else + fprintf(stderr, "unknown token %s\n", line); + + return TRUE; } -static void -default_options() +int +load_opts(char *filename) { - options_add_key("autosave", "true"); - - options_add_key("show_all_emails", "true"); - options_add_key("emailpos", "25"); - options_add_key("extra_column", "phone"); - options_add_key("extra_alternative", "-1"); - options_add_key("extrapos", "65"); + FILE *in; + char *line = NULL; + int n; + bool err = FALSE; + + if((in = fopen(filename, "r")) == NULL) + return -1; - options_add_key("mutt_command", "mutt"); - options_add_key("mutt_return_all_emails", "true"); + + for(n = 1;!feof(in); n++) { + line = getaline(in); - options_add_key("print_command", "lpr"); + if(feof(in)) + break; - options_add_key("filesel_sort", "false"); + if(line && *line) { + opt_line_remove_comments(line); + if(*line) + err = opt_parse_line(line, n, filename); + } - options_add_key("www_command", "lynx"); + my_free(line); + } - options_add_key("address_style", "eu"); + free(line); - options_add_key("use_ascii_only", "false"); + if(err) { + printf("Press any key to continue...\n"); + fgetc(stdin); + } + + return err; } + diff --git a/options.h b/options.h index e458314..13e9709 100644 --- a/options.h +++ b/options.h @@ -1,16 +1,55 @@ #ifndef _OPTIONS_H #define _OPTIONS_H -#define RCFILE "abookrc" -#define SYSWIDE_RCFILE "/etc/abookrc" +#if 0 +typedef int bool; +#else +# include /* bool */ +#endif + +/* + * bool options + */ + + +enum bool_opts { + BOOL_AUTOSAVE, + BOOL_SHOW_ALL_EMAILS, + BOOL_MUTT_RETURN_ALL_EMAILS, + BOOL_USE_ASCII_ONLY, + BOOL_MAX +}; + +/* + * int options + */ + +enum int_opts { + INT_EMAILPOS, + INT_EXTRAPOS, + INT_MAX +}; + +/* + * string options + */ + +enum str_opts { + STR_EXTRA_COLUMN, + STR_EXTRA_ALTERNATIVE, + STR_MUTT_COMMAND, + STR_PRINT_COMMAND, + STR_WWW_COMMAND, + STR_ADDRESS_STYLE, + STR_MAX +}; -#include "conff.h" -int options_get_int(char *key); -char *options_get_str(char *key); -void init_options(); -void close_config(); -void load_options(); -void save_options(); +int opt_get_int(enum int_opts opt); +bool opt_get_bool(enum bool_opts opt); +char * opt_get_str(enum str_opts opt); +void init_opts(); +void free_opts(); +int load_opts(char *filename); #endif diff --git a/ui.c b/ui.c index a7d1a54..ceb61db 100644 --- a/ui.c +++ b/ui.c @@ -538,7 +538,7 @@ void ui_print_database() { FILE *handle; - char *command = options_get_str("print_command"); + char *command = opt_get_str(STR_PRINT_COMMAND); int mode; if( list_is_empty() ) @@ -586,7 +586,7 @@ ui_open_datafile() return; } - if( options_get_int("autosave") ) + if( opt_get_bool(BOOL_AUTOSAVE) ) save_database(); else if(statusline_ask_boolean("Save current database", FALSE)) save_database(); diff --git a/ui.h b/ui.h index 33107f8..5cdd873 100644 --- a/ui.h +++ b/ui.h @@ -35,7 +35,7 @@ void ui_open_datafile(); #include "options.h" /* needed for options_get_int */ -#define UI_HLINE_CHAR options_get_int("use_ascii_only") ? \ +#define UI_HLINE_CHAR opt_get_bool(BOOL_USE_ASCII_ONLY) ? \ '-' : ACS_HLINE #endif -- 2.39.2