Commits

Michał Górny committed 9c70da2

Use glib for command-line option parsing.

  • Participants
  • Parent commits 8d5ca60

Comments (0)

Files changed (5)

 bin_PROGRAMS = mirage2iso
 
-mirage2iso_SOURCES = mirage2iso.c mirage-compat.h mirage-getopt.c mirage-getopt.h \
+mirage2iso_SOURCES = mirage2iso.c mirage-compat.h \
 	mirage-password.c mirage-password.h mirage-wrapper.c mirage-wrapper.h
-mirage2iso_LDADD = $(LIBMIRAGE_LIBS) $(LIBASSUAN_LIBS)
-mirage2iso_CPPFLAGS = $(LIBMIRAGE_CFLAGS) $(LIBASSUAN_CFLAGS)
+mirage2iso_LDADD = $(GLIB_LIBS) $(LIBMIRAGE_LIBS) $(LIBASSUAN_LIBS)
+mirage2iso_CPPFLAGS = $(GLIB_CFLAGS) $(LIBMIRAGE_CFLAGS) $(LIBASSUAN_CFLAGS)

File configure.ac

 
 AC_PROG_CC_C99
 AC_USE_SYSTEM_EXTENSIONS
+AM_PATH_GLIB_2_0([2.6.0],,
+	[AC_MSG_ERROR([This package requires >=glib-2.6.0 to compile])])
 PKG_CHECK_MODULES([LIBMIRAGE], [libmirage])
 AC_CHECK_FUNCS([ftruncate getopt_long mmap posix_fallocate])
 

File mirage-getopt.c

