/*====================================================================*
 *
 *   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