From 18c635f474d504f24e73cb22a3e6bf006dbeed41 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 21 Jan 2014 14:16:51 +0100 Subject: [PATCH] Replaced Free Getopt with getopt_port. --- README.md | 2 +- deps/getopt.c | 467 +++++++++++++++++++++++--------------------------- deps/getopt.h | 94 +++++----- 3 files changed, 260 insertions(+), 303 deletions(-) diff --git a/README.md b/README.md index bd28c154..06fa7d2d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ The following dependencies are needed by GLFW: The following dependencies are needed by the examples and test programs: - - [Free Getopt](http://freegetopt.sourceforge.net/) for getopt + - [getopt\_port](https://github.com/kimgr/getopt_port/) for getopt - [TinyCThread](https://gitorious.org/tinythread/tinycthread/) for threading - An OpenGL loader generated by [glad](https://github.com/Dav1dde/glad) diff --git a/deps/getopt.c b/deps/getopt.c index 7b3decd2..f7f667a9 100644 --- a/deps/getopt.c +++ b/deps/getopt.c @@ -1,267 +1,230 @@ -/***************************************************************************** -* getopt.c - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in -* the documentation and/or other materials provided with the -* distribution. -* -* * Neither the original author of this software nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -* DAMAGE. -*/ -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ -#include -#include -#include #include "getopt.h" -/* 2013-01-06 Camilla Berglund - * - * Only define _CRT_SECURE_NO_WARNINGS if not already defined. - */ -/* 2012-08-12 Lambert Clara - * - * Constify third argument of getopt. - */ -/* 2011-07-27 Camilla Berglund - * - * Added _CRT_SECURE_NO_WARNINGS macro. - */ -/* 2009-10-12 Camilla Berglund - * - * Removed unused global static variable 'ID'. - */ +#include +#include -char* optarg = NULL; -int optind = 0; -int opterr = 1; -int optopt = '?'; +const int no_argument = 0; +const int required_argument = 1; +const int optional_argument = 2; +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; -static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ -static int prev_argc = 0; /* tell if getopt params change */ -static int argv_index = 0; /* Option we're checking */ -static int argv_index2 = 0; /* Option argument we're checking */ -static int opt_offset = 0; /* Index into compounded "-option" */ -static int dashdash = 0; /* True if "--" option reached */ -static int nonopt = 0; /* How many nonopts we've found */ +static char* optcursor = NULL; -static void increment_index() -{ - /* Move onto the next option */ - if(argv_index < argv_index2) - { - while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' - && argv_index < argv_index2+1); - } - else argv_index++; - opt_offset = 1; -} +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. - -/* -* Permutes argv[] so that the argument currently being processed is moved -* to the end. +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE */ -static int permute_argv_once() -{ - /* Movability check */ - if(argv_index + nonopt >= prev_argc) return 1; - /* Move the current option to the end, bring the others to front */ - else - { - char* tmp = prev_argv[argv_index]; +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; - /* Move the data */ - memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], - sizeof(char**) * (prev_argc - argv_index - 1)); - prev_argv[prev_argc - 1] = tmp; + optarg = NULL; + opterr = 0; + optopt = 0; - nonopt++; - return 0; - } + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) + goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') + optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for example, + "-oarg"), then it is returned in optarg, otherwise optarg is set + to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string pointed to by + an element of argv, then optarg shall contain the next element + of argv, and optind shall be incremented by 2. If the resulting + value of optind is greater than argc, this indicates a missing + option-argument, and getopt() shall return an error indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind shall be + incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall return the + colon character ( ':' ) if the first character of optstring + was a colon, or a question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') + ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; } +/* Implementation based on [1]. -int getopt(int argc, char** argv, const char* optstr) -{ - int c = 0; - - /* If we have new argv, reinitialize */ - if(prev_argv != argv || prev_argc != argc) - { - /* Initialize variables */ - prev_argv = argv; - prev_argc = argc; - argv_index = 1; - argv_index2 = 1; - opt_offset = 1; - dashdash = 0; - nonopt = 0; - } - - /* Jump point in case we want to ignore the current argv_index */ - getopt_top: - - /* Misc. initializations */ - optarg = NULL; - - /* Dash-dash check */ - if(argv[argv_index] && !strcmp(argv[argv_index], "--")) - { - dashdash = 1; - increment_index(); - } - - /* If we're at the end of argv, that's it. */ - if(argv[argv_index] == NULL) - { - c = -1; - } - /* Are we looking at a string? Single dash is also a string */ - else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) - { - /* If we want a string... */ - if(optstr[0] == '-') - { - c = 1; - optarg = argv[argv_index]; - increment_index(); - } - /* If we really don't want it (we're in POSIX mode), we're done */ - else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) - { - c = -1; - - /* Everything else is a non-opt argument */ - nonopt = argc - argv_index; - } - /* If we mildly don't want it, then move it back */ - else - { - if(!permute_argv_once()) goto getopt_top; - else c = -1; - } - } - /* Otherwise we're looking at an option */ - else - { - char* opt_ptr = NULL; - - /* Grab the option */ - c = argv[argv_index][opt_offset++]; - - /* Is the option in the optstr? */ - if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); - else opt_ptr = strchr(optstr, c); - /* Invalid argument */ - if(!opt_ptr) - { - if(opterr) - { - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - } - - optopt = c; - c = '?'; - - /* Move onto the next option */ - increment_index(); - } - /* Option takes argument */ - else if(opt_ptr[1] == ':') - { - /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ - if(argv[argv_index][opt_offset] != '\0') - { - optarg = &argv[argv_index][opt_offset]; - increment_index(); - } - /* ie, -o ARGUMENT (only if it's a required argument) */ - else if(opt_ptr[2] != ':') - { - /* One of those "you're not expected to understand this" moment */ - if(argv_index2 < argv_index) argv_index2 = argv_index; - while(argv[++argv_index2] && argv[argv_index2][0] == '-'); - optarg = argv[argv_index2]; - - /* Don't cross into the non-option argument list */ - if(argv_index2 + nonopt >= prev_argc) optarg = NULL; - - /* Move onto the next option */ - increment_index(); - } - else - { - /* Move onto the next option */ - increment_index(); - } - - /* In case we got no argument for an option with required argument */ - if(optarg == NULL && opt_ptr[2] != ':') - { - optopt = c; - c = '?'; - - if(opterr) - { - fprintf(stderr,"%s: option requires an argument -- %c\n", - argv[0], optopt); - } - } - } - /* Option does not take argument */ - else - { - /* Next argv_index */ - if(argv[argv_index][opt_offset] == '\0') - { - increment_index(); - } - } - } - - /* Calculate optind */ - if(c == -1) - { - optind = argc - nonopt; - } - else - { - optind = argv_index; - } - - return c; -} - - -/* vim:ts=3 +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html */ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) + return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) + *longindex = (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a variable + which shall be set to val if the option is found, but left unchanged if + the option is not found. */ + if (match->flag) + *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) + ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) + retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and BSD-based + implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/deps/getopt.h b/deps/getopt.h index 6d2e4afe..e1eb540f 100644 --- a/deps/getopt.h +++ b/deps/getopt.h @@ -1,63 +1,57 @@ -/***************************************************************************** -* getopt.h - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in -* the documentation and/or other materials provided with the -* distribution. -* -* * Neither the original author of this software nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -* DAMAGE. -*/ -#ifndef GETOPT_H_ -#define GETOPT_H_ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif +extern const int no_argument; +extern const int required_argument; +extern const int optional_argument; extern char* optarg; -extern int optind; -extern int opterr; -extern int optopt; +extern int optind, opterr, optopt; -int getopt(int argc, char** argv, const char* optstr); +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; +int getopt(int argc, char* const argv[], const char* optstring); -#ifdef __cplusplus +int getopt_long(int argc, char* const argv[], + const char* optstring, const struct option* longopts, int* longindex); + +#if defined(__cplusplus) } #endif - -#endif /* GETOPT_H_ */ - - -/* vim:ts=3 -*/ +#endif // INCLUDED_GETOPT_PORT_H