-/* mirage2iso; getopt wrapper
- * (c) 2009 Michał Górny
- * Released under the terms of the 3-clause BSD license.
- */
-
-#ifdef HAVE_CONFIG_H
-#	include "mirage-config.h"
-#endif
-#include "mirage-getopt.h"
-
-#ifdef HAVE_GETOPT_LONG
-#	include <getopt.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-
-static bool try_atoi(const char* const val, int* const out) {
-	char *end;
-	int tmp;
-
-	if (!*val)
-		return false;
-
-	tmp = strtol(val, &end, 0);
-	if (end && *end)
-		return false;
-
-	*out = tmp;
-	return true;
-}
-
-#ifdef HAVE_GETOPT_LONG
-
-short int mirage_getopt(const int argc, char* const argv[], const struct mirage_opt* const opts, union mirage_optarg_val *outval, const char* newargv[]) {
-	const struct mirage_opt *op;
-	int arrlen = 1, buflen = 1;
-
-	for (op = opts; op->name; op++) {
-		arrlen++;
-		if (op->val) {
-			buflen++;
-			if (op->arg != mirage_arg_none)
-				buflen++;
-		}
-	}
-
-	char buf[buflen + 1];
-	struct option longopts[arrlen + 1];
-	char* bufptr = buf;
-	struct option *optptr = longopts;
-
-	for (op = opts; op->name; op++, optptr++) {
-		optptr->name = op->name;
-		optptr->has_arg = op->arg == mirage_arg_none ? no_argument : required_argument;
-		optptr->flag = NULL;
-		optptr->val = op->val;
-
-		if (op->val) {
-			*(bufptr++) = op->val;
-			if (op->arg != mirage_arg_none)
-				*(bufptr++) = ':';
-		}
-	}
-	*bufptr = 0;
-	memset(optptr, 0, sizeof(*optptr));
-
-	const int ret = getopt_long(argc, argv, buf, longopts, NULL);
-
-	if (ret == -1) { /* done parsing, set up newargv */
-		int i, newargc;
-		for (i = optind, newargc = 0; i < argc; i++)
-			newargv[newargc++] = argv[i];
-		newargv[newargc] = NULL;
-		return -newargc;
-	}
-
-	for (op = opts; op->name; op++) {
-		if (op->val == ret) {
-			switch (op->arg) {
-				case mirage_arg_int:
-					if (!try_atoi(optarg, &(outval->as_int))) {
-						fprintf(stderr, "--%s requires integer argument which '%s' apparently isn't\n", op->name, optarg);
-						return '?';
-					}
-					break;
-				case mirage_arg_str:
-					outval->as_str = optarg;
-					break;
-				case mirage_arg_none:
-					break;
-			}
-		}
-	}
-
-	return ret;
-}
-
-#else
-
-short int mirage_getopt(const int argc, char* const argv[], const struct mirage_opt* const opts, union mirage_optarg_val *outval, const char* newargv[]) {
-	static int argindex = 1;
-	static const char* shortptr = NULL;
-	static int newargc = 0;
-
-	const struct mirage_opt *op;
-
-	while (argindex < argc) {
-		const int i = argindex++;
-		const char *cp = argv[i];
-
-		const struct mirage_opt* opt = NULL;
-		const char *val = NULL;
-
-		if (shortptr || (cp[0] == '-' && cp[1] && (cp[1] != '-' || cp[2]))) {
-			cp++;
-			if (!shortptr && cp[0] == '-') {
-				cp++;
-
-				const char* const vp = strchr(cp, '=');
-				const int cl = vp ? vp-cp : strlen(cp);
-
-				for (op = opts; op->name; op++) {
-					if (!strncmp(op->name, cp, cl) && !op->name[cl]) {
-						if (vp) {
-							if (op->arg == mirage_arg_none) {
-								fprintf(stderr, "Option '--%s' doesn't take an argument\n", op->name);
-								return '?';
-							} else
-								val = vp + 1;
-						}
-						opt = op;
-						break;
-					}
-				}
-
-				if (!opt) {
-					fprintf(stderr, "Incorrect option: --%s\n", cp);
-					return '?';
-				}
-			} else { /* short option */
-				if (!shortptr)
-					shortptr = cp;
-				cp = shortptr++;
-
-				for (op = opts; op->name; op++) {
-					if (op->val == *cp) {
-						if (op->arg != mirage_arg_none && *shortptr) /* value coming */
-							val = shortptr;
-						opt = op;
-						break;
-					}
-				}
-
-				if (*shortptr && !val) { /* next short arg coming? */
-					argindex--;
-				} else
-					shortptr = NULL;
-
-				if (!opt) {
-					fprintf(stderr, "Incorrect option: -%c\n", *cp);
-					return '?';
-				}
-			}
-
-			if (opt->arg != mirage_arg_none) {
-				if (!val) { /* need to fetch argument from next arg */
-					if (!argv[argindex]) {
-						fprintf(stderr, "Option '--%s' requires an argument\n", opt->name);
-						return '?';
-					}
-
-					val = argv[argindex++];
-				}
-
-				switch (opt->arg) {
-					case mirage_arg_int:
-						if (!try_atoi(val, &(outval->as_int))) {
-							fprintf(stderr, "'--%s' requires integer argument which '%s' apparently isn't\n", opt->name, val);
-							return '?';
-						}
-						break;
-					case mirage_arg_str:
-						outval->as_str = val;
-				}
-			}
-
-			return opt->val;
-		} else if (cp[0] == '-' && cp[1] == '-') {
-			int i;
-			for (i = argindex; argv[i]; i++)
-				newargv[newargc++] = argv[i];
-		} else { /* non-option */
-			newargv[newargc++] = cp;
-			continue;
-		}
-	}
-
-	newargv[newargc] = NULL;
-	return -newargc;
-}
-
-#endif
-
-void mirage_getopt_help(const char* const argv0, const char* const synopsis, const struct mirage_opt* const opts) {
-	const char* const msg =
-		"Synopsis:\n"
-		"\t%s %s\n\n"
-		"Options:\n";
-
-	fprintf(stderr, msg, argv0, synopsis);
-
-	const struct mirage_opt* op;
-	for (op = opts; op->name; op++) {
-		const char* formatspec;
-		switch (op->arg) {
-			case mirage_arg_int: formatspec = " %d"; break;
-			case mirage_arg_str: formatspec = " %s"; break;
-			case mirage_arg_none: formatspec = "";
-		}
-
-		const char* const addtab = (strlen(op->name) + 2 * strlen(formatspec)) >= 10 ? "" : "\t";
-
-		fprintf(stderr, "\t--%s%s, -%c%s\t%s%s\n", op->name, formatspec, op->val, formatspec, addtab, op->help);
-	}
-}

