Setup TPM2-Plugin build environment
[aaf/sshsm.git] / SoftHSMv2 / src / bin / win32 / getopt.cpp
1 /*-
2  * Copyright (c) 2000 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Dieter Baron and Thomas Klausner.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *        This product includes software developed by the NetBSD
19  *        Foundation, Inc. and its contributors.
20  * 4. Neither the name of The NetBSD Foundation nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 #include <config.h>
38 #include <getopt.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #ifdef _WIN32
43
44 /* Windows needs warnx().  We change the definition though:
45  *  1. (another) global is defined, opterrmsg, which holds the error message
46  *  2. errors are always printed out on stderr w/o the program name
47  * Note that opterrmsg always gets set no matter what opterr is set to.  The
48  * error message will not be printed if opterr is 0 as usual.
49  */
50
51 #include <stdio.h>
52 #include <stdarg.h>
53
54 extern char opterrmsg[128];
55 char opterrmsg[128]; /* last error message is stored here */
56
57 static void warnx(int print_error, const char *fmt, ...)
58 {
59         va_list ap;
60         va_start(ap, fmt);
61         if (fmt != NULL)
62                 _vsnprintf(opterrmsg, 128, fmt, ap);
63         else
64                 opterrmsg[0]='\0';
65         va_end(ap);
66         if (print_error) {
67                 fprintf(stderr, opterrmsg);
68                 fprintf(stderr, "\n");
69         }
70 }
71
72 #endif /*_WIN32*/
73
74 /* not part of the original file */
75 #ifndef _DIAGASSERT
76 #define _DIAGASSERT(X)
77 #endif
78
79 #if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
80 #define REPLACE_GETOPT
81 #endif
82
83 int     opterr = 1;             /* if error message should be printed */
84 int     optind = 1;             /* index into parent argv vector */
85 int     optopt = '?';           /* character checked for validity */
86 int     optreset;               /* reset getopt */
87 char    *optarg;                /* argument associated with option */
88
89 #if !HAVE_GETOPT_LONG
90 #define IGNORE_FIRST    (*options == '-' || *options == '+')
91 #define PRINT_ERROR     ((opterr) && ((*options != ':') \
92                                       || (IGNORE_FIRST && options[1] != ':')))
93 #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
94 #define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
95 /* XXX: GNU ignores PC if *options == '-' */
96 #define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
97
98 /* return values */
99 #define BADCH   (int)'?'
100 #define BADARG          ((IGNORE_FIRST && options[1] == ':') \
101                          || (*options == ':') ? (int)':' : (int)'?')
102 #define INORDER (int)1
103
104 #define EMSG    ""
105
106 static int getopt_internal(int, char * const *, const char *);
107 static int gcd(int, int);
108 static void permute_args(int, int, int, char * const *);
109
110 static char *place = EMSG; /* option letter processing */
111
112 /* XXX: set optreset to 1 rather than these two */
113 static int nonopt_start = -1; /* first non option argument (for permute) */
114 static int nonopt_end = -1;   /* first option after non options (for permute) */
115
116 /* Error messages */
117 static const char recargchar[] = "option requires an argument -- %c";
118 static const char recargstring[] = "option requires an argument -- %s";
119 static const char ambig[] = "ambiguous option -- %.*s";
120 static const char noarg[] = "option doesn't take an argument -- %.*s";
121 static const char illoptchar[] = "unknown option -- %c";
122 static const char illoptstring[] = "unknown option -- %s";
123
124
125 /*
126  * Compute the greatest common divisor of a and b.
127  */
128 static int
129 gcd(int a, int b)
130 {
131         int c;
132
133         c = a % b;
134         while (c != 0) {
135                 a = b;
136                 b = c;
137                 c = a % b;
138         }
139            
140         return b;
141 }
142
143 /*
144  * Exchange the block from nonopt_start to nonopt_end with the block
145  * from nonopt_end to opt_end (keeping the same order of arguments
146  * in each block).
147  */
148 static void
149 permute_args(int panonopt_start, int panonopt_end,
150              int opt_end, char * const *nargv)
151 {
152         int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
153         char *swap;
154
155         _DIAGASSERT(nargv != NULL);
156
157         /*
158          * compute lengths of blocks and number and size of cycles
159          */
160         nnonopts = panonopt_end - panonopt_start;
161         nopts = opt_end - panonopt_end;
162         ncycle = gcd(nnonopts, nopts);
163         cyclelen = (opt_end - panonopt_start) / ncycle;
164
165         for (i = 0; i < ncycle; i++) {
166                 cstart = panonopt_end+i;
167                 pos = cstart;
168                 for (j = 0; j < cyclelen; j++) {
169                         if (pos >= panonopt_end)
170                                 pos -= nnonopts;
171                         else
172                                 pos += nopts;
173                         swap = nargv[pos];
174                         /* LINTED const cast */
175                         ((char **) nargv)[pos] = nargv[cstart];
176                         /* LINTED const cast */
177                         ((char **)nargv)[cstart] = swap;
178                 }
179         }
180 }
181
182 /*
183  * getopt_internal --
184  *      Parse argc/argv argument vector.  Called by user level routines.
185  *  Returns -2 if -- is found (can be long option or end of options marker).
186  */
187 static int
188 getopt_internal(int nargc, char * const *nargv, const char *options)
189 {
190         char *oli;                              /* option letter list index */
191         int optchar;
192
193         _DIAGASSERT(nargv != NULL);
194         _DIAGASSERT(options != NULL);
195
196         optarg = NULL;
197
198         /*
199          * XXX Some programs (like rsyncd) expect to be able to
200          * XXX re-initialize optind to 0 and have getopt_long(3)
201          * XXX properly function again.  Work around this braindamage.
202          */
203         if (optind == 0)
204                 optind = 1;
205
206         if (optreset)
207                 nonopt_start = nonopt_end = -1;
208 start:
209         if (optreset || !*place) {              /* update scanning pointer */
210                 optreset = 0;
211                 if (optind >= nargc) {          /* end of argument vector */
212                         place = EMSG;
213                         if (nonopt_end != -1) {
214                                 /* do permutation, if we have to */
215                                 permute_args(nonopt_start, nonopt_end,
216                                     optind, nargv);
217                                 optind -= nonopt_end - nonopt_start;
218                         }
219                         else if (nonopt_start != -1) {
220                                 /*
221                                  * If we skipped non-options, set optind
222                                  * to the first of them.
223                                  */
224                                 optind = nonopt_start;
225                         }
226                         nonopt_start = nonopt_end = -1;
227                         return -1;
228                 }
229                 if ((*(place = nargv[optind]) != '-')
230                     || (place[1] == '\0')) {    /* found non-option */
231                         place = EMSG;
232                         if (IN_ORDER) {
233                                 /*
234                                  * GNU extension: 
235                                  * return non-option as argument to option 1
236                                  */
237                                 optarg = nargv[optind++];
238                                 return INORDER;
239                         }
240                         if (!PERMUTE) {
241                                 /*
242                                  * if no permutation wanted, stop parsing
243                                  * at first non-option
244                                  */
245                                 return -1;
246                         }
247                         /* do permutation */
248                         if (nonopt_start == -1)
249                                 nonopt_start = optind;
250                         else if (nonopt_end != -1) {
251                                 permute_args(nonopt_start, nonopt_end,
252                                     optind, nargv);
253                                 nonopt_start = optind -
254                                     (nonopt_end - nonopt_start);
255                                 nonopt_end = -1;
256                         }
257                         optind++;
258                         /* process next argument */
259                         goto start;
260                 }
261                 if (nonopt_start != -1 && nonopt_end == -1)
262                         nonopt_end = optind;
263                 if (place[1] && *++place == '-') {      /* found "--" */
264                         place++;
265                         return -2;
266                 }
267         }
268         if ((optchar = (int)*place++) == (int)':' ||
269             (oli = (char *) strchr(options + (IGNORE_FIRST ? 1 : 0),
270                                    optchar)) == NULL) {
271                 /* option letter unknown or ':' */
272                 if (!*place)
273                         ++optind;
274 #ifndef _WIN32
275                 if (PRINT_ERROR)
276                         warnx(illoptchar, optchar);
277 #else
278                         warnx(PRINT_ERROR, illoptchar, optchar);
279 #endif
280                 optopt = optchar;
281                 return BADCH;
282         }
283         if (optchar == 'W' && oli[1] == ';') {          /* -W long-option */
284                 /* XXX: what if no long options provided (called by getopt)? */
285                 if (*place) 
286                         return -2;
287
288                 if (++optind >= nargc) {        /* no arg */
289                         place = EMSG;
290 #ifndef _WIN32
291                         if (PRINT_ERROR)
292                                 warnx(recargchar, optchar);
293 #else
294                                 warnx(PRINT_ERROR, recargchar, optchar);
295 #endif
296                         optopt = optchar;
297                         return BADARG;
298                 } else                          /* white space */
299                         place = nargv[optind];
300                 /*
301                  * Handle -W arg the same as --arg (which causes getopt to
302                  * stop parsing).
303                  */
304                 return -2;
305         }
306         if (*++oli != ':') {                    /* doesn't take argument */
307                 if (!*place)
308                         ++optind;
309         } else {                                /* takes (optional) argument */
310                 optarg = NULL;
311                 if (*place)                     /* no white space */
312                         optarg = place;
313                 /* XXX: disable test for :: if PC? (GNU doesn't) */
314                 else if (oli[1] != ':') {       /* arg not optional */
315                         if (++optind >= nargc) {        /* no arg */
316                                 place = EMSG;
317 #ifndef _WIN32
318                                 if (PRINT_ERROR)
319                                         warnx(recargchar, optchar);
320 #else
321                                         warnx(PRINT_ERROR, recargchar, optchar);
322 #endif
323                                 optopt = optchar;
324                                 return BADARG;
325                         } else
326                                 optarg = nargv[optind];
327                 }
328                 place = EMSG;
329                 ++optind;
330         }
331         /* dump back option letter */
332         return optchar;
333 }
334
335 /*
336  * getopt --
337  *      Parse argc/argv argument vector.
338  *
339  * [eventually this will replace the real getopt]
340  */
341 int
342 getopt(int nargc, char * const *nargv, const char *options)
343 {
344         int retval;
345
346         _DIAGASSERT(nargv != NULL);
347         _DIAGASSERT(options != NULL);
348
349         if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
350                 ++optind;
351                 /*
352                  * We found an option (--), so if we skipped non-options,
353                  * we have to permute.
354                  */
355                 if (nonopt_end != -1) {
356                         permute_args(nonopt_start, nonopt_end, optind,
357                                        nargv);
358                         optind -= nonopt_end - nonopt_start;
359                 }
360                 nonopt_start = nonopt_end = -1;
361                 retval = -1;
362         }
363         return retval;
364 }
365
366 /*
367  * getopt_long --
368  *      Parse argc/argv argument vector.
369  */
370 int
371 getopt_long(int nargc,
372             char * const *nargv,
373             const char *options,
374             const struct option *long_options,
375             int *idx)
376 {
377         int retval;
378
379         _DIAGASSERT(nargv != NULL);
380         _DIAGASSERT(options != NULL);
381         _DIAGASSERT(long_options != NULL);
382         /* idx may be NULL */
383
384         if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
385                 char *current_argv, *has_equal;
386                 size_t current_argv_len;
387                 int i, match;
388
389                 current_argv = place;
390                 match = -1;
391
392                 optind++;
393                 place = EMSG;
394
395                 if (*current_argv == '\0') {            /* found "--" */
396                         /*
397                          * We found an option (--), so if we skipped
398                          * non-options, we have to permute.
399                          */
400                         if (nonopt_end != -1) {
401                                 permute_args(nonopt_start, nonopt_end,
402                                     optind, nargv);
403                                 optind -= nonopt_end - nonopt_start;
404                         }
405                         nonopt_start = nonopt_end = -1;
406                         return -1;
407                 }
408                 if ((has_equal = strchr(current_argv, '=')) != NULL) {
409                         /* argument found (--option=arg) */
410                         current_argv_len = has_equal - current_argv;
411                         has_equal++;
412                 } else
413                         current_argv_len = strlen(current_argv);
414             
415                 for (i = 0; long_options[i].name; i++) {
416                         /* find matching long option */
417                         if (strncmp(current_argv, long_options[i].name,
418                             current_argv_len))
419                                 continue;
420
421                         if (strlen(long_options[i].name) ==
422                             (unsigned)current_argv_len) {
423                                 /* exact match */
424                                 match = i;
425                                 break;
426                         }
427                         if (match == -1)                /* partial match */
428                                 match = i;
429                         else {
430                                 /* ambiguous abbreviation */
431 #ifndef _WIN32
432                                 if (PRINT_ERROR)
433                                         warnx(ambig, (int)current_argv_len,
434                                              current_argv);
435 #else
436                                         warnx(PRINT_ERROR, ambig, (int)current_argv_len,
437                                              current_argv);
438 #endif
439                                 optopt = 0;
440                                 return BADCH;
441                         }
442                 }
443                 if (match != -1) {                      /* option found */
444                         if (long_options[match].has_arg == no_argument
445                             && has_equal) {
446 #ifndef _WIN32
447                                 if (PRINT_ERROR)
448                                         warnx(noarg, (int)current_argv_len,
449                                              current_argv);
450 #else
451                                         warnx(PRINT_ERROR, noarg, (int)current_argv_len,
452                                              current_argv);
453 #endif
454                                 /*
455                                  * XXX: GNU sets optopt to val regardless of
456                                  * flag
457                                  */
458                                 if (long_options[match].flag == NULL)
459                                         optopt = long_options[match].val;
460                                 else
461                                         optopt = 0;
462                                 return BADARG;
463                         }
464                         if (long_options[match].has_arg == required_argument ||
465                             long_options[match].has_arg == optional_argument) {
466                                 if (has_equal)
467                                         optarg = has_equal;
468                                 else if (long_options[match].has_arg ==
469                                     required_argument) {
470                                         /*
471                                          * optional argument doesn't use
472                                          * next nargv
473                                          */
474                                         optarg = nargv[optind++];
475                                 }
476                         }
477                         if ((long_options[match].has_arg == required_argument)
478                             && (optarg == NULL)) {
479                                 /*
480                                  * Missing argument; leading ':'
481                                  * indicates no error should be generated
482                                  */
483 #ifndef _WIN32
484                                 if (PRINT_ERROR)
485                                         warnx(recargstring, current_argv);
486 #else
487                                         warnx(PRINT_ERROR, recargstring, current_argv);
488 #endif
489                                 /*
490                                  * XXX: GNU sets optopt to val regardless
491                                  * of flag
492                                  */
493                                 if (long_options[match].flag == NULL)
494                                         optopt = long_options[match].val;
495                                 else
496                                         optopt = 0;
497                                 --optind;
498                                 return BADARG;
499                         }
500                 } else {                        /* unknown option */
501 #ifndef _WIN32
502                         if (PRINT_ERROR)
503                                 warnx(illoptstring, current_argv);
504 #else
505                                 warnx(PRINT_ERROR, illoptstring, current_argv);
506 #endif
507                         optopt = 0;
508                         return BADCH;
509                 }
510                 if (long_options[match].flag) {
511                         *long_options[match].flag = long_options[match].val;
512                         retval = 0;
513                 } else 
514                         retval = long_options[match].val;
515                 if (idx)
516                         *idx = match;
517         }
518         return retval;
519 }
520 #endif /* !GETOPT_LONG */