1 /* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
2 /*======================================================================
3 Copyright (C) 2004,2005,2009 Walter Doekes <walter+tthsum@wjd.nu>
4 This file is part of tthsum.
5 
6 tthsum is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 tthsum is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with tthsum.  If not, see <http://www.gnu.org/licenses/>.
18 ======================================================================*/
19 #include "getopt.h"
20 
21 
22 #ifdef USE_MY_GETOPT
23 #   include <stdio.h>
24 #   include <string.h>
25 
26 char* optarg;	/* option argument */
27 int optind = 0; /* argv index */
28 int opterr = 1; /* print errors on stderr */
29 int optopt = 0; /* the character found for '?' characters */
30 static int optindind = 0; /* letter-index for options at optind */
31 
getopt(int argc,char * const argv[],const char * optstring)32 int getopt(int argc, char* const argv[], const char* optstring) {
33     /* if optindind is set, we're looking at an option at optind */
34     if (optindind != 0) {
35 	int ret;
36 	const char* p = strchr(optstring, argv[optind][optindind]);
37 	/* unknown option */
38 	if (p == NULL) {
39 	    ret = '?';
40 	    optopt = argv[optind][optindind];
41 	    if (argv[optind][optindind + 1] != '\0') {
42 		++optindind;
43 	    } else {
44 		optindind = 0;
45 		++optind;
46 	    }
47 	    if (opterr)
48 		fprintf(stderr, "%s: invalid option -- %c\n",
49 			argv[0], optopt);
50 	    return '?';
51 	/* with-argument option */
52 	} else if (p[1] == ':') {
53 	    /* GNU extension: double colon means arg is optional */
54 	    ret = argv[optind][optindind];
55 	    /* argument is attached to option */
56 	    if (argv[optind][optindind + 1] != '\0') {
57 		optarg = argv[optind] + optindind + 1;
58 		optindind = 0;
59 		++optind;
60 	    /* argument is not attached and optional (GNU extension) */
61 	    } else if (p[2] == ':') {
62 		optarg = NULL;
63 		optindind = 0;
64 		++optind;
65 	    /* argument is not optional and loose */
66 	    } else {
67 		if (optind + 1 == argc) {
68 		    optopt = ret;
69 		    if (opterr)
70 			fprintf(stderr, "%s: option requires an argument"
71 				" -- %c\n", argv[0], optopt);
72 		    ret = '?';
73 		} else {
74 		    ++optind;
75 		    optarg = argv[optind];
76 		}
77 	    }
78 	    optindind = 0;
79 	    ++optind;
80 	/* correct non-argument option */
81 	} else {
82 	    ret = argv[optind][optindind];
83 	    if (argv[optind][optindind + 1] != '\0') {
84 		++optindind;
85 	    } else {
86 		optindind = 0;
87 		++optind;
88 	    }
89 	}
90 	return ret;
91     }
92 
93     /* if optind is zero, we haven't run yet */
94     if (optind <= 0) {
95 	optind = 1;
96 	optindind = 0;
97     }
98 
99     /* done? */
100     if (optind >= argc)
101 	return -1;
102 
103     /* end of options? */
104     if (argv[optind][0] == '-' && argv[optind][1] == '-'
105 	    && argv[optind][2] == '\0') {
106 	++optind;
107 	return -1;
108     }
109 
110     /* not an option? */
111     if (argv[optind][0] != '-') {
112 	/* find option and move it to front */
113 	const char** mut_argv = (const char**)argv;
114 	int i;
115 	for (i = optind + 1; i < argc; ++i) {
116 	    if (argv[i][0] == '-') {
117 		if (argv[i][1] == '\0')
118 		    continue;
119 		if (argv[i][1] == '-' && argv[i][2] == '\0')
120 		    continue;
121 		/* found, move back */
122 		for (; i > optind; --i) {
123 		    const char* tmp;
124 		    tmp = mut_argv[i];
125 		    mut_argv[i] = mut_argv[i - 1];
126 		    mut_argv[i - 1] = tmp;
127 		}
128 		break;
129 	    }
130     	}
131 	if (i == argc)
132 	    return -1;
133     }
134 
135     /* we're here, so we have an option */
136     optindind = 1;
137     return getopt(argc, argv, optstring);
138 }
139 
140 #endif /* !USE_MY_GETOPT */
141