File mirage-getopt.h

-/* mirage2iso; getopt wrapper
- * (c) 2009 Michał Górny
- * Released under the terms of the 3-clause BSD license.
- */
-
-#ifndef _MIRAGE_GETOPT_H
-#define _MIRAGE_GETOPT_H 1
-
-enum mirage_optarg {
-	mirage_arg_none,
-	mirage_arg_int,
-	mirage_arg_str
-};
-
-union mirage_optarg_val {
-	int as_int;
-	const char* as_str;
-};
-
-struct mirage_opt {
-	const char* const name;
-	enum mirage_optarg arg;
-	short int val;
-	const char* const help;
-};
-
-short int mirage_getopt(const int argc, char* const argv[], const struct mirage_opt* const opts, union mirage_optarg_val *outval, const char* newargv[]);
-void mirage_getopt_help(const char* const argv0, const char* const synopsis, const struct mirage_opt* const opts);
-
-#endif

File mirage2iso.c

 #	define EX_IOERR 74
 #endif
 
-#include "mirage-getopt.h"
+#include <glib.h>
+
 #include "mirage-password.h"
 #include "mirage-wrapper.h"
 
-bool quiet = false;
-bool verbose = false;
+gboolean quiet = false;
+gboolean verbose = false;
 
 #if defined(HAVE_FTRUNCATE) && defined(HAVE_MMAP)
-static bool force_stdio = false;
+static gboolean force_stdio = false;
 #endif
 
-static const struct mirage_opt opts[] = {
-	{ "force", mirage_arg_none, 'f', "Force replacing guessed output file" },
-	{ "help", mirage_arg_none, '?', "Take a wild guess" },
-	{ "password", mirage_arg_str, 'p', "Password for the encrypted image" },
-	{ "quiet", mirage_arg_none, 'q', "Disable progress reporting, output only errors" },
-	{ "session", mirage_arg_int, 's', "Session to use (default: last one)" },
-	{ "stdio", mirage_arg_none, 'S', "Force using stdio instead of mmap()" },
-	{ "stdout", mirage_arg_none, 'c', "Output image into STDOUT instead of a file" },
-	{ "verbose", mirage_arg_none, 'v', "Increase progress reporting verbosity" },
-	{ "version", mirage_arg_none, 'V', "Print version number and quit" },
-	{ 0, 0, 0, 0 }
-};
-
-static int help(const char* argv0) {
-	mirage_getopt_help(*argv0 ? argv0 : "mirage2iso", "[options] <infile> [outfile.iso]", opts);
-	return EX_USAGE;
-}
-
 static void version(const bool mirage) {
 	const char* const ver = mirage ? miragewrap_get_version() : NULL;
 	fprintf(stderr, "mirage2iso %s, using libmirage %s\n", VERSION, ver ? ver : "unknown");
 	return EX_OK;
 }
 
