/* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
/*======================================================================
Copyright (C) 2004,2005,2009 Walter Doekes <walter+tthsum@wjd.nu>
This file is part of tthsum.

tthsum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

tthsum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with tthsum.  If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "getopt.h"


#ifdef USE_MY_GETOPT
#   include <stdio.h>
#   include <string.h>

char* optarg;	/* option argument */
int optind = 0; /* argv index */
int opterr = 1; /* print errors on stderr */
int optopt = 0; /* the character found for '?' characters */
static int optindind = 0; /* letter-index for options at optind */

int getopt(int argc, char* const argv[], const char* optstring) {
    /* if optindind is set, we're looking at an option at optind */
    if (optindind != 0) {
	int ret;
	const char* p = strchr(optstring, argv[optind][optindind]);
	/* unknown option */
	if (p == NULL) {
	    ret = '?';
	    optopt = argv[optind][optindind];
	    if (argv[optind][optindind + 1] != '\0') {
		++optindind;
	    } else {
		optindind = 0;
		++optind;
	    }
	    if (opterr)
		fprintf(stderr, "%s: invalid option -- %c\n",
			argv[0], optopt);
	    return '?';
	/* with-argument option */
	} else if (p[1] == ':') {
	    /* GNU extension: double colon means arg is optional */
	    ret = argv[optind][optindind];
	    /* argument is attached to option */
	    if (argv[optind][optindind + 1] != '\0') {
		optarg = argv[optind] + optindind + 1;
		optindind = 0;
		++optind;
	    /* argument is not attached and optional (GNU extension) */
	    } else if (p[2] == ':') {
		optarg = NULL;
		optindind = 0;
		++optind;
	    /* argument is not optional and loose */
	    } else {
		if (optind + 1 == argc) {
		    optopt = ret;
		    if (opterr)
			fprintf(stderr, "%s: option requires an argument"
				" -- %c\n", argv[0], optopt);
		    ret = '?';
		} else {
		    ++optind;
		    optarg = argv[optind];
		}
	    }
	    optindind = 0;
	    ++optind;
	/* correct non-argument option */
	} else {
	    ret = argv[optind][optindind];
	    if (argv[optind][optindind + 1] != '\0') {
		++optindind;
	    } else {
		optindind = 0;
		++optind;
	    }
	}
	return ret;
    }
    
    /* if optind is zero, we haven't run yet */
    if (optind <= 0) {
	optind = 1;
	optindind = 0;
    }
    
    /* done? */
    if (optind >= argc)
	return -1;

    /* end of options? */
    if (argv[optind][0] == '-' && argv[optind][1] == '-'
	    && argv[optind][2] == '\0') {
	++optind;
	return -1;
    }

    /* not an option? */
    if (argv[optind][0] != '-') {
	/* find option and move it to front */
	const char** mut_argv = (const char**)argv;
	int i;
	for (i = optind + 1; i < argc; ++i) {
	    if (argv[i][0] == '-') {
		if (argv[i][1] == '\0')
		    continue;
		if (argv[i][1] == '-' && argv[i][2] == '\0')
		    continue;
		/* found, move back */
		for (; i > optind; --i) {
		    const char* tmp;
		    tmp = mut_argv[i];
		    mut_argv[i] = mut_argv[i - 1];
		    mut_argv[i - 1] = tmp;
		}
		break;
	    }
    	}
	if (i == argc)
	    return -1;
    }

    /* we're here, so we have an option */
    optindind = 1;
    return getopt(argc, argv, optstring);
}

#endif /* !USE_MY_GETOPT */
