1 /*
2 * Copyright (C) 2006 Josh A. Beam
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 /*
27 * This is a simple getopt implementation for use by prtunnel
28 * on win32 systems. Note that it only supports the features
29 * that prtunnel actually uses, so it doesn't have an opterr
30 * variable, for example.
31 */
32
33 #ifdef _WIN32
34 #include <stdio.h>
35 #include <string.h>
36 #include "getopt.h"
37
38 #ifndef NULL
39 #define NULL 0
40 #endif
41
42 int optind = 1;
43 char *optarg = NULL;
44
45 /*
46 * if opt is an option found in optstring, return opt. otherwise,
47 * return -1. if opt is valid and it has an argument, set the int
48 * pointed to by has_argument to 1. otherwise, set it 0.
49 */
50 static char
get_matching_option(char opt,const char * optstring,int * has_argument)51 get_matching_option(char opt, const char *optstring, int *has_argument)
52 {
53 int i;
54
55 for(i = 0; i < strlen(optstring); i++) {
56 if(opt == optstring[i]) {
57 /* if there's a colon after this character, the option has
58 * an argument */
59 if((i + 1) < strlen(optstring) && optstring[i+1] == ':')
60 *has_argument = 1;
61 else
62 *has_argument = 0;
63
64 return opt;
65 }
66 }
67
68 return -1;
69 }
70
71 /*
72 * permutes argv so that the argument at the specified
73 * index appears at the end of the array.
74 */
75 static void
permute_arguments(int argc,char * argv[],int index)76 permute_arguments(int argc, char *argv[], int index)
77 {
78 int i;
79 char *tmp = argv[index];
80
81 for(i = index; i < (argc - 1); i++)
82 argv[i] = argv[i+1];
83
84 argv[argc-1] = tmp;
85 }
86
87 int
getopt(int argc,char * argv[],const char * optstring)88 getopt(int argc, char *argv[], const char *optstring)
89 {
90 static int current_arg = 1;
91 static int current_char = 1;
92 static int loop_argc = -1;
93 int i;
94
95 /* loop_argc is used instead of argc directly so that the
96 * permuted arguments are not scanned more than once. this
97 * is done by decrementing loop_argc every time an
98 * argument is permuted. note that the permute_arguments
99 * function still needs to be given the actual argc.*/
100 if(loop_argc < 0)
101 loop_argc = argc;
102
103 if(current_arg >= argc) /* past end of arguments */
104 return -1;
105
106 /* loop through each argument */
107 for(i = current_arg; i < loop_argc; i++, current_arg++) {
108 char opt;
109 int has_argument;
110
111 if(*argv[i] != '-') { /* not an option string */
112 permute_arguments(argc, argv, i);
113 i--; /* arguments have been re-arranged, so the one at
114 * this index needs to be looked at again */
115 current_arg--;
116 loop_argc--;
117 continue;
118 } else if(current_char == 1) {
119 optind++;
120 }
121
122 if(current_char >= strlen(argv[i])) { /* past end of argument */
123 current_char = 1;
124 continue;
125 }
126
127 /* if the current character matches an option in the option string,
128 * return the character. otherwise, return '?' */
129 opt = get_matching_option(argv[i][current_char], optstring, &has_argument);
130 if(opt != -1) {
131 /* if the option has an argument, set optarg pointer. if
132 * the argument is missing, return ':' */
133 if(has_argument) {
134 /* if there are any characters after the current one
135 * in this argument, use those as the option argument.
136 * otherwise, use the next argument */
137 if(current_char < (strlen(argv[i]) - 1)) {
138 optarg = argv[i] + current_char + 1;
139 current_arg++; /* set past the option argument */
140 current_char = 0; /* reset */
141 } else {
142 current_arg += 2; /* set past the option argument */
143 current_char = 0; /* reset */
144 optind++;
145 if((i + 1) < loop_argc) {
146 optarg = argv[i + 1];
147 } else {
148 optarg = NULL;
149 current_char++;
150 return ':';
151 }
152 }
153 }
154
155 current_char++;
156 return (int)opt;
157 } else {
158 current_char++;
159 return '?';
160 }
161 }
162
163 #ifdef DEBUG_GETOPT
164 printf("argv:");
165 for(i = 0; i < argc; i++)
166 printf(" %s", argv[i]);
167 printf("\n");
168 #endif /* DEBUG_GETOPT */
169
170 /* reached end of arguments */
171 return -1;
172 }
173 #endif /* _WIN32 */
174