-int main(const int argc, char* const argv[]) {
-	int session_num = -1;
-	bool force = false;
-	bool use_stdout = false;
-
-	int arg;
-	union mirage_optarg_val val;
-	const char* newargv[argc];
-
-	while ((arg = mirage_getopt(argc, argv, opts, &val, newargv)) > 0) {
-		switch (arg) {
-			case 'c':
-				use_stdout = true;
-				break;
-			case 'f':
-				force = true;
-				break;
-			case 'p':
-				mirage_set_password(val.as_str);
-				break;
-			case 'q':
-				quiet = true;
-				break;
-			case 's':
-				session_num = val.as_int;
-				break;
-			case 'S':
-#if defined(HAVE_FTRUNCATE) && defined(HAVE_MMAP)
-				force_stdio = true;
-#else
-				fprintf(stderr, "mirage2iso compiled without mmap support, --stdio is always on\n");
+int main(int argc, char* argv[]) {
+	gint session_num = -1;
+	gboolean force = false;
+	gboolean use_stdout = false;
+	gchar **newargv = NULL;
+
+	const GOptionEntry opts[] = {
+		{ "force", 'f', 0, G_OPTION_ARG_NONE, &force, "Force replacing the guessed output file", NULL },
+#if 0 /* XXX: mirage_set_password()? */
+		{ "password", 'p', 0, G_OPTION_ARG_STRING, XXX, "Password for the encrypted image", "PASS" },
 #endif
-				break;
-			case 'v':
-				verbose = true;
-				break;
-			case 'V':
-				version(miragewrap_init());
-				return EX_OK;
-			case '?':
-				return help(argv[0]);
-		}
+		{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Disable progress reporting, output only errors", NULL },
+		{ "session", 's', 0, G_OPTION_ARG_INT, &session_num, "Session to use (default: the last one)", "N" },
+		{ "stdio", 'S', 0, G_OPTION_ARG_NONE, &force_stdio, "Force using stdio instead of mmap()", NULL },
+		{ "stdout", 'c', 0, G_OPTION_ARG_NONE, &use_stdout, "Output the image into stdout instead of a file", NULL },
+		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Increase progress reporting verbosity", NULL },
+		{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &newargv, NULL, "<in> [<out.iso>]" },
+		{ NULL }
+	};
+	GOptionContext *opt;
+	GError *err = NULL;
+
+	opt = g_option_context_new(NULL);
+	g_option_context_add_main_entries(opt, opts, NULL);
+
+	if (!g_option_context_parse(opt, &argc, &argv, &err)) {
+		g_print("Option parsing failed: %s\n", err->message);
+		g_error_free(err);
+		g_option_context_free(opt);
+		g_strfreev(newargv);
+		return EX_USAGE;
 	}
 
 	if (quiet && verbose) {
 			fprintf(stderr, "--force has no effect when --stdout in use\n");
 	}
 
-	const char* const in = newargv[0];
-	if (!in) {
+	const char* in;
+	if (!newargv || !(in = newargv[0])) {
+		gchar* const helpmsg = g_option_context_get_help(opt, TRUE, NULL);
 		fprintf(stderr, "No input file specified\n");
-		return help(argv[0]);
+		g_print("%s", helpmsg);
+		g_free(helpmsg);
+		g_option_context_free(opt);
+		g_strfreev(newargv);
+		return EX_USAGE;
 	}
+	g_option_context_free(opt);
 
 	const char* out = newargv[1];
 	char* outbuf = NULL;
 				if (!force) {
 					fprintf(stderr, "Input file has .iso suffix and no output file specified\n"
 							"Either specify one or use --force to use '.iso.iso' output suffix\n");
+					g_strfreev(newargv);
 					return EX_USAGE;
 				}
 				ext = NULL;
 			outbuf = malloc(namelen + 5);
 			if (!outbuf) {
 				perror("malloc() for output filename failed");
+				g_strfreev(newargv);
 				return EX_OSERR;
 			}
 			strncpy(outbuf, in, namelen);
 
 					fprintf(stderr, "No output file specified and guessed filename matches existing file:\n\t%s\n", outbuf);
 					free(outbuf);
+					g_strfreev(newargv);
 					return EX_USAGE;
 				}
 			}
 		}
 	} else if (use_stdout) {
 		fprintf(stderr, "Output file can't be specified with --stdout\n");
+		g_strfreev(newargv);
 		return EX_USAGE;
 	}
 
-	if (!miragewrap_init())
+	if (!miragewrap_init()) {
+		g_strfreev(newargv);
 		return EX_SOFTWARE;
+	}
 
 	if (verbose)
 		version(true);
 
 	if (!miragewrap_open(in, session_num)) {
 		miragewrap_free();
+		g_strfreev(newargv);
 		return EX_NOINPUT;
 	}
 	if (verbose)
 
 		if (ret != EX_OK && ret != EX_DATAERR) {
 			miragewrap_free();
+			g_strfreev(newargv);
 			return ret;
 		}
 	}
 		fprintf(stderr, "Done\n");
 
 	miragewrap_free();
+	g_strfreev(newargv);
 	return EX_OK;
 }