Changeset - r17346:c18704fa8b81
[Not reviewed]
master
0 3 0
alberth - 13 years ago 2011-02-18 20:28:25
alberth@openttd.org
(svn r22098) -Codechange: Have an array of option data, use it in the option parsing routine. Adapt openttd option processing too.
3 files changed with 187 insertions and 68 deletions:
0 comments (0 inline, 0 general)
src/misc/getoptdata.cpp
Show inline comments
 
@@ -16,56 +16,75 @@
 
 * Find the next option.
 
 * @return Function returns one
 
 * - An option letter if it found another option.
 
 * - -1 if option processing is finished.
 
 * - -1 if option processing is finished. Inspect #argv and #numleft to find the command line arguments.
 
 * - -2 if an error was encountered.
 
 */
 
int GetOptData::GetOpt()
 
{
 
	const OptionData *odata;
 

	
 
	char *s = this->cont;
 
	if (s != NULL) {
 
		goto md_continue_here;
 
	if (s == NULL) {
 
		if (this->numleft == 0) return -1; // No arguments left -> finished.
 

	
 
		s = this->argv[0];
 
		if (*s != '-') return -1; // No leading '-' -> not an option -> finished.
 

	
 
		this->argv++;
 
		this->numleft--;
 

	
 
		/* Is it a long option? */
 
		for (odata = this->options; odata->flags != ODF_END; odata++) {
 
			if (odata->longname != NULL && !strcmp(odata->longname, s)) { // Long options always use the entire argument.
 
				this->cont = NULL;
 
				goto set_optval;
 
			}
 
		}
 

	
 
		s++; // Skip leading '-'.
 
	}
 

	
 
	for (;;) {
 
		if (--this->numleft < 0) return -1;
 
	/* Is it a short option? */
 
	for (odata = this->options; odata->flags != ODF_END; odata++) {
 
		if (odata->shortname != '\0' && *s == odata->shortname) {
 
			this->cont = (s[1] != '\0') ? s + 1 : NULL;
 

	
 
set_optval: // Handle option value of *odata .
 
			this->opt = NULL;
 
			switch (odata->flags) {
 
				case ODF_NO_VALUE:
 
					return odata->id;
 

	
 
		s = *this->argv++;
 
		if (*s == '-') {
 
md_continue_here:;
 
			s++;
 
			if (*s != 0) {
 
				const char *r;
 
				/* Found argument, try to locate it in options. */
 
				if (*s == ':' || (r = strchr(this->options, *s)) == NULL) {
 
					/* ERROR! */
 
					return -2;
 
				}
 
				if (r[1] == ':') {
 
					char *t;
 
					/* Item wants an argument. Check if the argument follows, or if it comes as a separate arg. */
 
					if (!*(t = s + 1)) {
 
						/* It comes as a separate arg. Check if out of args? */
 
						if (--this->numleft < 0 || *(t = *this->argv) == '-') {
 
							/* Check if item is optional? */
 
							if (r[2] != ':') return -2;
 
							this->numleft++;
 
							t = NULL;
 
						} else {
 
							this->argv++;
 
						}
 
				case ODF_HAS_VALUE:
 
					if (this->cont != NULL) { // Remainder of the argument is the option value.
 
						this->opt = this->cont;
 
						this->cont = NULL;
 
						return odata->id;
 
					}
 
					this->opt = t;
 
					this->cont = NULL;
 
					return *s;
 
				}
 
				this->opt = NULL;
 
				this->cont = s;
 
				return *s;
 
					if (this->numleft == 0) return -2; // Missing the option value.
 
					this->opt = this->argv[0];
 
					this->argv++;
 
					this->numleft--;
 
					return odata->id;
 

	
 
				case ODF_OPTIONAL_VALUE:
 
					if (this->cont != NULL) { // Remainder of the argument is the option value.
 
						this->opt = this->cont;
 
						this->cont = NULL;
 
						return odata->id;
 
					}
 
					if (this->numleft > 0 && this->argv[0][0] != '-') {
 
						this->opt = this->argv[0];
 
						this->argv++;
 
						this->numleft--;
 
					}
 
					return odata->id;
 

	
 
				default: NOT_REACHED();
 
			}
 
		} else {
 
			/* This is currently not supported. */
 
			return -2;
 
		}
 
	}
 

	
 
	return -2; // No other ways to interpret the text -> error.
 
}
 

	
src/misc/getoptdata.h
Show inline comments
 
@@ -12,13 +12,29 @@
 
#ifndef GETOPTDATA_H
 
#define GETOPTDATA_H
 

	
 
/** Flags of an option. */
 
enum OptionDataFlags {
 
	ODF_NO_VALUE,       ///< A plain option (no value attached to it).
 
	ODF_HAS_VALUE,      ///< An option with a value.
 
	ODF_OPTIONAL_VALUE, ///< An option with an optional value.
 
	ODF_END,            ///< Terminator (data is not parsed further).
 
};
 

	
 
/** Data of an option. */
 
struct OptionData {
 
	byte id;              ///< Unique identification of this option data, often the same as #shortname.
 
	char shortname;       ///< Short option letter if available, else use \c '\0'.
 
	uint16 flags;         ///< Option data flags. @see OptionDataFlags
 
	const char *longname; ///< Long option name including '-'/'--' prefix, use \c NULL if not available.
 
};
 

	
 
/** Data storage for parsing command line options. */
 
struct GetOptData {
 
	char *opt;           ///< Option value, if available (else \c NULL).
 
	int numleft;         ///< Number of arguments left in #argv.
 
	char **argv;         ///< Remaining command line arguments.
 
	const char *options; ///< Command line option descriptions.
 
	char *cont;          ///< Next call to #MyGetOpt should start here (in the middle of an argument).
 
	char *opt;                 ///< Option value, if available (else \c NULL).
 
	int numleft;               ///< Number of arguments left in #argv.
 
	char **argv;               ///< Remaining command line arguments.
 
	const OptionData *options; ///< Command line option descriptions.
 
	char *cont;                ///< Next call to #MyGetOpt should start here (in the middle of an argument).
 

	
 
	/**
 
	 * Constructor of the data store.
 
@@ -26,7 +42,7 @@ struct GetOptData {
 
	 * @param argv Command line arguments, excluding the program name.
 
	 * @param options Command line option descriptions.
 
	 */
 
	GetOptData(int argc, char **argv, const char *options) :
 
	GetOptData(int argc, char **argv, const OptionData *options) :
 
			opt(NULL),
 
			numleft(argc),
 
			argv(argv),
 
@@ -38,4 +54,59 @@ struct GetOptData {
 
	int GetOpt();
 
};
 

	
 
/**
 
 * General macro for creating an option.
 
 * @param id        Identification of the option.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 * @param longname  Long option name including leading '-' or '--'. Use \c NULL if not used.
 
 * @param flags     Flags of the option.
 
 */
 
#define GETOPT_GENERAL(id, shortname, longname, flags) { id, shortname, flags, longname }
 

	
 
/**
 
 * Short option without value.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 * @param longname  Long option name including leading '-' or '--'. Use \c NULL if not used.
 
 */
 
#define GETOPT_NOVAL(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_NO_VALUE)
 

	
 
/**
 
 * Short option with value.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 * @param longname  Long option name including leading '-' or '--'. Use \c NULL if not used.
 
 */
 
#define GETOPT_VALUE(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_HAS_VALUE)
 

	
 
/**
 
 * Short option with optional value.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 * @param longname  Long option name including leading '-' or '--'. Use \c NULL if not used.
 
 * @note Options with optional values are hopelessly ambiguous, eg "-opt -value", avoid them.
 
 */
 
#define GETOPT_OPTVAL(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_OPTIONAL_VALUE)
 

	
 

	
 
/**
 
 * Short option without value.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 */
 
#define GETOPT_SHORT_NOVAL(shortname) GETOPT_NOVAL(shortname, NULL)
 

	
 
/**
 
 * Short option with value.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 */
 
#define GETOPT_SHORT_VALUE(shortname) GETOPT_VALUE(shortname, NULL)
 

	
 
/**
 
 * Short option with optional value.
 
 * @param shortname Short option name. Use \c '\0' if not used.
 
 * @note Options with optional values are hopelessly ambiguous, eg "-opt -value", avoid them.
 
 */
 
#define GETOPT_SHORT_OPTVAL(shortname) GETOPT_OPTVAL(shortname, NULL)
 

	
 
/** Option terminator. */
 
#define GETOPT_END() { '\0', '\0', ODF_END, NULL}
 

	
 

	
 
#endif /* GETOPTDATA_H */
src/openttd.cpp
Show inline comments
 
@@ -342,10 +342,41 @@ void MakeNewgameSettingsLive()
 
extern void DedicatedFork();
 
#endif
 

	
 
/** Options of OpenTTD. */
 
static const OptionData _options[] = {
 
	 GETOPT_SHORT_VALUE('I'),
 
	 GETOPT_SHORT_VALUE('S'),
 
	 GETOPT_SHORT_VALUE('M'),
 
	 GETOPT_SHORT_VALUE('m'),
 
	 GETOPT_SHORT_VALUE('s'),
 
	 GETOPT_SHORT_VALUE('v'),
 
	 GETOPT_SHORT_VALUE('b'),
 
#if defined(ENABLE_NETWORK)
 
	GETOPT_SHORT_OPTVAL('D'),
 
	GETOPT_SHORT_OPTVAL('n'),
 
	 GETOPT_SHORT_VALUE('l'),
 
	 GETOPT_SHORT_VALUE('p'),
 
	 GETOPT_SHORT_VALUE('P'),
 
#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
 
	 GETOPT_SHORT_NOVAL('f'),
 
#endif
 
#endif /* ENABLE_NETWORK */
 
	 GETOPT_SHORT_VALUE('r'),
 
	 GETOPT_SHORT_VALUE('t'),
 
	GETOPT_SHORT_OPTVAL('d'),
 
	 GETOPT_SHORT_NOVAL('e'),
 
	GETOPT_SHORT_OPTVAL('i'),
 
	GETOPT_SHORT_OPTVAL('g'),
 
	 GETOPT_SHORT_VALUE('G'),
 
	 GETOPT_SHORT_VALUE('c'),
 
	 GETOPT_SHORT_NOVAL('x'),
 
	 GETOPT_SHORT_NOVAL('h'),
 
	GETOPT_END()
 
};
 

	
 

	
 
int ttd_main(int argc, char *argv[])
 
{
 
	int i;
 
	const char *optformat;
 
	char *musicdriver = NULL;
 
	char *sounddriver = NULL;
 
	char *videodriver = NULL;
 
@@ -376,18 +407,9 @@ int ttd_main(int argc, char *argv[])
 
	_switch_mode_errorstr = INVALID_STRING_ID;
 
	_config_file = NULL;
 

	
 
	/* The last param of the following function means this:
 
	 *   a letter means: it accepts that param (e.g.: -h)
 
	 *   a ':' behind it means: it need a param (e.g.: -m<driver>)
 
	 *   a '::' behind it means: it can optional have a param (e.g.: -d<debug>) */
 
	optformat = "m:s:v:b:hD::n::ei::I:S:M:t:d::r:g::G:c:xl:p:P:"
 
#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
 
		"f"
 
#endif
 
	;
 
	GetOptData mgo(argc - 1, argv + 1, _options);
 

	
 
	GetOptData mgo(argc - 1, argv + 1, optformat);
 

	
 
	int i;
 
	while ((i = mgo.GetOpt()) != -1) {
 
		switch (i) {
 
		case 'I': free(graphics_set); graphics_set = strdup(mgo.opt); break;
 
@@ -476,18 +498,25 @@ int ttd_main(int argc, char *argv[])
 
		case 'G': generation_seed = atoi(mgo.opt); break;
 
		case 'c': _config_file = strdup(mgo.opt); break;
 
		case 'x': save_config = false; break;
 
		case -2:
 
		case 'h':
 
			/* The next two functions are needed to list the graphics sets.
 
			 * We can't do them earlier because then we can't show it on
 
			 * the debug console as that hasn't been configured yet. */
 
			DeterminePaths(argv[0]);
 
			BaseGraphics::FindSets();
 
			BaseSounds::FindSets();
 
			BaseMusic::FindSets();
 
			ShowHelp();
 
			return 0;
 
			i = -2; // Force printing of help.
 
			break;
 
		}
 
		if (i == -2) break;
 
	}
 

	
 
	if (i == -2 || mgo.numleft > 0) {
 
		/* Either the user typed '-h', he made an error, or he added unrecognized command line arguments.
 
		 * In all cases, print the help, and exit.
 
		 *
 
		 * The next two functions are needed to list the graphics sets. We can't do them earlier
 
		 * because then we cannot show it on the debug console as that hasn't been configured yet. */
 
		DeterminePaths(argv[0]);
 
		BaseGraphics::FindSets();
 
		BaseSounds::FindSets();
 
		BaseMusic::FindSets();
 
		ShowHelp();
 
		return 0;
 
	}
 

	
 
#if defined(WINCE) && defined(_DEBUG)
0 comments (0 inline, 0 general)