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