1.1 --- a/bookloupe/bookloupe.c Sat Oct 26 18:47:33 2013 +0100
1.2 +++ b/bookloupe/bookloupe.c Fri Oct 25 11:15:18 2013 +0100
1.3 @@ -128,35 +128,97 @@
1.4
1.5 gboolean pswit[SWITNO]; /* program switches */
1.6
1.7 +gboolean typo_compat,paranoid_compat;
1.8 +
1.9 static GOptionEntry options[]={
1.10 { "dp", 'd', 0, G_OPTION_ARG_NONE, pswit+DP_SWITCH,
1.11 "Ignore DP-specific markup", NULL },
1.12 - { "noecho", 'e', 0, G_OPTION_ARG_NONE, pswit+ECHO_SWITCH,
1.13 + { "no-dp", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.14 + G_OPTION_ARG_NONE, pswit+DP_SWITCH,
1.15 + "Don't ignore DP-specific markup", NULL },
1.16 + { "echo", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, pswit+ECHO_SWITCH,
1.17 + "Echo queried line", NULL },
1.18 + { "no-echo", 'e', G_OPTION_FLAG_REVERSE,
1.19 + G_OPTION_ARG_NONE, pswit+ECHO_SWITCH,
1.20 "Don't echo queried line", NULL },
1.21 { "squote", 's', 0, G_OPTION_ARG_NONE, pswit+SQUOTE_SWITCH,
1.22 "Check single quotes", NULL },
1.23 - { "typo", 't', 0, G_OPTION_ARG_NONE, pswit+TYPO_SWITCH,
1.24 + { "no-squote", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.25 + G_OPTION_ARG_NONE, pswit+SQUOTE_SWITCH,
1.26 + "Don't check single quotes", NULL },
1.27 + { "typo", 0, 0, G_OPTION_ARG_NONE, pswit+TYPO_SWITCH,
1.28 "Check common typos", NULL },
1.29 + { "no-typo", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.30 + G_OPTION_ARG_NONE, pswit+TYPO_SWITCH,
1.31 + "Don't check common typos", NULL },
1.32 { "qpara", 'p', 0, G_OPTION_ARG_NONE, pswit+QPARA_SWITCH,
1.33 "Require closure of quotes on every paragraph", NULL },
1.34 - { "relaxed", 'x', 0, G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH,
1.35 + { "no-qpara", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.36 + G_OPTION_ARG_NONE, pswit+QPARA_SWITCH,
1.37 + "Don't require closure of quotes on every paragraph", NULL },
1.38 + { "paranoid", 0, G_OPTION_FLAG_HIDDEN,
1.39 + G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH,
1.40 + "Enable paranoid querying of everything", NULL },
1.41 + { "no-paranoid", 0, G_OPTION_FLAG_REVERSE,
1.42 + G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH,
1.43 "Disable paranoid querying of everything", NULL },
1.44 - { "line-end", 'l', 0, G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH,
1.45 + { "line-end", 0, G_OPTION_FLAG_HIDDEN,
1.46 + G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH,
1.47 + "Enable line end checking", NULL },
1.48 + { "no-line-end", 'l', G_OPTION_FLAG_REVERSE,
1.49 + G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH,
1.50 "Disable line end checking", NULL },
1.51 { "overview", 'o', 0, G_OPTION_ARG_NONE, pswit+OVERVIEW_SWITCH,
1.52 "Overview: just show counts", NULL },
1.53 + { "no-overview", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.54 + G_OPTION_ARG_NONE, pswit+OVERVIEW_SWITCH,
1.55 + "Show individual warnings", NULL },
1.56 { "stdout", 'y', 0, G_OPTION_ARG_NONE, pswit+STDOUT_SWITCH,
1.57 "Output errors to stdout instead of stderr", NULL },
1.58 + { "no-stdout", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.59 + G_OPTION_ARG_NONE, pswit+STDOUT_SWITCH,
1.60 + "Output errors to stderr instead of stdout", NULL },
1.61 { "header", 'h', 0, G_OPTION_ARG_NONE, pswit+HEADER_SWITCH,
1.62 "Echo header fields", NULL },
1.63 + { "no-header", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.64 + G_OPTION_ARG_NONE, pswit+HEADER_SWITCH,
1.65 + "Don't echo header fields", NULL },
1.66 { "markup", 'm', 0, G_OPTION_ARG_NONE, pswit+MARKUP_SWITCH,
1.67 "Ignore markup in < >", NULL },
1.68 + { "no-markup", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.69 + G_OPTION_ARG_NONE, pswit+MARKUP_SWITCH,
1.70 + "No special handling for markup in < >", NULL },
1.71 { "usertypo", 'u', 0, G_OPTION_ARG_NONE, pswit+USERTYPO_SWITCH,
1.72 "Use file of user-defined typos", NULL },
1.73 + { "no-usertypo", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.74 + G_OPTION_ARG_NONE, pswit+USERTYPO_SWITCH,
1.75 + "Ignore file of user-defined typos", NULL },
1.76 + { "verbose", 'v', 0, G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH,
1.77 + "Verbose - list everything", NULL },
1.78 + { "no-verbose", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
1.79 + G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH,
1.80 + "Switch off verbose mode", NULL },
1.81 + { NULL }
1.82 +};
1.83 +
1.84 +/*
1.85 + * Options relating to configuration which make no sense from inside
1.86 + * a configuration file.
1.87 + */
1.88 +
1.89 +static GOptionEntry config_options[]={
1.90 { "web", 'w', 0, G_OPTION_ARG_NONE, pswit+WEB_SWITCH,
1.91 "Defaults for use on www upload", NULL },
1.92 - { "verbose", 'v', 0, G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH,
1.93 - "Verbose - list everything", NULL },
1.94 + { "dump-config", 0, 0, G_OPTION_ARG_NONE, pswit+DUMP_CONFIG_SWITCH,
1.95 + "Dump current config settings", NULL },
1.96 + { NULL }
1.97 +};
1.98 +
1.99 +static GOptionEntry compatibility_options[]={
1.100 + { "toggle-typo", 't', 0, G_OPTION_ARG_NONE, &typo_compat,
1.101 + "Toggle checking for common typos", NULL },
1.102 + { "toggle-relaxed", 'x', 0, G_OPTION_ARG_NONE, ¶noid_compat,
1.103 + "Toggle both paranoid mode and common typos", NULL },
1.104 { NULL }
1.105 };
1.106
1.107 @@ -200,31 +262,198 @@
1.108 UINT saved_cp;
1.109 #endif
1.110
1.111 +GKeyFile *config;
1.112 +
1.113 +void config_file_update(GKeyFile *kf)
1.114 +{
1.115 + int i;
1.116 + gboolean sw;
1.117 + for(i=0;options[i].long_name;i++)
1.118 + {
1.119 + if (g_str_has_prefix(options[i].long_name,"no-"))
1.120 + continue;
1.121 + if (options[i].arg==G_OPTION_ARG_NONE)
1.122 + {
1.123 + sw=*(gboolean *)options[i].arg_data;
1.124 + if (options[i].flags&G_OPTION_FLAG_REVERSE)
1.125 + sw=!sw;
1.126 + g_key_file_set_boolean(kf,"options",options[i].long_name,sw);
1.127 + }
1.128 + else
1.129 + g_assert_not_reached();
1.130 + }
1.131 +}
1.132 +
1.133 +void config_file_add_comments(GKeyFile *kf)
1.134 +{
1.135 + int i;
1.136 + gchar *comment;
1.137 + g_key_file_set_comment(kf,NULL,NULL," Default configuration for bookloupe",
1.138 + NULL);
1.139 + for(i=0;options[i].long_name;i++)
1.140 + {
1.141 + if (g_str_has_prefix(options[i].long_name,"no-"))
1.142 + continue;
1.143 + comment=g_strconcat(" ",options[i].description,NULL);
1.144 + g_key_file_set_comment(kf,"options",options[i].long_name,comment,NULL);
1.145 + g_free(comment);
1.146 + }
1.147 +}
1.148 +
1.149 +void dump_config(void)
1.150 +{
1.151 + gchar *s;
1.152 + if (config)
1.153 + config_file_update(config);
1.154 + else
1.155 + {
1.156 + config=g_key_file_new();
1.157 + config_file_update(config);
1.158 + config_file_add_comments(config);
1.159 + }
1.160 + s=g_key_file_to_data(config,NULL,NULL);
1.161 + if (s)
1.162 + g_print("%s",s);
1.163 + g_free(s);
1.164 +}
1.165 +
1.166 +GKeyFile *read_config_file(gchar **full_path)
1.167 +{
1.168 + int i;
1.169 + GError *err=NULL;
1.170 + gchar **search_dirs;
1.171 + gchar *path;
1.172 + const char *search_path;
1.173 + GKeyFile *kf;
1.174 + kf=g_key_file_new();
1.175 + search_path=g_getenv("BOOKLOUPE_CONFIG_PATH");
1.176 + if (search_path)
1.177 + {
1.178 +#ifdef __WIN32__
1.179 + search_dirs=g_strsplit(search_path,";",0);
1.180 +#else
1.181 + search_dirs=g_strsplit(search_path,":",0);
1.182 +#endif
1.183 + }
1.184 + else
1.185 + {
1.186 + search_dirs=g_new(gchar *,4);
1.187 + search_dirs[0]=g_get_current_dir();
1.188 + search_dirs[1]=g_strdup(running_from);
1.189 + search_dirs[2]=g_strdup(g_get_user_config_dir());
1.190 + search_dirs[3]=NULL;
1.191 + }
1.192 + for(i=0;search_dirs[i];i++)
1.193 + {
1.194 + path=g_build_filename(search_dirs[i],"bookloupe.ini",NULL);
1.195 + if (g_key_file_load_from_file(kf,path,
1.196 + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS,&err))
1.197 + break;
1.198 + if (!g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT))
1.199 + {
1.200 + g_printerr("Bookloupe: Error reading %s\n",path);
1.201 + g_printerr("%s\n",err->message);
1.202 + exit(1);
1.203 + }
1.204 + g_clear_error(&err);
1.205 + g_free(path);
1.206 + path=NULL;
1.207 + }
1.208 + if (!search_dirs[i])
1.209 + {
1.210 + g_key_file_free(kf);
1.211 + kf=NULL;
1.212 + }
1.213 + g_strfreev(search_dirs);
1.214 + if (full_path && kf)
1.215 + *full_path=path;
1.216 + else
1.217 + g_free(path);
1.218 + return kf;
1.219 +}
1.220 +
1.221 +void parse_config_file(void)
1.222 +{
1.223 + int i,j;
1.224 + gchar *path;
1.225 + gchar **keys;
1.226 + gboolean sw;
1.227 + GError *err=NULL;
1.228 + config=read_config_file(&path);
1.229 + if (config)
1.230 + keys=g_key_file_get_keys(config,"options",NULL,NULL);
1.231 + else
1.232 + keys=NULL;
1.233 + if (keys)
1.234 + {
1.235 + for(i=0;keys[i];i++)
1.236 + {
1.237 + for(j=0;options[j].long_name;j++)
1.238 + {
1.239 + if (g_str_has_prefix(options[j].long_name,"no-"))
1.240 + continue;
1.241 + else if (!strcmp(keys[i],options[j].long_name))
1.242 + {
1.243 + if (options[j].arg==G_OPTION_ARG_NONE)
1.244 + {
1.245 + sw=g_key_file_get_boolean(config,"options",keys[i],
1.246 + &err);
1.247 + if (err)
1.248 + {
1.249 + g_printerr("Bookloupe: %s: options.%s: %s\n",
1.250 + path,keys[i],err->message);
1.251 + g_clear_error(&err);
1.252 + }
1.253 + if (options[j].flags&G_OPTION_FLAG_REVERSE)
1.254 + sw=!sw;
1.255 + *(gboolean *)options[j].arg_data=sw;
1.256 + break;
1.257 + }
1.258 + else
1.259 + g_assert_not_reached();
1.260 + }
1.261 + }
1.262 + if (!options[j].long_name)
1.263 + g_printerr("Bookloupe: %s: Unknown option \"%s\" ignored\n",
1.264 + path,keys[i]);
1.265 + }
1.266 + g_strfreev(keys);
1.267 + }
1.268 + if (config)
1.269 + g_free(path);
1.270 +}
1.271 +
1.272 void parse_options(int *argc,char ***argv)
1.273 {
1.274 GError *err=NULL;
1.275 GOptionContext *context;
1.276 + GOptionGroup *compatibility;
1.277 context=g_option_context_new(
1.278 - "file - looks for errors in Project Gutenberg(TM) etexts");
1.279 + "file - look for errors in Project Gutenberg(TM) etexts");
1.280 g_option_context_add_main_entries(context,options,NULL);
1.281 + g_option_context_add_main_entries(context,config_options,NULL);
1.282 + compatibility=g_option_group_new("compatibility",
1.283 + "Options for Compatibility with Gutcheck:",
1.284 + "Show compatibility options",NULL,NULL);
1.285 + g_option_group_add_entries(compatibility,compatibility_options);
1.286 + g_option_context_add_group(context,compatibility);
1.287 + g_option_context_set_description(context,
1.288 + "For simplicity, only the switch options which reverse the\n"
1.289 + "default configuration are listed. In most cases, both vanilla\n"
1.290 + "and \"no-\" prefixed versions are available for use.");
1.291 if (!g_option_context_parse(context,argc,argv,&err))
1.292 {
1.293 g_printerr("Bookloupe: %s\n",err->message);
1.294 g_printerr("Use \"%s --help\" for help\n",(*argv)[0]);
1.295 exit(1);
1.296 }
1.297 - /* Paranoid checking is turned OFF, not on, by its switch */
1.298 - pswit[PARANOID_SWITCH]=!pswit[PARANOID_SWITCH];
1.299 - if (pswit[PARANOID_SWITCH])
1.300 - /* if running in paranoid mode, typo checks default to enabled */
1.301 + if (typo_compat)
1.302 pswit[TYPO_SWITCH]=!pswit[TYPO_SWITCH];
1.303 - /* Line-end checking is turned OFF, not on, by its switch */
1.304 - pswit[LINE_END_SWITCH]=!pswit[LINE_END_SWITCH];
1.305 - /* Echoing is turned OFF, not on, by its switch */
1.306 - pswit[ECHO_SWITCH]=!pswit[ECHO_SWITCH];
1.307 - if (pswit[OVERVIEW_SWITCH])
1.308 - /* just print summary; don't echo */
1.309 - pswit[ECHO_SWITCH]=FALSE;
1.310 + if (paranoid_compat)
1.311 + {
1.312 + pswit[PARANOID_SWITCH]=!pswit[PARANOID_SWITCH];
1.313 + pswit[TYPO_SWITCH]=!pswit[TYPO_SWITCH];
1.314 + }
1.315 /*
1.316 * Web uploads - for the moment, this is really just a placeholder
1.317 * until we decide what processing we really want to do on web uploads
1.318 @@ -246,6 +475,14 @@
1.319 pswit[USERTYPO_SWITCH]=FALSE;
1.320 pswit[DP_SWITCH]=FALSE;
1.321 }
1.322 + if (pswit[DUMP_CONFIG_SWITCH])
1.323 + {
1.324 + dump_config();
1.325 + exit(0);
1.326 + }
1.327 + if (pswit[OVERVIEW_SWITCH])
1.328 + /* just print summary; don't echo */
1.329 + pswit[ECHO_SWITCH]=FALSE;
1.330 if (*argc<2)
1.331 {
1.332 proghelp(context);
1.333 @@ -388,6 +625,15 @@
1.334 saved_cp=GetConsoleOutputCP();
1.335 #endif
1.336 running_from=g_path_get_dirname(argv[0]);
1.337 + /* Paranoid checking is turned OFF, not on, by its switch */
1.338 + pswit[PARANOID_SWITCH]=TRUE;
1.339 + /* if running in paranoid mode, typo checks default to enabled */
1.340 + pswit[TYPO_SWITCH]=TRUE;
1.341 + /* Line-end checking is turned OFF, not on, by its switch */
1.342 + pswit[LINE_END_SWITCH]=TRUE;
1.343 + /* Echoing is turned OFF, not on, by its switch */
1.344 + pswit[ECHO_SWITCH]=TRUE;
1.345 + parse_config_file();
1.346 parse_options(&argc,&argv);
1.347 if (pswit[USERTYPO_SWITCH])
1.348 read_user_scannos();
1.349 @@ -428,6 +674,8 @@
1.350 g_free(running_from);
1.351 if (usertypo)
1.352 g_tree_unref(usertypo);
1.353 + if (config)
1.354 + g_key_file_free(config);
1.355 return 0;
1.356 }
1.357