1.1 --- a/Makefile.am Sun Sep 29 09:18:05 2013 +0100
1.2 +++ b/Makefile.am Mon Sep 30 08:18:42 2013 +0100
1.3 @@ -1,1 +1,3 @@
1.4 SUBDIRS=bl bookloupe test doc
1.5 +
1.6 +dist_pkgdata_DATA=sample.ini
2.1 --- a/bookloupe/bookloupe.c Sun Sep 29 09:18:05 2013 +0100
2.2 +++ b/bookloupe/bookloupe.c Mon Sep 30 08:18:42 2013 +0100
2.3 @@ -132,37 +132,99 @@
2.4 gboolean pswit[SWITNO]; /* program switches */
2.5 gchar *opt_charset;
2.6
2.7 +gboolean typo_compat,paranoid_compat;
2.8 +
2.9 static GOptionEntry options[]={
2.10 { "dp", 'd', 0, G_OPTION_ARG_NONE, pswit+DP_SWITCH,
2.11 "Ignore DP-specific markup", NULL },
2.12 - { "noecho", 'e', 0, G_OPTION_ARG_NONE, pswit+ECHO_SWITCH,
2.13 + { "no-dp", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.14 + G_OPTION_ARG_NONE, pswit+DP_SWITCH,
2.15 + "Don't ignore DP-specific markup", NULL },
2.16 + { "echo", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, pswit+ECHO_SWITCH,
2.17 + "Echo queried line", NULL },
2.18 + { "no-echo", 'e', G_OPTION_FLAG_REVERSE,
2.19 + G_OPTION_ARG_NONE, pswit+ECHO_SWITCH,
2.20 "Don't echo queried line", NULL },
2.21 { "squote", 's', 0, G_OPTION_ARG_NONE, pswit+SQUOTE_SWITCH,
2.22 "Check single quotes", NULL },
2.23 - { "typo", 't', 0, G_OPTION_ARG_NONE, pswit+TYPO_SWITCH,
2.24 + { "no-squote", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.25 + G_OPTION_ARG_NONE, pswit+SQUOTE_SWITCH,
2.26 + "Don't check single quotes", NULL },
2.27 + { "typo", 0, 0, G_OPTION_ARG_NONE, pswit+TYPO_SWITCH,
2.28 "Check common typos", NULL },
2.29 + { "no-typo", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.30 + G_OPTION_ARG_NONE, pswit+TYPO_SWITCH,
2.31 + "Don't check common typos", NULL },
2.32 { "qpara", 'p', 0, G_OPTION_ARG_NONE, pswit+QPARA_SWITCH,
2.33 "Require closure of quotes on every paragraph", NULL },
2.34 - { "relaxed", 'x', 0, G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH,
2.35 + { "no-qpara", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.36 + G_OPTION_ARG_NONE, pswit+QPARA_SWITCH,
2.37 + "Don't require closure of quotes on every paragraph", NULL },
2.38 + { "paranoid", 0, G_OPTION_FLAG_HIDDEN,
2.39 + G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH,
2.40 + "Enable paranoid querying of everything", NULL },
2.41 + { "no-paranoid", 0, G_OPTION_FLAG_REVERSE,
2.42 + G_OPTION_ARG_NONE, pswit+PARANOID_SWITCH,
2.43 "Disable paranoid querying of everything", NULL },
2.44 - { "line-end", 'l', 0, G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH,
2.45 - "Disable line end checking", NULL },
2.46 + { "line-end", 0, G_OPTION_FLAG_HIDDEN,
2.47 + G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH,
2.48 + "Enable line end checking", NULL },
2.49 + { "no-line-end", 'l', G_OPTION_FLAG_REVERSE,
2.50 + G_OPTION_ARG_NONE, pswit+LINE_END_SWITCH,
2.51 + "Diable line end checking", NULL },
2.52 { "overview", 'o', 0, G_OPTION_ARG_NONE, pswit+OVERVIEW_SWITCH,
2.53 "Overview: just show counts", NULL },
2.54 + { "no-overview", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.55 + G_OPTION_ARG_NONE, pswit+OVERVIEW_SWITCH,
2.56 + "Show individual warnings", NULL },
2.57 { "stdout", 'y', 0, G_OPTION_ARG_NONE, pswit+STDOUT_SWITCH,
2.58 "Output errors to stdout instead of stderr", NULL },
2.59 + { "no-stdout", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.60 + G_OPTION_ARG_NONE, pswit+STDOUT_SWITCH,
2.61 + "Output errors to stderr instead of stdout", NULL },
2.62 { "header", 'h', 0, G_OPTION_ARG_NONE, pswit+HEADER_SWITCH,
2.63 "Echo header fields", NULL },
2.64 + { "no-header", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.65 + G_OPTION_ARG_NONE, pswit+HEADER_SWITCH,
2.66 + "Don't echo header fields", NULL },
2.67 { "markup", 'm', 0, G_OPTION_ARG_NONE, pswit+MARKUP_SWITCH,
2.68 "Ignore markup in < >", NULL },
2.69 + { "no-markup", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.70 + G_OPTION_ARG_NONE, pswit+MARKUP_SWITCH,
2.71 + "No special handling for markup in < >", NULL },
2.72 { "usertypo", 'u', 0, G_OPTION_ARG_NONE, pswit+USERTYPO_SWITCH,
2.73 "Use file of user-defined typos", NULL },
2.74 + { "no-usertypo", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.75 + G_OPTION_ARG_NONE, pswit+USERTYPO_SWITCH,
2.76 + "Ignore file of user-defined typos", NULL },
2.77 + { "verbose", 'v', 0, G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH,
2.78 + "Verbose - list everything", NULL },
2.79 + { "no-verbose", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_REVERSE,
2.80 + G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH,
2.81 + "Switch off verbose mode", NULL },
2.82 + { "charset", 0, 0, G_OPTION_ARG_STRING, &opt_charset,
2.83 + "Set of characters valid for this ebook", "NAME" },
2.84 + { NULL }
2.85 +};
2.86 +
2.87 +/*
2.88 + * Options relating to configuration which make no sense from inside
2.89 + * a configuration file.
2.90 + */
2.91 +
2.92 +static GOptionEntry config_options[]={
2.93 { "web", 'w', 0, G_OPTION_ARG_NONE, pswit+WEB_SWITCH,
2.94 "Defaults for use on www upload", NULL },
2.95 - { "verbose", 'v', 0, G_OPTION_ARG_NONE, pswit+VERBOSE_SWITCH,
2.96 - "Verbose - list everything", NULL },
2.97 - { "charset", 0, 0, G_OPTION_ARG_STRING, &opt_charset,
2.98 - "Set of characters valid for this ebook", "NAME" },
2.99 + { "dump-config", 0, 0, G_OPTION_ARG_NONE, pswit+DUMP_CONFIG_SWITCH,
2.100 + "Dump current config settings", NULL },
2.101 + { NULL }
2.102 +};
2.103 +
2.104 +static GOptionEntry compatibility_options[]={
2.105 + { "toggle-typo", 't', 0, G_OPTION_ARG_NONE, &typo_compat,
2.106 + "Toggle checking for common typos", NULL },
2.107 + { "toggle-relaxed", 'x', 0, G_OPTION_ARG_NONE, ¶noid_compat,
2.108 + "Toggle both paranoid mode and common typos", NULL },
2.109 { NULL }
2.110 };
2.111
2.112 @@ -249,31 +311,232 @@
2.113 return TRUE;
2.114 }
2.115
2.116 +GKeyFile *config;
2.117 +
2.118 +void config_file_update(GKeyFile *kf)
2.119 +{
2.120 + int i;
2.121 + const char *s;
2.122 + gboolean sw;
2.123 + for(i=0;options[i].long_name;i++)
2.124 + {
2.125 + if (g_str_has_prefix(options[i].long_name,"no-"))
2.126 + continue;
2.127 + if (options[i].arg==G_OPTION_ARG_NONE)
2.128 + {
2.129 + sw=*(gboolean *)options[i].arg_data;
2.130 + if (options[i].flags&G_OPTION_FLAG_REVERSE)
2.131 + sw=!sw;
2.132 + g_key_file_set_boolean(kf,"options",options[i].long_name,sw);
2.133 + }
2.134 + else if (options[i].arg==G_OPTION_ARG_STRING)
2.135 + {
2.136 + s=*(gchar **)options[i].arg_data;
2.137 + if (!s)
2.138 + s="auto";
2.139 + g_key_file_set_string(kf,"options",options[i].long_name,s);
2.140 + }
2.141 + else
2.142 + g_assert_not_reached();
2.143 + }
2.144 +}
2.145 +
2.146 +void config_file_add_comments(GKeyFile *kf)
2.147 +{
2.148 + int i;
2.149 + gchar *comment;
2.150 + g_key_file_set_comment(kf,NULL,NULL," Default configuration for bookloupe",
2.151 + NULL);
2.152 + for(i=0;options[i].long_name;i++)
2.153 + {
2.154 + if (g_str_has_prefix(options[i].long_name,"no-"))
2.155 + continue;
2.156 + comment=g_strconcat(" ",options[i].description,NULL);
2.157 + g_key_file_set_comment(kf,"options",options[i].long_name,comment,NULL);
2.158 + g_free(comment);
2.159 + }
2.160 +}
2.161 +
2.162 +void dump_config(void)
2.163 +{
2.164 + gchar *s;
2.165 + if (config)
2.166 + config_file_update(config);
2.167 + else
2.168 + {
2.169 + config=g_key_file_new();
2.170 + config_file_update(config);
2.171 + config_file_add_comments(config);
2.172 + }
2.173 + s=g_key_file_to_data(config,NULL,NULL);
2.174 + if (s)
2.175 + g_print("%s",s);
2.176 + g_free(s);
2.177 +}
2.178 +
2.179 +GKeyFile *read_config_file(gchar **full_path)
2.180 +{
2.181 + int i;
2.182 + GError *err=NULL;
2.183 + gchar **search_dirs;
2.184 + gchar *path;
2.185 + const char *search_path;
2.186 + GKeyFile *kf;
2.187 + kf=g_key_file_new();
2.188 + search_path=g_getenv("BOOKLOUPE_CONFIG_PATH");
2.189 + if (search_path)
2.190 + {
2.191 +#ifdef __WIN32__
2.192 + search_dirs=g_strsplit(search_path,";",0);
2.193 +#else
2.194 + search_dirs=g_strsplit(search_path,":",0);
2.195 +#endif
2.196 + }
2.197 + else
2.198 + {
2.199 + search_dirs=g_new(gchar *,4);
2.200 + search_dirs[0]=g_get_current_dir();
2.201 + search_dirs[1]=g_strdup(running_from);
2.202 + search_dirs[2]=g_strdup(g_get_user_config_dir());
2.203 + search_dirs[3]=NULL;
2.204 + }
2.205 + for(i=0;search_dirs[i];i++)
2.206 + {
2.207 + path=g_build_filename(search_dirs[i],"bookloupe.ini",NULL);
2.208 + if (g_key_file_load_from_file(kf,path,
2.209 + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS,&err))
2.210 + break;
2.211 + if (!g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT))
2.212 + {
2.213 + g_printerr("Bookloupe: Error reading %s\n",path);
2.214 + g_printerr("%s\n",err->message);
2.215 + exit(1);
2.216 + }
2.217 + g_clear_error(&err);
2.218 + g_free(path);
2.219 + path=NULL;
2.220 + }
2.221 + if (!search_dirs[i])
2.222 + {
2.223 + g_key_file_free(kf);
2.224 + kf=NULL;
2.225 + }
2.226 + g_strfreev(search_dirs);
2.227 + if (full_path && kf)
2.228 + *full_path=path;
2.229 + else
2.230 + g_free(path);
2.231 + return kf;
2.232 +}
2.233 +
2.234 +void parse_config_file(void)
2.235 +{
2.236 + int i,j;
2.237 + gchar *path,*s;
2.238 + gchar **keys;
2.239 + gboolean sw;
2.240 + GError *err=NULL;
2.241 + config=read_config_file(&path);
2.242 + if (config)
2.243 + keys=g_key_file_get_keys(config,"options",NULL,NULL);
2.244 + else
2.245 + keys=NULL;
2.246 + if (keys)
2.247 + {
2.248 + for(i=0;keys[i];i++)
2.249 + {
2.250 + for(j=0;options[j].long_name;j++)
2.251 + {
2.252 + if (g_str_has_prefix(options[j].long_name,"no-"))
2.253 + continue;
2.254 + else if (!strcmp(keys[i],options[j].long_name))
2.255 + {
2.256 + if (options[j].arg==G_OPTION_ARG_NONE)
2.257 + {
2.258 + sw=g_key_file_get_boolean(config,"options",keys[i],
2.259 + &err);
2.260 + if (err)
2.261 + {
2.262 + g_printerr("Bookloupe: %s: options.%s: %s\n",
2.263 + path,keys[i],err->message);
2.264 + g_clear_error(&err);
2.265 + }
2.266 + else
2.267 + {
2.268 + if (options[j].flags&G_OPTION_FLAG_REVERSE)
2.269 + sw=!sw;
2.270 + *(gboolean *)options[j].arg_data=sw;
2.271 + }
2.272 + break;
2.273 + }
2.274 + else if (options[j].arg==G_OPTION_ARG_STRING)
2.275 + {
2.276 + s=g_key_file_get_string(config,"options",keys[i],
2.277 + &err);
2.278 + if (err)
2.279 + {
2.280 + g_printerr("Bookloupe: %s: options.%s: %s\n",
2.281 + path,keys[i],err->message);
2.282 + g_clear_error(&err);
2.283 + }
2.284 + else
2.285 + {
2.286 + g_free(*(gchar **)options[j].arg_data);
2.287 + if (!g_strcmp0(s,"auto"))
2.288 + {
2.289 + *(gchar **)options[j].arg_data=NULL;
2.290 + g_free(s);
2.291 + }
2.292 + else
2.293 + *(gchar **)options[j].arg_data=s;
2.294 + }
2.295 + break;
2.296 + }
2.297 + else
2.298 + g_assert_not_reached();
2.299 + }
2.300 + }
2.301 + if (!options[j].long_name)
2.302 + g_printerr("Bookloupe: %s: Unknown option \"%s\" ignored\n",
2.303 + path,keys[i]);
2.304 + }
2.305 + g_strfreev(keys);
2.306 + }
2.307 + if (config)
2.308 + g_free(path);
2.309 +}
2.310 +
2.311 void parse_options(int *argc,char ***argv)
2.312 {
2.313 GError *err=NULL;
2.314 GOptionContext *context;
2.315 + GOptionGroup *compatibility;
2.316 context=g_option_context_new(
2.317 - "file - looks for errors in Project Gutenberg(TM) etexts");
2.318 + "file - look for errors in Project Gutenberg(TM) etexts");
2.319 g_option_context_add_main_entries(context,options,NULL);
2.320 + g_option_context_add_main_entries(context,config_options,NULL);
2.321 + compatibility=g_option_group_new("compatibility",
2.322 + "Options for Compatibility with Gutcheck:",
2.323 + "Show compatibility options",NULL,NULL);
2.324 + g_option_group_add_entries(compatibility,compatibility_options);
2.325 + g_option_context_add_group(context,compatibility);
2.326 + g_option_context_set_description(context,
2.327 + "For simplicity, only the switch options which reverse the\n"
2.328 + "default configuration are listed. In most cases, both vanilla\n"
2.329 + "and \"no-\" prefixed versions are available for use.");
2.330 if (!g_option_context_parse(context,argc,argv,&err))
2.331 {
2.332 g_printerr("Bookloupe: %s\n",err->message);
2.333 g_printerr("Use \"%s --help\" for help\n",(*argv)[0]);
2.334 exit(1);
2.335 }
2.336 - /* Paranoid checking is turned OFF, not on, by its switch */
2.337 - pswit[PARANOID_SWITCH]=!pswit[PARANOID_SWITCH];
2.338 - if (pswit[PARANOID_SWITCH])
2.339 - /* if running in paranoid mode, typo checks default to enabled */
2.340 + if (typo_compat)
2.341 pswit[TYPO_SWITCH]=!pswit[TYPO_SWITCH];
2.342 - /* Line-end checking is turned OFF, not on, by its switch */
2.343 - pswit[LINE_END_SWITCH]=!pswit[LINE_END_SWITCH];
2.344 - /* Echoing is turned OFF, not on, by its switch */
2.345 - pswit[ECHO_SWITCH]=!pswit[ECHO_SWITCH];
2.346 - if (pswit[OVERVIEW_SWITCH])
2.347 - /* just print summary; don't echo */
2.348 - pswit[ECHO_SWITCH]=FALSE;
2.349 + if (paranoid_compat)
2.350 + {
2.351 + pswit[PARANOID_SWITCH]=!pswit[PARANOID_SWITCH];
2.352 + pswit[TYPO_SWITCH]=!pswit[TYPO_SWITCH];
2.353 + }
2.354 /*
2.355 * Web uploads - for the moment, this is really just a placeholder
2.356 * until we decide what processing we really want to do on web uploads
2.357 @@ -300,8 +563,16 @@
2.358 g_printerr("%s\n",err->message);
2.359 exit(1);
2.360 }
2.361 + if (pswit[DUMP_CONFIG_SWITCH])
2.362 + {
2.363 + dump_config();
2.364 + exit(0);
2.365 + }
2.366 g_free(opt_charset);
2.367 opt_charset=NULL;
2.368 + if (pswit[OVERVIEW_SWITCH])
2.369 + /* just print summary; don't echo */
2.370 + pswit[ECHO_SWITCH]=FALSE;
2.371 if (*argc<2)
2.372 {
2.373 proghelp(context);
2.374 @@ -448,6 +719,15 @@
2.375 saved_cp=GetConsoleOutputCP();
2.376 #endif
2.377 running_from=g_path_get_dirname(argv[0]);
2.378 + /* Paranoid checking is turned OFF, not on, by its switch */
2.379 + pswit[PARANOID_SWITCH]=TRUE;
2.380 + /* if running in paranoid mode, typo checks default to enabled */
2.381 + pswit[TYPO_SWITCH]=TRUE;
2.382 + /* Line-end checking is turned OFF, not on, by its switch */
2.383 + pswit[LINE_END_SWITCH]=TRUE;
2.384 + /* Echoing is turned OFF, not on, by its switch */
2.385 + pswit[ECHO_SWITCH]=TRUE;
2.386 + parse_config_file();
2.387 parse_options(&argc,&argv);
2.388 if (pswit[USERTYPO_SWITCH])
2.389 read_user_scannos();
2.390 @@ -489,6 +769,8 @@
2.391 if (usertypo)
2.392 g_tree_unref(usertypo);
2.393 set_charset(NULL,NULL);
2.394 + if (config)
2.395 + g_key_file_free(config);
2.396 return 0;
2.397 }
2.398
3.1 --- a/bookloupe/bookloupe.h Sun Sep 29 09:18:05 2013 +0100
3.2 +++ b/bookloupe/bookloupe.h Mon Sep 30 08:18:42 2013 +0100
3.3 @@ -55,6 +55,7 @@
3.4 MARKUP_SWITCH,
3.5 USERTYPO_SWITCH,
3.6 DP_SWITCH,
3.7 + DUMP_CONFIG_SWITCH,
3.8 SWITNO
3.9 };
3.10
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/sample.ini Mon Sep 30 08:18:42 2013 +0100
4.3 @@ -0,0 +1,33 @@
4.4 +# Default configuration for bookloupe
4.5 +
4.6 +[options]
4.7 +# Ignore DP-specific markup
4.8 +dp=false
4.9 +# Echo queried line
4.10 +echo=true
4.11 +# Check single quotes
4.12 +squote=false
4.13 +# Check common typos
4.14 +typo=true
4.15 +# Require closure of quotes on every paragraph
4.16 +qpara=false
4.17 +# Enable paranoid querying of everything
4.18 +paranoid=true
4.19 +# Enable line end checking
4.20 +line-end=true
4.21 +# Overview: just show counts
4.22 +overview=false
4.23 +# Output errors to stdout instead of stderr
4.24 +stdout=false
4.25 +# Echo header fields
4.26 +header=false
4.27 +# Ignore markup in < >
4.28 +markup=false
4.29 +# Use file of user-defined typos
4.30 +usertypo=false
4.31 +# Defaults for use on www upload
4.32 +web=false
4.33 +# Verbose - list everything
4.34 +verbose=false
4.35 +# Set of characters valid for this ebook
4.36 +charset=auto
5.1 --- a/test/bookloupe/Makefile.am Sun Sep 29 09:18:05 2013 +0100
5.2 +++ b/test/bookloupe/Makefile.am Mon Sep 30 08:18:42 2013 +0100
5.3 @@ -1,6 +1,7 @@
5.4 TESTS_ENVIRONMENT=BOOKLOUPE=../../bookloupe/bookloupe ../harness/loupe-test
5.5 TESTS=non-ascii.tst long-line.tst curved-single-quotes.tst curved-quotes.tst \
5.6 runfox-quotes.tst curved-genitives.tst multi-line-illustration.tst \
5.7 - charset-cp1252.tst charset-latin1.tst
5.8 + config-internal.tst config-default.tst config-user.tst \
5.9 + config-override.tst charset-cp1252.tst charset-latin1.tst
5.10
5.11 dist_pkgdata_DATA=$(TESTS)
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/test/bookloupe/config-default.tst Mon Sep 30 08:18:42 2013 +0100
6.3 @@ -0,0 +1,66 @@
6.4 +**************** OPTIONS ****************
6.5 +--dump-config
6.6 +**************** INPUT(bookloupe.ini) ****************
6.7 +# Default configuration for bookloupe
6.8 +
6.9 +[options]
6.10 +# Ignore DP-specific markup
6.11 +dp=false
6.12 +# Echo queried line
6.13 +echo=true
6.14 +# Check single quotes
6.15 +squote=false
6.16 +# Check common typos
6.17 +typo=true
6.18 +# Require closure of quotes on every paragraph
6.19 +qpara=false
6.20 +# Enable paranoid querying of everything
6.21 +paranoid=true
6.22 +# Enable line end checking
6.23 +line-end=true
6.24 +# Overview: just show counts
6.25 +overview=false
6.26 +# Output errors to stdout instead of stderr
6.27 +stdout=false
6.28 +# Echo header fields
6.29 +header=false
6.30 +# Ignore markup in < >
6.31 +markup=false
6.32 +# Use file of user-defined typos
6.33 +usertypo=false
6.34 +# Verbose - list everything
6.35 +verbose=false
6.36 +# Set of characters valid for this ebook
6.37 +charset=auto
6.38 +**************** EXPECTED(stdout) ****************
6.39 +# Default configuration for bookloupe
6.40 +
6.41 +[options]
6.42 +# Ignore DP-specific markup
6.43 +dp=false
6.44 +# Echo queried line
6.45 +echo=true
6.46 +# Check single quotes
6.47 +squote=false
6.48 +# Check common typos
6.49 +typo=true
6.50 +# Require closure of quotes on every paragraph
6.51 +qpara=false
6.52 +# Enable paranoid querying of everything
6.53 +paranoid=true
6.54 +# Enable line end checking
6.55 +line-end=true
6.56 +# Overview: just show counts
6.57 +overview=false
6.58 +# Output errors to stdout instead of stderr
6.59 +stdout=false
6.60 +# Echo header fields
6.61 +header=false
6.62 +# Ignore markup in < >
6.63 +markup=false
6.64 +# Use file of user-defined typos
6.65 +usertypo=false
6.66 +# Verbose - list everything
6.67 +verbose=false
6.68 +# Set of characters valid for this ebook
6.69 +charset=auto
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/test/bookloupe/config-internal.tst Mon Sep 30 08:18:42 2013 +0100
7.3 @@ -0,0 +1,34 @@
7.4 +**************** OPTIONS ****************
7.5 +--dump-config
7.6 +**************** EXPECTED(stdout) ****************
7.7 +# Default configuration for bookloupe
7.8 +
7.9 +[options]
7.10 +# Ignore DP-specific markup
7.11 +dp=false
7.12 +# Echo queried line
7.13 +echo=true
7.14 +# Check single quotes
7.15 +squote=false
7.16 +# Check common typos
7.17 +typo=true
7.18 +# Require closure of quotes on every paragraph
7.19 +qpara=false
7.20 +# Enable paranoid querying of everything
7.21 +paranoid=true
7.22 +# Enable line end checking
7.23 +line-end=true
7.24 +# Overview: just show counts
7.25 +overview=false
7.26 +# Output errors to stdout instead of stderr
7.27 +stdout=false
7.28 +# Echo header fields
7.29 +header=false
7.30 +# Ignore markup in < >
7.31 +markup=false
7.32 +# Use file of user-defined typos
7.33 +usertypo=false
7.34 +# Verbose - list everything
7.35 +verbose=false
7.36 +# Set of characters valid for this ebook
7.37 +charset=auto
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/test/bookloupe/config-override.tst Mon Sep 30 08:18:42 2013 +0100
8.3 @@ -0,0 +1,68 @@
8.4 +**************** OPTIONS ****************
8.5 +--usertypo
8.6 +--charset=auto
8.7 +--dump-config
8.8 +**************** INPUT(bookloupe.ini) ****************
8.9 +# Relaxed configuration for bookloupe
8.10 +
8.11 +[options]
8.12 +# Ignore DP-specific markup
8.13 +dp=false
8.14 +# Echo queried line
8.15 +echo=true
8.16 +# Check single quotes
8.17 +squote=false
8.18 +# Check common typos
8.19 +typo=true
8.20 +# Require closure of quotes on every paragraph
8.21 +qpara=false
8.22 +# Enable paranoid querying of everything
8.23 +paranoid=false
8.24 +# Enable line end checking
8.25 +line-end=true
8.26 +# Overview: just show counts
8.27 +overview=false
8.28 +# Output errors to stdout instead of stderr
8.29 +stdout=false
8.30 +# Echo header fields
8.31 +header=false
8.32 +# Ignore markup in < >
8.33 +markup=false
8.34 +# Use file of user-defined typos
8.35 +usertypo=false
8.36 +# Verbose - list everything
8.37 +verbose=false
8.38 +# Set of characters valid for this ebook
8.39 +charset=UNICODE
8.40 +**************** EXPECTED(stdout) ****************
8.41 +# Relaxed configuration for bookloupe
8.42 +
8.43 +[options]
8.44 +# Ignore DP-specific markup
8.45 +dp=false
8.46 +# Echo queried line
8.47 +echo=true
8.48 +# Check single quotes
8.49 +squote=false
8.50 +# Check common typos
8.51 +typo=true
8.52 +# Require closure of quotes on every paragraph
8.53 +qpara=false
8.54 +# Enable paranoid querying of everything
8.55 +paranoid=false
8.56 +# Enable line end checking
8.57 +line-end=true
8.58 +# Overview: just show counts
8.59 +overview=false
8.60 +# Output errors to stdout instead of stderr
8.61 +stdout=false
8.62 +# Echo header fields
8.63 +header=false
8.64 +# Ignore markup in < >
8.65 +markup=false
8.66 +# Use file of user-defined typos
8.67 +usertypo=true
8.68 +# Verbose - list everything
8.69 +verbose=false
8.70 +# Set of characters valid for this ebook
8.71 +charset=auto
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/test/bookloupe/config-user.tst Mon Sep 30 08:18:42 2013 +0100
9.3 @@ -0,0 +1,76 @@
9.4 +**************** OPTIONS ****************
9.5 +--dump-config
9.6 +**************** INPUT(bookloupe.ini) ****************
9.7 +# Mary Contrary's configuration for bookloupe
9.8 +
9.9 +# Bookloupe will ignore this group, but it's nice to have.
9.10 +[other]
9.11 +# Look at me!
9.12 +name="Mary Contrary"
9.13 +
9.14 +[options]
9.15 +# Ignore DP-specific markup - sounds useful
9.16 +dp=true
9.17 +# Echo queried line - what's the point of that?
9.18 +echo=false
9.19 +# Check single quotes - yup
9.20 +squote=true
9.21 +# Check common typos - waste of time
9.22 +typo=false
9.23 +# Require closure of quotes on every paragraph - okay
9.24 +qpara=true
9.25 +# Enable paranoid querying of everything - Huh?
9.26 +paranoid=false
9.27 +# Enable line end checking - pointless
9.28 +line-end=false
9.29 +# Overview: just show counts - Brief is good
9.30 +overview=true
9.31 +# Output errors to stdout instead of stderr - keeps things together
9.32 +stdout=true
9.33 +# Echo header fields - I'd rather see it
9.34 +header=true
9.35 +# Ignore markup in < > - Need this
9.36 +markup=true
9.37 +# Use file of user-defined typos - And this
9.38 +usertypo=true
9.39 +# Verbose - list everything - Contrary by name...
9.40 +verbose=true
9.41 +# Set of characters valid for this ebook - Let's stick with Latin1
9.42 +charset=ISO-8859-1
9.43 +**************** EXPECTED(stdout) ****************
9.44 +# Mary Contrary's configuration for bookloupe
9.45 +
9.46 +# Bookloupe will ignore this group, but it's nice to have.
9.47 +[other]
9.48 +# Look at me!
9.49 +name="Mary Contrary"
9.50 +
9.51 +[options]
9.52 +# Ignore DP-specific markup - sounds useful
9.53 +dp=true
9.54 +# Echo queried line - what's the point of that?
9.55 +echo=false
9.56 +# Check single quotes - yup
9.57 +squote=true
9.58 +# Check common typos - waste of time
9.59 +typo=false
9.60 +# Require closure of quotes on every paragraph - okay
9.61 +qpara=true
9.62 +# Enable paranoid querying of everything - Huh?
9.63 +paranoid=false
9.64 +# Enable line end checking - pointless
9.65 +line-end=false
9.66 +# Overview: just show counts - Brief is good
9.67 +overview=true
9.68 +# Output errors to stdout instead of stderr - keeps things together
9.69 +stdout=true
9.70 +# Echo header fields - I'd rather see it
9.71 +header=true
9.72 +# Ignore markup in < > - Need this
9.73 +markup=true
9.74 +# Use file of user-defined typos - And this
9.75 +usertypo=true
9.76 +# Verbose - list everything - Contrary by name...
9.77 +verbose=true
9.78 +# Set of characters valid for this ebook - Let's stick with Latin1
9.79 +charset=ISO-8859-1
10.1 --- a/test/compatibility/Makefile.am Sun Sep 29 09:18:05 2013 +0100
10.2 +++ b/test/compatibility/Makefile.am Mon Sep 30 08:18:42 2013 +0100
10.3 @@ -6,6 +6,7 @@
10.4 user-defined-typo.tst brackets.tst single-quotes.tst grave-quotes.tst \
10.5 dashes.tst control-characters.tst unusual-characters.tst \
10.6 windows-1252.tst periods.tst long-line.tst unmarked-paragraph.tst \
10.7 + paranoid.tst paranoid-typos.tst no-paranoid.tst no-paranoid-typos.tst \
10.8 hebe-jeebies.tst mail-from.tst scannos.tst before-comma.tst \
10.9 before-period.tst double-punctuation.tst genitives.tst embedded-cr.tst \
10.10 continuing-quotes.tst
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/test/compatibility/no-paranoid-typos.tst Mon Sep 30 08:18:42 2013 +0100
11.3 @@ -0,0 +1,12 @@
11.4 +**************** OPTIONS ****************
11.5 +-x
11.6 +-t
11.7 +**************** INPUT ****************
11.8 +In paranoid mode we check for a standalone digits. 1 think this is a useful
11.9 +feature. When checking for typos every, strangly placed comma is reported.
11.10 +
11.11 +If paranoid mode is switched off, we can still check for typos.
11.12 +**************** EXPECTED ****************
11.13 +
11.14 +feature. When checking for typos every, strangly placed comma is reported.
11.15 + Line 2 column 39 - Query punctuation after every?
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/test/compatibility/no-paranoid.tst Mon Sep 30 08:18:42 2013 +0100
12.3 @@ -0,0 +1,8 @@
12.4 +**************** OPTIONS ****************
12.5 +-x
12.6 +**************** INPUT ****************
12.7 +In paranoid mode we check for a standalone digits. 1 think this is a useful
12.8 +feature. When checking for typos every, strangly placed comma is reported.
12.9 +
12.10 +If paranoid mode is switched off, checking for typos defaults to off too.
12.11 +**************** EXPECTED ****************
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/test/compatibility/paranoid-typos.tst Mon Sep 30 08:18:42 2013 +0100
13.3 @@ -0,0 +1,12 @@
13.4 +**************** OPTIONS ****************
13.5 +-t
13.6 +**************** INPUT ****************
13.7 +In paranoid mode we check for a standalone digits. 1 think this is a useful
13.8 +feature. When checking for typos every, strangly placed comma is reported.
13.9 +
13.10 +In paranoid mode (the default), typo checking is switched off with its
13.11 +short option.
13.12 +**************** EXPECTED ****************
13.13 +
13.14 +In paranoid mode we check for a standalone digits. 1 think this is a useful
13.15 + Line 1 column 51 - Query standalone 1
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/test/compatibility/paranoid.tst Mon Sep 30 08:18:42 2013 +0100
14.3 @@ -0,0 +1,12 @@
14.4 +**************** INPUT ****************
14.5 +In paranoid mode we check for a standalone digits. 1 think this is a useful
14.6 +feature. When checking for typos every, strangly placed comma is reported.
14.7 +
14.8 +By default, both paranoid mode and checking for typos should be on.
14.9 +**************** EXPECTED ****************
14.10 +
14.11 +In paranoid mode we check for a standalone digits. 1 think this is a useful
14.12 + Line 1 column 51 - Query standalone 1
14.13 +
14.14 +feature. When checking for typos every, strangly placed comma is reported.
14.15 + Line 2 column 39 - Query punctuation after every?
15.1 --- a/test/harness/Makefile.am Sun Sep 29 09:18:05 2013 +0100
15.2 +++ b/test/harness/Makefile.am Mon Sep 30 08:18:42 2013 +0100
15.3 @@ -5,5 +5,6 @@
15.4
15.5 loupe_test_SOURCES=loupe-test.c testcase.c testcase.h testcaseio.c \
15.6 testcaseio.h testcaseparser.c testcaseparser.h testcaseinput.c \
15.7 - testcaseinput.h warningsparser.c warningsparser.h
15.8 + testcaseinput.h testcaseoutput.c testcaseoutput.h warningsparser.c \
15.9 + warningsparser.h
15.10 loupe_test_LDADD=../../bl/libbl.la
16.1 --- a/test/harness/loupe-test.c Sun Sep 29 09:18:05 2013 +0100
16.2 +++ b/test/harness/loupe-test.c Mon Sep 30 08:18:42 2013 +0100
16.3 @@ -27,6 +27,7 @@
16.4 int i;
16.5 gboolean pass=TRUE;
16.6 bl_set_print_handlers();
16.7 + g_setenv("BOOKLOUPE_CONFIG_PATH",".",TRUE);
16.8 for(i=1;i<argc;i++)
16.9 pass&=run_test(argv[i]);
16.10 return pass?0:1;
17.1 --- a/test/harness/testcase.c Sun Sep 29 09:18:05 2013 +0100
17.2 +++ b/test/harness/testcase.c Mon Sep 30 08:18:42 2013 +0100
17.3 @@ -7,6 +7,7 @@
17.4 #include <bl/bl.h>
17.5 #include "testcase.h"
17.6 #include "testcaseinput.h"
17.7 +#include "testcaseoutput.h"
17.8
17.9 GQuark testcase_error_quark(void)
17.10 {
17.11 @@ -171,6 +172,64 @@
17.12 return g_string_free(filename,FALSE);
17.13 }
17.14
17.15 +/*
17.16 + * Verify that all the output files specified by a testcase are present
17.17 + * with the expected contents.
17.18 + */
17.19 +gboolean testcase_verify_output_files(Testcase *testcase)
17.20 +{
17.21 + GSList *link;
17.22 + GError *tmp_err=NULL;
17.23 + gboolean retval=TRUE;
17.24 + ssize_t offset;
17.25 + gchar *contents;
17.26 + TestcaseOutput *output;
17.27 + for(link=testcase->outputs;link;link=link->next)
17.28 + {
17.29 + output=link->data;
17.30 + if (!testcase_output_read(testcase,output,&contents,NULL,&tmp_err))
17.31 + {
17.32 + g_print("%s: FAIL\n",testcase->basename);
17.33 + g_print("%s\n",tmp_err->message);
17.34 + g_clear_error(&tmp_err);
17.35 + retval=FALSE;
17.36 + break;
17.37 + }
17.38 + else
17.39 + {
17.40 + if (strcmp(contents,output->contents))
17.41 + {
17.42 + g_print("%s: FAIL\n",testcase->basename);
17.43 + offset=common_prefix_length(contents,output->contents);
17.44 + if (!offset && !contents[offset])
17.45 + g_print("%s: Unexpected empty output from bookloupe.\n",
17.46 + output->name);
17.47 + else
17.48 + {
17.49 + g_print("%s: Unexpected output from bookloupe:\n",
17.50 + output->name);
17.51 + print_unexpected(contents,offset);
17.52 + }
17.53 + retval=FALSE;
17.54 + }
17.55 + g_free(contents);
17.56 + break;
17.57 + }
17.58 + }
17.59 + for(link=testcase->outputs;link;link=link->next)
17.60 + if (!testcase_output_remove(testcase,link->data,&tmp_err))
17.61 + {
17.62 + if (retval)
17.63 + {
17.64 + g_print("%s: FAIL\n",testcase->basename);
17.65 + g_print("%s\n",tmp_err->message);
17.66 + retval=TRUE;
17.67 + }
17.68 + g_clear_error(&tmp_err);
17.69 + }
17.70 + return retval;
17.71 +}
17.72 +
17.73 gboolean testcase_spawn_bookloupe(Testcase *testcase,char **standard_output,
17.74 GError **error)
17.75 {
17.76 @@ -460,7 +519,7 @@
17.77 gboolean r;
17.78 size_t pos,offset;
17.79 GString *header;
17.80 - char *output,*filename,*s,*xfail=NULL;
17.81 + char *filename,*s,*xfail=NULL;
17.82 GError *error=NULL;
17.83 if (!testcase_create_input_files(testcase,&error))
17.84 {
17.85 @@ -469,7 +528,7 @@
17.86 g_error_free(error);
17.87 return FALSE;
17.88 }
17.89 - r=testcase_spawn_bookloupe(testcase,&output,&error);
17.90 + r=testcase_spawn_bookloupe(testcase,&testcase->test_output,&error);
17.91 if (!r)
17.92 {
17.93 g_print("%s: FAIL\n",testcase->basename);
17.94 @@ -486,35 +545,40 @@
17.95 g_error_free(error);
17.96 return FALSE;
17.97 }
17.98 - header=g_string_new("\n\nFile: ");
17.99 - g_string_append(header,filename);
17.100 - g_string_append(header,"\n");
17.101 - if (!g_str_has_prefix(output,header->str))
17.102 + if (testcase->expected || testcase->warnings)
17.103 {
17.104 - g_print("%s: FAIL\n",testcase->basename);
17.105 - g_print("Unexpected header from bookloupe:\n");
17.106 - offset=common_prefix_length(output,header->str);
17.107 - print_unexpected(output,offset);
17.108 - r=FALSE;
17.109 - }
17.110 - pos=header->len;
17.111 - if (r)
17.112 - {
17.113 - /* Skip the summary */
17.114 - s=strstr(output+pos,"\n\n");
17.115 - if (s)
17.116 - pos=s-output+2;
17.117 - else
17.118 + header=g_string_new("\n\nFile: ");
17.119 + g_string_append(header,filename);
17.120 + g_string_append(header,"\n");
17.121 + if (!g_str_has_prefix(testcase->test_output,header->str))
17.122 {
17.123 g_print("%s: FAIL\n",testcase->basename);
17.124 - g_print("Unterminated summary from bookloupe:\n%s\n",output+pos);
17.125 + g_print("Unexpected header from bookloupe:\n");
17.126 + offset=common_prefix_length(testcase->test_output,header->str);
17.127 + print_unexpected(testcase->test_output,offset);
17.128 r=FALSE;
17.129 }
17.130 + pos=header->len;
17.131 + if (r)
17.132 + {
17.133 + /* Skip the summary */
17.134 + s=strstr(testcase->test_output+pos,"\n\n");
17.135 + if (s)
17.136 + pos=s-testcase->test_output+2;
17.137 + else
17.138 + {
17.139 + g_print("%s: FAIL\n",testcase->basename);
17.140 + g_print("Unterminated summary from bookloupe:\n%s\n",
17.141 + testcase->test_output+pos);
17.142 + r=FALSE;
17.143 + }
17.144 + }
17.145 + g_string_free(header,TRUE);
17.146 + r=testcase_check_warnings(testcase,testcase->test_output+pos,&xfail);
17.147 }
17.148 - g_string_free(header,TRUE);
17.149 - r=testcase_check_warnings(testcase,output+pos,&xfail);
17.150 + if (!testcase_verify_output_files(testcase))
17.151 + r=FALSE;
17.152 g_free(filename);
17.153 - g_free(output);
17.154 if (r)
17.155 {
17.156 if (xfail)
17.157 @@ -550,5 +614,6 @@
17.158 g_slist_free(testcase->warnings);
17.159 g_free(testcase->encoding);
17.160 g_strfreev(testcase->options);
17.161 + g_free(testcase->test_output);
17.162 g_free(testcase);
17.163 }
18.1 --- a/test/harness/testcase.h Sun Sep 29 09:18:05 2013 +0100
18.2 +++ b/test/harness/testcase.h Mon Sep 30 08:18:42 2013 +0100
18.3 @@ -37,10 +37,12 @@
18.4 char *basename;
18.5 char *tmpdir;
18.6 GSList *inputs;
18.7 + GSList *outputs;
18.8 char *expected;
18.9 GSList *warnings;
18.10 char *encoding; /* The character encoding to talk to BOOKLOUPE in */
18.11 char **options;
18.12 + char *test_output;
18.13 enum {
18.14 TESTCASE_XFAIL=1<<0,
18.15 TESTCASE_TMP_DIR=1<<1,
19.1 --- a/test/harness/testcaseio.c Sun Sep 29 09:18:05 2013 +0100
19.2 +++ b/test/harness/testcaseio.c Mon Sep 30 08:18:42 2013 +0100
19.3 @@ -5,6 +5,7 @@
19.4 #include <bl/bl.h>
19.5 #include "testcaseparser.h"
19.6 #include "testcaseinput.h"
19.7 +#include "testcaseoutput.h"
19.8 #include "testcaseio.h"
19.9 #include "warningsparser.h"
19.10
19.11 @@ -70,6 +71,25 @@
19.12 else if (!testcase->expected && !testcase->warnings &&
19.13 !strcmp(tag,"EXPECTED"))
19.14 testcase->expected=g_strdup(text);
19.15 + else if (g_str_has_prefix(tag,"EXPECTED(") && tag[strlen(tag)-1]==')')
19.16 + {
19.17 + arg=g_strndup(tag+9,strlen(tag)-10);
19.18 + s=g_path_get_dirname(arg);
19.19 + if (strcmp(s,"."))
19.20 + {
19.21 + g_printerr("%s: Expected files may not have a "
19.22 + "directory component\n",arg);
19.23 + g_free(s);
19.24 + g_free(arg);
19.25 + testcase_free(testcase);
19.26 + testcase_parser_free(parser);
19.27 + return NULL;
19.28 + }
19.29 + g_free(s);
19.30 + testcase->outputs=g_slist_prepend(testcase->outputs,
19.31 + testcase_output_new(arg,text));
19.32 + g_free(arg);
19.33 + }
19.34 else if (!testcase->expected && !testcase->warnings &&
19.35 !strcmp(tag,"WARNINGS"))
19.36 {
19.37 @@ -88,11 +108,14 @@
19.38 }
19.39 else if (!testcase->encoding && !strcmp(tag,"ENCODING"))
19.40 testcase->encoding=g_strchomp(g_strdup(text));
19.41 - else if (!testcase->encoding && !strcmp(tag,"OPTIONS"))
19.42 + else if (!testcase->options && !strcmp(tag,"OPTIONS"))
19.43 {
19.44 testcase->options=g_strsplit(text,"\n",0);
19.45 - g_free(testcase->options[g_strv_length(testcase->options)-1]);
19.46 - testcase->options[g_strv_length(testcase->options)-1]=NULL;
19.47 + if (testcase->options && g_strv_length(testcase->options)>0)
19.48 + {
19.49 + g_free(testcase->options[g_strv_length(testcase->options)-1]);
19.50 + testcase->options[g_strv_length(testcase->options)-1]=NULL;
19.51 + }
19.52 }
19.53 else
19.54 {
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/test/harness/testcaseoutput.c Mon Sep 30 08:18:42 2013 +0100
20.3 @@ -0,0 +1,140 @@
20.4 +#include <stdlib.h>
20.5 +#include <string.h>
20.6 +#include <errno.h>
20.7 +#include <glib.h>
20.8 +#include <bl/bl.h>
20.9 +#include "testcase.h"
20.10 +#include "testcaseoutput.h"
20.11 +
20.12 +/*
20.13 + * Replace \r\n with \n, \n with U+240A (visible symbol for LF)
20.14 + * and \r with U+240D (visible symbol for CR).
20.15 + */
20.16 +static char *dos2unix(const char *text)
20.17 +{
20.18 + gunichar c;
20.19 + gboolean cr=FALSE;
20.20 + const gunichar visible_lf=0x240A;
20.21 + const gunichar visible_cr=0x240D;
20.22 + GString *string;
20.23 + string=g_string_new(NULL);
20.24 + while(*text)
20.25 + {
20.26 + c=g_utf8_get_char(text);
20.27 + text=g_utf8_next_char(text);
20.28 + if (cr)
20.29 + {
20.30 + cr=FALSE;
20.31 + if (c=='\n')
20.32 + {
20.33 + g_string_append_c(string,'\n');
20.34 + continue;
20.35 + }
20.36 + else
20.37 + g_string_append_unichar(string,visible_cr);
20.38 + }
20.39 + if (c=='\r')
20.40 + cr=TRUE;
20.41 + else if (c=='\n')
20.42 + g_string_append_unichar(string,visible_lf);
20.43 + else
20.44 + g_string_append_unichar(string,c);
20.45 + }
20.46 + if (cr)
20.47 + g_string_append_unichar(string,visible_cr);
20.48 + return g_string_free(string,FALSE);
20.49 +}
20.50 +
20.51 +/*
20.52 + * Read an output file needed for a testcase (as specified in <output>).
20.53 + * The file is read in the encoding specified for communicating with
20.54 + * bookloupe.
20.55 + */
20.56 +gboolean testcase_output_read(Testcase *testcase,TestcaseOutput *output,
20.57 + gchar **contents,gsize *length,GError **error)
20.58 +{
20.59 + char *filename,*s,*t;
20.60 + gboolean retval;
20.61 + GError *tmp_err=NULL;
20.62 + if (!strcmp(output->name,"stdout"))
20.63 + {
20.64 + *contents=g_strdup(testcase->test_output);
20.65 + if (length)
20.66 + *length=strlen(testcase->test_output);
20.67 + }
20.68 + else
20.69 + {
20.70 + if (testcase->tmpdir)
20.71 + filename=g_build_filename(testcase->tmpdir,output->name,NULL);
20.72 + else
20.73 + filename=g_strdup(output->name);
20.74 + if (!g_file_get_contents(filename,&s,NULL,error))
20.75 + {
20.76 + g_free(filename);
20.77 + return FALSE;
20.78 + }
20.79 + g_free(filename);
20.80 + if (testcase->encoding)
20.81 + {
20.82 + t=dos2unix(s);
20.83 + g_free(s);
20.84 + s=g_convert(t,-1,"UTF-8",testcase->encoding,NULL,length,&tmp_err);
20.85 + g_free(t);
20.86 + if (!s)
20.87 + {
20.88 + g_propagate_prefixed_error(error,tmp_err,
20.89 + "Conversion from %s failed: ",testcase->encoding);
20.90 + return FALSE;
20.91 + }
20.92 + *contents=s;
20.93 + }
20.94 + else
20.95 + {
20.96 + *contents=dos2unix(s);
20.97 + if (length)
20.98 + *length=strlen(*contents);
20.99 + }
20.100 + }
20.101 + return TRUE;
20.102 +}
20.103 +
20.104 +/*
20.105 + * Remove an output file created by program under test.
20.106 + */
20.107 +gboolean testcase_output_remove(Testcase *testcase,TestcaseOutput *output,
20.108 + GError **error)
20.109 +{
20.110 + char *filename;
20.111 + if (!strcmp(output->name,"stdout"))
20.112 + return TRUE;
20.113 + if (testcase->tmpdir)
20.114 + filename=g_build_filename(testcase->tmpdir,output->name,NULL);
20.115 + else
20.116 + filename=g_strdup(output->name);
20.117 + if (g_unlink(filename)<0)
20.118 + {
20.119 + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
20.120 + "%s: %s",filename,g_strerror(errno));
20.121 + return FALSE;
20.122 + }
20.123 + g_free(filename);
20.124 + return TRUE;
20.125 +}
20.126 +
20.127 +/* Create a new description of an output file expected by a testcase */
20.128 +TestcaseOutput *testcase_output_new(const char *name,const char *contents)
20.129 +{
20.130 + TestcaseOutput *output;
20.131 + output=g_new0(TestcaseOutput,1);
20.132 + output->name=g_strdup(name);
20.133 + output->contents=g_strdup(contents);
20.134 + return output;
20.135 +}
20.136 +
20.137 +/* Free the description of a testcase output file */
20.138 +void testcase_output_free(TestcaseOutput *output)
20.139 +{
20.140 + g_free(output->name);
20.141 + g_free(output->contents);
20.142 + g_free(output);
20.143 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/test/harness/testcaseoutput.h Mon Sep 30 08:18:42 2013 +0100
21.3 @@ -0,0 +1,19 @@
21.4 +#ifndef TESTCASE_OUTPUT_H
21.5 +#define TESTCASE_OUTPUT_H
21.6 +
21.7 +#include <glib.h>
21.8 +#include "testcase.h"
21.9 +
21.10 +typedef struct {
21.11 + char *name;
21.12 + char *contents;
21.13 +} TestcaseOutput;
21.14 +
21.15 +gboolean testcase_output_read(Testcase *testcase,TestcaseOutput *output,
21.16 + gchar **contents,gsize *length,GError **error);
21.17 +gboolean testcase_output_remove(Testcase *testcase,TestcaseOutput *output,
21.18 + GError **error);
21.19 +TestcaseOutput *testcase_output_new(const char *name,const char *contents);
21.20 +void testcase_output_free(TestcaseOutput *output);
21.21 +
21.22 +#endif /* TESTCASE_OUTPUT_H */