/*====================================================================*
 *
 *   int getoptv (int argc, char const * argv[], char const * optv[]);
 *
 *   getoptv.h
 *
 *   this is a posix compliant getopt() function that supports no 
 *   extensions; see the posix website for specification details; 
 *
 *   <http://www.opengroup.org/onlinepubs/007904975/functions/getopt.html>
 *
 *   we implemented this function to ensure that linux and windows
 *   consoles act the same; microsoft c++ would not compile the 
 *   debian version of getopt and so, after trying to fix things, 
 *   we decided to start fresh; the debian version is too complex;
 *
 *   this function conforms to posix standard; it does not support
 *   gnu style extensions like "--option" for arguments or "ab::c" 
 *   for operands; if you don't know what that means then you won't 
 *   care, either; you should avoid such extentions, anyway;
 *
 *   the posix standard says that command options and operands must 
 *   precede other arguments; this version of getopt allows options
 *   and operands to appear anywhere and makes non-compliant argv[]
 *   compliant in the process;
 *
 *   we define characters instead of coding them so that microsoft
 *   folks can use '/' instead of '-' and still preserve the posix 
 *   behaviour;
 *
 *   we declare optarg as "char const *" so that the target cannot
 *   be changed by the application; this is not POSIX compliant so
 *   it will conflict with other getopt variants; getopt.h is often
 *   included with unistd.h which is a common file;
 *
 *   systems.
 *
 *   this version calls virtually no functions and should compile 
 *   on any posix system; 
 *
 *   you may include getoptv.h or declare these variables:
 *
 *    extern char const *optarg;
 *    extern int optopt;
 *    extern int optind;
 *    extern int opterr;
 *
 *   you may cut and paste this c language code segment to get you 
 *   started; you must insert your own code and case breaks;
 *
 *    signed c;
 *    optind = 1;
 *    opterr = 1;
 *
 *    while ((c = getoptv(argc, argv, * optv)) != -1)
 *    {
 *       switch(c)
 *       {
 *          case 'a': // optopt is 'a'; optarg is NULL;
 *          case 'b': // optopt is 'b'; optarg is operand;
 *          case ':': // optopt is option; optarg is NULL; missing operand;
 *          case '?': // optopt is option; optarg is NULL; illegal option; 
 *           default: // optopt is option: optarg is NULL; illegal option; 
 *       }
 *    }
 *
 *    after options and operands are processed, optind points to
 *    the next argv [] string; loop until optind equals argc or 
 *    argv[optind] is NULL; we check both but either will do; 
 *
 *    while ((optind < argc) && (argv [optind]))
 *    {
 *       // do stuff to argv[optind++].
 *    }
 *
 *   alternately, and even better, the following works just fine:
 *
 *    argc -= optind;
 *    argv += optind;
 *    while ((argc) && (* argv))
 *    {
 *       // do stuff to * argv.
 *
 *    }
 *
 *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
 *   Copyright (c) 2001-2006 by Charles Maier Associates;
 *   Licensed under the Internet Software Consortium License;
 *
 *--------------------------------------------------------------------*/

#ifndef GETOPTV_SOURCE
#define GETOPTV_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../tools/getoptv.h"
#include "../tools/putoptv.h"
#include "../tools/version.h"
#include "../tools/error.h"

char const * program_name = "program"; 
char * optarg = (char *) (0); 
signed optopt = (char) (0); 
signed optind = 1; 
signed opterr = 1; 
signed optmin = 0; 
signed getoptv (int argc, char const * argv [], char const * optv []) 

{ 
	static char const * string; 
	static char const * option; 
	static signed count; 
	signed index; 
	if ((optind == 0) || (optind == 1)) 
	{ 
		for (program_name = string = * argv; * string; string++) 
		{ 
			if ((* string == '/') || (* string == '\\')) 
			{ 
				program_name = string +  1; 
			} 
		} 
		string = (char *) (0); 
		if (argc == optmin) 
		{ 
			putoptv (optv); 
			exit (0); 
		} 
		count = optind = 1; 
	} 
	while ((count < argc) || (string)) 
	{ 
		if (string) 
		{ 
			if (* string) 
			{ 
				optarg = (char *) (0); 
				optopt = * string++; 
				for (option = * optv; * option; option++) 
				{ 
					if (optopt == GETOPTV_C_OPERAND) 
					{ 
						continue; 
					} 
					if (* option == GETOPTV_C_OPERAND) 
					{ 
						continue; 
					} 
					if (* option == optopt) 
					{ 
						option++; 
						if (* option != GETOPTV_C_OPERAND) 
						{ 
							return (optopt); 
						} 
						if (* string) 
						{ 
							optarg = (char *) (string); 
							string = (char *) (0); 
							return (optopt); 
						} 
						if (count < argc) 
						{ 
							optarg = (char *) (argv [count]); 
							for (index = count++; index > optind; index--) 
							{ 
								argv [index] = argv [index - 1]; 
							} 
							argv [optind++] = optarg; 
							return (optopt); 
						} 
						if (opterr) 
						{ 
							error (1, 0, "option '%c' needs an operand.", optopt); 
						} 
						if (** optv == GETOPTV_C_OPERAND) 
						{ 
							return (GETOPTV_C_OPERAND); 
						} 
						return (GETOPTV_C_ILLEGAL); 
					} 
				} 
				if (opterr) 
				{ 
					error (1, 0, "option '%c' has no meaning.", optopt); 
				} 
				return (GETOPTV_C_ILLEGAL); 
			} 
			else 
			{ 
				string = (char *) (0); 
			} 
		} 
		if (count < argc) 
		{ 
			string = argv [count]; 
			if (* string == GETOPTV_C_OPTION) 
			{ 
				for (index = count; index > optind; index--) 
				{ 
					argv [index] = argv [index - 1]; 
				} 
				argv [optind++] = string++; 
				if (* string == GETOPTV_C_VERSION) 
				{ 
					version (); 
					exit (0); 
				} 
				if (* string == GETOPTV_C_SUMMARY) 
				{ 
					putoptv (optv); 
					exit (0); 
				} 
				if (* string == GETOPTV_C_OPTION) 
				{ 
					string++; 
					if (! strcmp (string, "")) 
					{ 
						optarg = (char *) (0); 
						optopt = (char) (0); 
						return (- 1); 
					} 
					if (! strcmp (string, "version")) 
					{ 
						version (); 
						exit (0); 
					} 
					if (! strcmp (string, "help")) 
					{ 
						putoptv (optv); 
						exit (0); 
					} 
					optarg = (char *) (string); 
					optopt = GETOPTV_C_OPTION; 
					return (- 1); 
				} 
			} 
			else 
			{ 
				string = (char *) (0); 
			} 
			count++; 
		} 
	} 
	optarg = (char *) (0); 
	optopt = (char) (0); 
	return (- 1); 
} 

#endif