diff -r 37da646396b9 -r f0740133c606 bookloupe/bookloupe.c --- a/bookloupe/bookloupe.c Tue Oct 15 07:57:45 2013 +0100 +++ b/bookloupe/bookloupe.c Sun Sep 29 22:51:27 2013 +0100 @@ -128,35 +128,97 @@ gboolean pswit[SWITNO]; /* program switches */ +gboolean typo_compat,paranoid_compat; + static GOptionEntry options[]={ { "dp", 'd', 0, G_OPTION_ARG_NONE, pswit+DP_SWITCH, "Ignore DP-specific markup", NULL }, - { "noecho", 'e', 0, G_OPTION_ARG_NONE, pswit+ECHO_SWITCH, + { "no-dp", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+DP_SWITCH, + "Don't ignore DP-specific markup", NULL }, + { "echo", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, pswit+ECHO_SWITCH, + "Echo queried line", NULL }, + { "no-echo", 'e', G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+ECHO_SWITCH, "Don't echo queried line", NULL }, { "squote", 's', 0, G_OPTION_ARG_NONE, pswit+SQUOTE_SWITCH, "Check single quotes", NULL }, - { "typo", 't', 0, G_OPTION_ARG_NONE, pswit+TYPO_SWITCH, + { "no-squote", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+SQUOTE_SWITCH, + "Don't check single quotes", NULL }, + { "typo", 0, 0, G_OPTION_ARG_NONE, pswit+TYPO_SWITCH, "Check common typos", NULL }, + { "no-typo", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+TYPO_SWITCH, + "Don't check common typos", NULL }, { "qpara", 'p', 0, G_OPTION_ARG_NONE, pswit+QPARA_SWITCH, "Require closure of quotes on every paragraph", NULL }, - { "relaxed", 'x', 0, G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH, + { "no-qpara", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+QPARA_SWITCH, + "Don't require closure of quotes on every paragraph", NULL }, + { "paranoid", 0, G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH, + "Enable paranoid querying of everything", NULL }, + { "no-paranoid", 0, G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH, "Disable paranoid querying of everything", NULL }, - { "line-end", 'l', 0, G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH, - "Disable line end checking", NULL }, + { "line-end", 0, G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH, + "Enable line end checking", NULL }, + { "no-line-end", 'l', G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH, + "Diable line end checking", NULL }, { "overview", 'o', 0, G_OPTION_ARG_NONE, pswit+OVERVIEW_SWITCH, "Overview: just show counts", NULL }, + { "no-overview", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+OVERVIEW_SWITCH, + "Show individual warnings", NULL }, { "stdout", 'y', 0, G_OPTION_ARG_NONE, pswit+STDOUT_SWITCH, "Output errors to stdout instead of stderr", NULL }, + { "no-stdout", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+STDOUT_SWITCH, + "Output errors to stderr instead of stdout", NULL }, { "header", 'h', 0, G_OPTION_ARG_NONE, pswit+HEADER_SWITCH, "Echo header fields", NULL }, + { "no-header", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+HEADER_SWITCH, + "Don't echo header fields", NULL }, { "markup", 'm', 0, G_OPTION_ARG_NONE, pswit+MARKUP_SWITCH, "Ignore markup in < >", NULL }, + { "no-markup", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+MARKUP_SWITCH, + "No special handling for markup in < >", NULL }, { "usertypo", 'u', 0, G_OPTION_ARG_NONE, pswit+USERTYPO_SWITCH, "Use file of user-defined typos", NULL }, + { "no-usertypo", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+USERTYPO_SWITCH, + "Ignore file of user-defined typos", NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH, + "Verbose - list everything", NULL }, + { "no-verbose", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH, + "Switch off verbose mode", NULL }, + { NULL } +}; + +/* + * Options relating to configuration which make no sense from inside + * a configuration file. + */ + +static GOptionEntry config_options[]={ { "web", 'w', 0, G_OPTION_ARG_NONE, pswit+WEB_SWITCH, "Defaults for use on www upload", NULL }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH, - "Verbose - list everything", NULL }, + { "dump-config", 0, 0, G_OPTION_ARG_NONE, pswit+DUMP_CONFIG_SWITCH, + "Dump current config settings", NULL }, + { NULL } +}; + +static GOptionEntry compatibility_options[]={ + { "toggle-typo", 't', 0, G_OPTION_ARG_NONE, &typo_compat, + "Toggle checking for common typos", NULL }, + { "toggle-relaxed", 'x', 0, G_OPTION_ARG_NONE, ¶noid_compat, + "Toggle both paranoid mode and common typos", NULL }, { NULL } }; @@ -200,31 +262,198 @@ UINT saved_cp; #endif +GKeyFile *config; + +void config_file_update(GKeyFile *kf) +{ + int i; + gboolean sw; + for(i=0;options[i].long_name;i++) + { + if (g_str_has_prefix(options[i].long_name,"no-")) + continue; + if (options[i].arg==G_OPTION_ARG_NONE) + { + sw=*(gboolean *)options[i].arg_data; + if (options[i].flags&G_OPTION_FLAG_REVERSE) + sw=!sw; + g_key_file_set_boolean(kf,"options",options[i].long_name,sw); + } + else + g_assert_not_reached(); + } +} + +void config_file_add_comments(GKeyFile *kf) +{ + int i; + gchar *comment; + g_key_file_set_comment(kf,NULL,NULL," Default configuration for bookloupe", + NULL); + for(i=0;options[i].long_name;i++) + { + if (g_str_has_prefix(options[i].long_name,"no-")) + continue; + comment=g_strconcat(" ",options[i].description,NULL); + g_key_file_set_comment(kf,"options",options[i].long_name,comment,NULL); + g_free(comment); + } +} + +void dump_config(void) +{ + gchar *s; + if (config) + config_file_update(config); + else + { + config=g_key_file_new(); + config_file_update(config); + config_file_add_comments(config); + } + s=g_key_file_to_data(config,NULL,NULL); + if (s) + g_print("%s",s); + g_free(s); +} + +GKeyFile *read_config_file(gchar **full_path) +{ + int i; + GError *err=NULL; + gchar **search_dirs; + gchar *path; + const char *search_path; + GKeyFile *kf; + kf=g_key_file_new(); + search_path=g_getenv("BOOKLOUPE_CONFIG_PATH"); + if (search_path) + { +#ifdef __WIN32__ + search_dirs=g_strsplit(search_path,";",0); +#else + search_dirs=g_strsplit(search_path,":",0); +#endif + } + else + { + search_dirs=g_new(gchar *,4); + search_dirs[0]=g_get_current_dir(); + search_dirs[1]=g_strdup(running_from); + search_dirs[2]=g_strdup(g_get_user_config_dir()); + search_dirs[3]=NULL; + } + for(i=0;search_dirs[i];i++) + { + path=g_build_filename(search_dirs[i],"bookloupe.ini",NULL); + if (g_key_file_load_from_file(kf,path, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS,&err)) + break; + if (!g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT)) + { + g_printerr("Bookloupe: Error reading %s\n",path); + g_printerr("%s\n",err->message); + exit(1); + } + g_clear_error(&err); + g_free(path); + path=NULL; + } + if (!search_dirs[i]) + { + g_key_file_free(kf); + kf=NULL; + } + g_strfreev(search_dirs); + if (full_path && kf) + *full_path=path; + else + g_free(path); + return kf; +} + +void parse_config_file(void) +{ + int i,j; + gchar *path; + gchar **keys; + gboolean sw; + GError *err=NULL; + config=read_config_file(&path); + if (config) + keys=g_key_file_get_keys(config,"options",NULL,NULL); + else + keys=NULL; + if (keys) + { + for(i=0;keys[i];i++) + { + for(j=0;options[j].long_name;j++) + { + if (g_str_has_prefix(options[j].long_name,"no-")) + continue; + else if (!strcmp(keys[i],options[j].long_name)) + { + if (options[j].arg==G_OPTION_ARG_NONE) + { + sw=g_key_file_get_boolean(config,"options",keys[i], + &err); + if (err) + { + g_printerr("Bookloupe: %s: options.%s: %s\n", + path,keys[i],err->message); + g_clear_error(&err); + } + if (options[j].flags&G_OPTION_FLAG_REVERSE) + sw=!sw; + *(gboolean *)options[j].arg_data=sw; + break; + } + else + g_assert_not_reached(); + } + } + if (!options[j].long_name) + g_printerr("Bookloupe: %s: Unknown option \"%s\" ignored\n", + path,keys[i]); + } + g_strfreev(keys); + } + if (config) + g_free(path); +} + void parse_options(int *argc,char ***argv) { GError *err=NULL; GOptionContext *context; + GOptionGroup *compatibility; context=g_option_context_new( - "file - looks for errors in Project Gutenberg(TM) etexts"); + "file - look for errors in Project Gutenberg(TM) etexts"); g_option_context_add_main_entries(context,options,NULL); + g_option_context_add_main_entries(context,config_options,NULL); + compatibility=g_option_group_new("compatibility", + "Options for Compatibility with Gutcheck:", + "Show compatibility options",NULL,NULL); + g_option_group_add_entries(compatibility,compatibility_options); + g_option_context_add_group(context,compatibility); + g_option_context_set_description(context, + "For simplicity, only the switch options which reverse the\n" + "default configuration are listed. In most cases, both vanilla\n" + "and \"no-\" prefixed versions are available for use."); if (!g_option_context_parse(context,argc,argv,&err)) { g_printerr("Bookloupe: %s\n",err->message); g_printerr("Use \"%s --help\" for help\n",(*argv)[0]); exit(1); } - /* Paranoid checking is turned OFF, not on, by its switch */ - pswit[PARANOID_SWITCH]=!pswit[PARANOID_SWITCH]; - if (pswit[PARANOID_SWITCH]) - /* if running in paranoid mode, typo checks default to enabled */ + if (typo_compat) pswit[TYPO_SWITCH]=!pswit[TYPO_SWITCH]; - /* Line-end checking is turned OFF, not on, by its switch */ - pswit[LINE_END_SWITCH]=!pswit[LINE_END_SWITCH]; - /* Echoing is turned OFF, not on, by its switch */ - pswit[ECHO_SWITCH]=!pswit[ECHO_SWITCH]; - if (pswit[OVERVIEW_SWITCH]) - /* just print summary; don't echo */ - pswit[ECHO_SWITCH]=FALSE; + if (paranoid_compat) + { + pswit[PARANOID_SWITCH]=!pswit[PARANOID_SWITCH]; + pswit[TYPO_SWITCH]=!pswit[TYPO_SWITCH]; + } /* * Web uploads - for the moment, this is really just a placeholder * until we decide what processing we really want to do on web uploads @@ -246,6 +475,14 @@ pswit[USERTYPO_SWITCH]=FALSE; pswit[DP_SWITCH]=FALSE; } + if (pswit[DUMP_CONFIG_SWITCH]) + { + dump_config(); + exit(0); + } + if (pswit[OVERVIEW_SWITCH]) + /* just print summary; don't echo */ + pswit[ECHO_SWITCH]=FALSE; if (*argc<2) { proghelp(context); @@ -388,6 +625,15 @@ saved_cp=GetConsoleOutputCP(); #endif running_from=g_path_get_dirname(argv[0]); + /* Paranoid checking is turned OFF, not on, by its switch */ + pswit[PARANOID_SWITCH]=TRUE; + /* if running in paranoid mode, typo checks default to enabled */ + pswit[TYPO_SWITCH]=TRUE; + /* Line-end checking is turned OFF, not on, by its switch */ + pswit[LINE_END_SWITCH]=TRUE; + /* Echoing is turned OFF, not on, by its switch */ + pswit[ECHO_SWITCH]=TRUE; + parse_config_file(); parse_options(&argc,&argv); if (pswit[USERTYPO_SWITCH]) read_user_scannos(); @@ -428,6 +674,8 @@ g_free(running_from); if (usertypo) g_tree_unref(usertypo); + if (config) + g_key_file_free(config); return 0; }