mirror of
https://github.com/ScrelliCopter/tmx2gba.git
synced 2025-02-21 03:29:25 +11:00
MSVC build fix & buildsystem overhaul
This commit is contained in:
11
src/CMakeLists.txt
Normal file
11
src/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
add_executable(tmx2gba
|
||||
tmx2gba.cpp
|
||||
tmxlayer.cpp tmxlayer.h
|
||||
tmxobject.cpp tmxobject.h
|
||||
tmxreader.cpp tmxreader.h
|
||||
tmxtileset.cpp tmxtileset.h)
|
||||
target_link_libraries(tmx2gba
|
||||
External::base64
|
||||
External::miniz
|
||||
External::rapidxml
|
||||
External::ultragetopt)
|
||||
212
src/XGetopt.cpp
212
src/XGetopt.cpp
@@ -1,212 +0,0 @@
|
||||
// XGetopt.cpp Version 1.2
|
||||
//
|
||||
// Author: Hans Dietrich
|
||||
// hdietrich2@hotmail.com
|
||||
//
|
||||
// Description:
|
||||
// XGetopt.cpp implements getopt(), a function to parse command lines.
|
||||
//
|
||||
// History
|
||||
// Version 1.2 - 2003 May 17
|
||||
// - Added Unicode support
|
||||
//
|
||||
// Version 1.1 - 2002 March 10
|
||||
// - Added example to XGetopt.cpp module header
|
||||
//
|
||||
// This software is released into the public domain.
|
||||
// You are free to use it in any way you like.
|
||||
//
|
||||
// This software is provided "as is" with no expressed
|
||||
// or implied warranty. I accept no liability for any
|
||||
// damage or loss of business that this software may cause.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// if you are not using precompiled headers then include these lines:
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "XGetopt.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// X G e t o p t . c p p
|
||||
//
|
||||
//
|
||||
// NAME
|
||||
// getopt -- parse command line options
|
||||
//
|
||||
// SYNOPSIS
|
||||
// int getopt(int argc, char *argv[], char *optstring)
|
||||
//
|
||||
// extern char *optarg;
|
||||
// extern int optind;
|
||||
//
|
||||
// DESCRIPTION
|
||||
// The getopt() function parses the command line arguments. Its
|
||||
// arguments argc and argv are the argument count and array as
|
||||
// passed into the application on program invocation. In the case
|
||||
// of Visual C++ programs, argc and argv are available via the
|
||||
// variables __argc and __argv (double underscores), respectively.
|
||||
// getopt returns the next option letter in argv that matches a
|
||||
// letter in optstring. (Note: Unicode programs should use
|
||||
// __targv instead of __argv. Also, all character and string
|
||||
// literals should be enclosed in _T( ) ).
|
||||
//
|
||||
// optstring is a string of recognized option letters; if a letter
|
||||
// is followed by a colon, the option is expected to have an argument
|
||||
// that may or may not be separated from it by white space. optarg
|
||||
// is set to point to the start of the option argument on return from
|
||||
// getopt.
|
||||
//
|
||||
// Option letters may be combined, e.g., "-ab" is equivalent to
|
||||
// "-a -b". Option letters are case sensitive.
|
||||
//
|
||||
// getopt places in the external variable optind the argv index
|
||||
// of the next argument to be processed. optind is initialized
|
||||
// to 0 before the first call to getopt.
|
||||
//
|
||||
// When all options have been processed (i.e., up to the first
|
||||
// non-option argument), getopt returns EOF, optarg will point
|
||||
// to the argument, and optind will be set to the argv index of
|
||||
// the argument. If there are no non-option arguments, optarg
|
||||
// will be set to nullptr.
|
||||
//
|
||||
// The special option "--" may be used to delimit the end of the
|
||||
// options; EOF will be returned, and "--" (and everything after it)
|
||||
// will be skipped.
|
||||
//
|
||||
// RETURN VALUE
|
||||
// For option letters contained in the string optstring, getopt
|
||||
// will return the option letter. getopt returns a question mark (?)
|
||||
// when it encounters an option letter not included in optstring.
|
||||
// EOF is returned when processing is finished.
|
||||
//
|
||||
// BUGS
|
||||
// 1) Long options are not supported.
|
||||
// 2) The GNU double-colon extension is not supported.
|
||||
// 3) The environment variable POSIXLY_CORRECT is not supported.
|
||||
// 4) The + syntax is not supported.
|
||||
// 5) The automatic permutation of arguments is not supported.
|
||||
// 6) This implementation of getopt() returns EOF if an error is
|
||||
// encountered, instead of -1 as the latest standard requires.
|
||||
//
|
||||
// EXAMPLE
|
||||
// BOOL CMyApp::ProcessCommandLine(int argc, char *argv[])
|
||||
// {
|
||||
// int c;
|
||||
//
|
||||
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
|
||||
// {
|
||||
// switch (c)
|
||||
// {
|
||||
// case _T('a'):
|
||||
// TRACE(_T("option a\n"));
|
||||
// //
|
||||
// // set some flag here
|
||||
// //
|
||||
// break;
|
||||
//
|
||||
// case _T('B'):
|
||||
// TRACE( _T("option B\n"));
|
||||
// //
|
||||
// // set some other flag here
|
||||
// //
|
||||
// break;
|
||||
//
|
||||
// case _T('n'):
|
||||
// TRACE(_T("option n: value=%d\n"), atoi(optarg));
|
||||
// //
|
||||
// // do something with value here
|
||||
// //
|
||||
// break;
|
||||
//
|
||||
// case _T('?'):
|
||||
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
|
||||
// return FALSE;
|
||||
// break;
|
||||
//
|
||||
// default:
|
||||
// TRACE(_T("WARNING: no handler for option %c\n"), c);
|
||||
// return FALSE;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// //
|
||||
// // check for non-option args here
|
||||
// //
|
||||
// return TRUE;
|
||||
// }
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char *optarg; // global argument pointer
|
||||
char *next;
|
||||
int optind = 0; // global argv index
|
||||
|
||||
int getopt(int argc, char *argv[], char *optstring)
|
||||
{
|
||||
if (optind == 0)
|
||||
next = nullptr;
|
||||
|
||||
optarg = nullptr;
|
||||
|
||||
if (next == nullptr || *next == '\0')
|
||||
{
|
||||
if (optind == 0)
|
||||
optind++;
|
||||
|
||||
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
{
|
||||
optarg = nullptr;
|
||||
if (optind < argc)
|
||||
optarg = argv[optind];
|
||||
return EOF;
|
||||
}
|
||||
|
||||
if (strcmp(argv[optind], "--") == 0)
|
||||
{
|
||||
optind++;
|
||||
optarg = nullptr;
|
||||
if (optind < argc)
|
||||
optarg = argv[optind];
|
||||
return EOF;
|
||||
}
|
||||
|
||||
next = argv[optind];
|
||||
next++; // skip past -
|
||||
optind++;
|
||||
}
|
||||
|
||||
char c = *next++;
|
||||
char *cp = strchr(optstring, c);
|
||||
|
||||
if (cp == nullptr || c == ':')
|
||||
return '?';
|
||||
|
||||
cp++;
|
||||
if (*cp == ':')
|
||||
{
|
||||
if (*next != '\0')
|
||||
{
|
||||
optarg = next;
|
||||
next = nullptr;
|
||||
}
|
||||
else if (optind < argc)
|
||||
{
|
||||
optarg = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
123
src/base64.cpp
123
src/base64.cpp
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
#include <iostream>
|
||||
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string const& encoded_string) {
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* tmx2gba.cpp
|
||||
|
||||
Copyright (C) 2015-2019 Nicholas Curtis (a dinosaur)
|
||||
Copyright (C) 2015-2022 a dinosaur
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* tmxlayer.cpp
|
||||
|
||||
Copyright (C) 2015 Nicholas Curtis
|
||||
Copyright (C) 2015 a dinosaur
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* tmxobject.cpp
|
||||
|
||||
Copyright (C) 2015 Nicholas Curtis
|
||||
Copyright (C) 2015 a dinosaur
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* tmxreader.cpp
|
||||
|
||||
Copyright (C) 2015 Nicholas Curtis
|
||||
Copyright (C) 2015 a dinosaur
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <rapidxml/rapidxml.hpp>
|
||||
#include <rapidxml.hpp>
|
||||
#include <base64.h>
|
||||
#include <miniz.h>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <rapidxml/rapidxml.hpp>
|
||||
#include <rapidxml.hpp>
|
||||
|
||||
class CTmxTileset;
|
||||
class CTmxLayer;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* tmxtileset.cpp
|
||||
|
||||
Copyright (C) 2015 Nicholas Curtis
|
||||
Copyright (C) 2015 a dinosaur
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,826 +0,0 @@
|
||||
/* Ultra-Getopt - A replacement for getopt() with support for many common
|
||||
* extensions, MS-DOS formatted option strings, and much more.
|
||||
*
|
||||
* To use this library as a replacement for vendor-provided getopt() functions,
|
||||
* define ULTRAGETOPT_REPLACE_GETOPT and include "ultragetopt.h" after the
|
||||
* vendor-provided headers for getopt() functions.
|
||||
*
|
||||
* Copyright (C) 2007-2011, Kevin Locke <kevin@kevinlocke.name>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h> /* islower() isupper() tolower() toupper() */
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h> /* fprintf() */
|
||||
#include <stdlib.h> /* getenv() */
|
||||
#include <string.h> /* strcmp(), strncmp(), strchr() */
|
||||
|
||||
#if HAVE_STRINGS_H
|
||||
# include <strings.h> /* strcasecmp(), strncasecmp() */
|
||||
#endif
|
||||
|
||||
#undef ULTRAGETOPT_REPLACE_GETOPT /* Protect against project-wide defines */
|
||||
#include "ultragetopt.h"
|
||||
|
||||
/* Define replacements for missing functions */
|
||||
#if !HAVE_STRCASECMP && HAVE__STRICMP
|
||||
# define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#if !HAVE_STRNCASECMP && HAVE__STRNICMP
|
||||
# define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
#if !HAVE_STRCHR && HAVE_INDEX
|
||||
# define strchr index
|
||||
#endif
|
||||
|
||||
/* Supported defines:
|
||||
* ULTRAGETOPT_LIKE_BSD Behave like BSD getopt()
|
||||
* ULTRAGETOPT_LIKE_DARWIN Behave like Darwin (Mac OS) getopt()
|
||||
* ULTRAGETOPT_LIKE_GNU Behave like GNU getopt()
|
||||
* ULTRAGETOPT_LIKE_POSIX Behave like POSIX definition of getopt()
|
||||
*
|
||||
* ULTRAGETOPT_ASSIGNSPACE Parse "-o value" as "value" rather than " value"
|
||||
* Note: Only applicable when argv[x] == "-o value"
|
||||
* Not for argv[x] == "-o" [x+1] == "value"
|
||||
* ULTRAGETOPT_DEFAULTOPTOPT Set optopt to this value by default on each
|
||||
* call to getopt()
|
||||
* ULTRAGETOPT_HYPHENARG Accept -option -arg as -option with argument
|
||||
* "-arg" rather than -option missing argument
|
||||
* Note: A single "-" is always accepted as an
|
||||
* argument
|
||||
* ULTRAGETOPT_LONGOPTADJACENT Accept adjacent arguments to long options
|
||||
* (e.g. --optionarg) based on first longest-match
|
||||
* ULTRAGETOPT_OPTIONPERMUTE Permute options, do not stop at first non-option
|
||||
* Behaves like GNU getopt where leading '+' or
|
||||
* $POSIXLY_CORRECT both stop this @ runtime
|
||||
* ULTRAGETOPT_SHORTOPTASSIGN Support -o=file syntax for short options
|
||||
* ULTRAGETOPT_SEPARATEDOPTIONAL Accept separated optional arguments
|
||||
* Parse -o file as -o with argument file
|
||||
* ULTRAGETOPT_DOS_DASH Support - and -- options in ultragetopt*_dos()
|
||||
* ULTRAGETOPT_BSD_ERRORS Print error messages matching BSD getopt
|
||||
* ULTRAGETOPT_DARWIN_ERRORS Print error messages matching Darwin getopt
|
||||
* ULTRAGETOPT_GNU_ERRORS Print error messages matching GNU getopt
|
||||
* ULTRAGETOPT_NO_EATDASHDASH Do not increment optind when argv[optind] is --
|
||||
* ULTRAGETOPT_NO_OPTIONALARG Do not support GNU "::" optional argument
|
||||
* Always supported in *_long*()
|
||||
* ULTRAGETOPT_NO_OPTIONASSIGN Do not support --option=value syntax
|
||||
*/
|
||||
|
||||
#ifdef ULTRAGETOPT_LIKE_POSIX
|
||||
# define ULTRAGETOPT_NO_OPTIONALARG
|
||||
# define ULTRAGETOPT_NO_OPTIONASSIGN
|
||||
# undef ULTRAGETOPT_NO_EATDASHDASH
|
||||
# undef ULTRAGETOPT_ASSIGNSPACE
|
||||
# undef ULTRAGETOPT_BSD_ERRORS
|
||||
# undef ULTRAGETOPT_DARWIN_ERRORS
|
||||
# undef ULTRAGETOPT_GNU_ERRORS
|
||||
# undef ULTRAGETOPT_OPTIONPERMUTE
|
||||
# undef ULTRAGETOPT_SHORTOPTASSIGN
|
||||
#elif defined(ULTRAGETOPT_LIKE_GNU)
|
||||
# define ULTRAGETOPT_GNU_ERRORS
|
||||
# define ULTRAGETOPT_HYPHENARG
|
||||
# define ULTRAGETOPT_OPTIONPERMUTE
|
||||
# undef ULTRAGETOPT_ASSIGNSPACE
|
||||
# undef ULTRAGETOPT_NO_OPTIONALARG
|
||||
# undef ULTRAGETOPT_NO_OPTIONASSIGN
|
||||
# undef ULTRAGETOPT_NO_EATDASHDASH
|
||||
# undef ULTRAGETOPT_SHORTOPTASSIGN
|
||||
# undef ULTRAGETOPT_SEPARATEOPTIONAL
|
||||
# undef ULTRAGETOPT_LONGOPTADJACENT
|
||||
#elif defined(ULTRAGETOPT_LIKE_BSD)
|
||||
# define ULTRAGETOPT_BSD_ERRORS
|
||||
# define ULTRAGETOPT_OPTIONPERMUTE
|
||||
# define ULTRAGETOPT_DEFAULTOPTOPT '?'
|
||||
# undef ULTRAGETOPT_ASSIGNSPACE
|
||||
# undef ULTRAGETOPT_NO_OPTIONALARG
|
||||
# undef ULTRAGETOPT_NO_OPTIONASSIGN
|
||||
# undef ULTRAGETOPT_NO_EATDASHDASH
|
||||
# undef ULTRAGETOPT_SHORTOPTASSIGN
|
||||
# undef ULTRAGETOPT_SEPARATEOPTIONAL
|
||||
# undef ULTRAGETOPT_LONGOPTADJACENT
|
||||
#elif defined(ULTRAGETOPT_LIKE_DARWIN)
|
||||
# define ULTRAGETOPT_DARWIN_ERRORS
|
||||
# define ULTRAGETOPT_OPTIONPERMUTE
|
||||
# undef ULTRAGETOPT_ASSIGNSPACE
|
||||
# undef ULTRAGETOPT_NO_OPTIONALARG
|
||||
# undef ULTRAGETOPT_NO_OPTIONASSIGN
|
||||
# undef ULTRAGETOPT_SHORTOPTASSIGN
|
||||
# undef ULTRAGETOPT_NO_EATDASHDASH
|
||||
# undef ULTRAGETOPT_SEPARATEOPTIONAL
|
||||
# undef ULTRAGETOPT_LONGOPTADJACENT
|
||||
#endif
|
||||
|
||||
#ifdef ULTRAGETOPT_NO_OPTIONASSIGN
|
||||
static const char *const unixassigners = "";
|
||||
static const char *const dosassigners = ":";
|
||||
#elif defined(ULTRAGETOPT_OPTIONSPACE)
|
||||
static const char *const unixassigners = "= ";
|
||||
static const char *const dosassigners = ":= ";
|
||||
#else
|
||||
static const char *const unixassigners = "=";
|
||||
static const char *const dosassigners = ":=";
|
||||
#endif
|
||||
|
||||
#ifdef ULTRAGETOPT_DOS_DASH
|
||||
static const char *const unixleaders = "-";
|
||||
static const char *const dosleaders = "/-";
|
||||
#else
|
||||
static const char *const unixleaders = "-";
|
||||
static const char *const dosleaders = "/";
|
||||
#endif
|
||||
|
||||
/* Flags for all variants of ultragetopt*() */
|
||||
static const int getoptflags = 0
|
||||
#ifdef ULTRAGETOPT_SEPARATEDOPTIONAL
|
||||
| UGO_SEPARATEDOPTIONAL
|
||||
#endif
|
||||
#ifdef ULTRAGETOPT_SHORTOPTASSIGN
|
||||
| UGO_SHORTOPTASSIGN
|
||||
#endif
|
||||
#ifdef ULTRAGETOPT_NO_EATDASHDASH
|
||||
| UGO_NOEATDASHDASH
|
||||
#endif
|
||||
#ifdef ULTRAGETOPT_HYPHENARG
|
||||
| UGO_HYPHENARG
|
||||
#endif
|
||||
;
|
||||
|
||||
#ifdef ULTRAGETOPT_GNU_ERRORS
|
||||
static const char *const errorarg =
|
||||
"%s: option `%.*s' doesn't allow an argument\n";
|
||||
static const char *const errornoarg =
|
||||
"%s: option `%.*s' requires an argument \n";
|
||||
static const char *const erroropt =
|
||||
"%s: unrecognized option `%.*s'\n";
|
||||
static const char *const errorargc =
|
||||
"%s: option `-%c' does not take an argument\n";
|
||||
static const char *const errornoargc =
|
||||
"%s: option requires an argument -- `-%c'\n";
|
||||
static const char *const erroroptc =
|
||||
"%s: invalid option -- %c\n";
|
||||
#elif defined(ULTRAGETOPT_BSD_ERRORS)
|
||||
static const char *const errorarg =
|
||||
"%s: option doesn't take an argument -- %.*s\n";
|
||||
static const char *const errornoarg =
|
||||
"%s: option requires an argument -- %.*s\n";
|
||||
static const char *const erroropt =
|
||||
"%s: unknown option -- %.*s\n";
|
||||
static const char *const errorargc =
|
||||
"%s: option doesn't take an argument -- %c\n";
|
||||
static const char *const errornoargc =
|
||||
"%s: option requires an argument -- %c\n";
|
||||
static const char *const erroroptc =
|
||||
"%s: unknown option -- %c\n";
|
||||
#elif defined(ULTRAGETOPT_DARWIN_ERRORS)
|
||||
static const char *const errorarg =
|
||||
"%s: option `%.*s' doesn't allow an argument\n"; /* with -- */
|
||||
static const char *const errornoarg =
|
||||
"%s: option `%.*s' requires an argument\n";
|
||||
static const char *const erroropt =
|
||||
"%s: unrecognized option `%.*s'\n"; /* with -- */
|
||||
static const char *const errorargc =
|
||||
"%s: option doesn't take an argument -- %c\n";
|
||||
static const char *const errornoargc =
|
||||
"%s: option requires an argument -- %c\n";
|
||||
static const char *const erroroptc =
|
||||
"%s: invalid option -- %c\n";
|
||||
#else /* POSIX-like */
|
||||
static const char *const errorarg =
|
||||
"%s: option does not take an argument -- %.*s\n";
|
||||
static const char *const errornoarg =
|
||||
"%s: option requires an argument -- %.*s\n";
|
||||
static const char *const erroropt =
|
||||
"%s: illegal option -- %.*s\n";
|
||||
static const char *const errorargc =
|
||||
"%s: option does not take an argument -- %c\n";
|
||||
static const char *const errornoargc =
|
||||
"%s: option requires an argument -- %c\n";
|
||||
static const char *const erroroptc =
|
||||
"%s: illegal option -- %c\n";
|
||||
#endif
|
||||
|
||||
/* Globals to match optarg, optind, opterr, optopt, optreset */
|
||||
char *ultraoptarg = NULL;
|
||||
int ultraoptind = 1;
|
||||
int ultraopterr = 1;
|
||||
int ultraoptreset = 0;
|
||||
#ifdef ULTRAGETOPT_DEFAULTOPTOPT
|
||||
int ultraoptopt = ULTRAGETOPT_DEFAULTOPTOPT -0;
|
||||
#else
|
||||
int ultraoptopt = 0;
|
||||
#endif
|
||||
|
||||
static int ultraoptnum = 0; /* How many options of the current multi-option
|
||||
argument have been processed? (e.g. -vvv) */
|
||||
|
||||
/* Add format error checking for gcc versions that support it */
|
||||
#if defined(__GNUC__) && __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR > 6)
|
||||
static void print_error(int flags, const char *template, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
#endif
|
||||
|
||||
/* Print errors only if not suppressed */
|
||||
static void print_error(int flags, const char *template, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, template);
|
||||
if (ultraopterr != 0 && !(flags & UGO_NOPRINTERR))
|
||||
vfprintf(stderr, template, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Check if an argument string looks like an option string */
|
||||
static inline int like_option(const char *arg, const char *optleaders)
|
||||
{
|
||||
return arg != NULL &&
|
||||
arg[0] != '\0' && /* >= 2 characters long */
|
||||
arg[1] != '\0' &&
|
||||
strchr(optleaders, arg[0]) && /* Starts with optleader */
|
||||
(arg[2] != '\0' || arg[0] != arg[1]); /* Not -- */
|
||||
}
|
||||
|
||||
/* Check if an argument string looks like the option terminator string */
|
||||
static inline int like_optterm(const char *arg, const char *optleaders)
|
||||
{
|
||||
return arg != NULL &&
|
||||
arg[0] != '\0' &&
|
||||
arg[1] != '\0' &&
|
||||
arg[2] == '\0' &&
|
||||
arg[0] == arg[1] &&
|
||||
strchr(optleaders, arg[0]);
|
||||
}
|
||||
|
||||
/* Check if an argument string looks like an option argument string */
|
||||
static inline int like_optarg(const char *arg, const char *optleaders,
|
||||
int allow_option)
|
||||
{
|
||||
return arg != NULL &&
|
||||
(allow_option ||
|
||||
(!like_option(arg, optleaders) && !like_optterm(arg, optleaders)));
|
||||
}
|
||||
|
||||
/* If argv[curopt] matches a long option, return the index of that option
|
||||
* Otherwise, return -1
|
||||
* If it has an adjacent argument, return pointer to it in longarg, else NULL
|
||||
*/
|
||||
static int match_longopt(int curopt, char *const argv[],
|
||||
const struct option *longopts, const char *assigners,
|
||||
const char *optleaders, int flags, char **longarg)
|
||||
{
|
||||
size_t alen, optnamelen = 0;
|
||||
char *optname;
|
||||
char *temp;
|
||||
int i;
|
||||
int (*optncmp)(const char *s1, const char *s2, size_t n);
|
||||
|
||||
if (longarg == NULL)
|
||||
longarg = &temp;
|
||||
*longarg = NULL;
|
||||
|
||||
if (flags & UGO_CASEINSENSITIVE)
|
||||
optncmp = strncasecmp;
|
||||
else
|
||||
optncmp = strncmp;
|
||||
|
||||
if (longopts == NULL)
|
||||
return -1;
|
||||
|
||||
if (!like_option(argv[curopt], optleaders))
|
||||
return -1;
|
||||
|
||||
if (flags & UGO_SINGLELEADERONLY) {
|
||||
optname = argv[curopt]+1;
|
||||
} else if (!strchr(optleaders, argv[curopt][1])) {
|
||||
/* Possible short option */
|
||||
if (flags & UGO_SINGLELEADERLONG)
|
||||
optname = argv[curopt]+1;
|
||||
else
|
||||
return -1;
|
||||
} else {
|
||||
optname = argv[curopt]+2;
|
||||
}
|
||||
|
||||
/* Do first longest-match search if requested */
|
||||
if (flags & UGO_LONGOPTADJACENT) {
|
||||
size_t matchlen = 0;
|
||||
int matchind = -1;
|
||||
for (i=0; longopts[i].name != NULL; i++) {
|
||||
size_t longnamelen = strlen(longopts[i].name);
|
||||
if (longnamelen > matchlen
|
||||
&& optncmp(optname, longopts[i].name, longnamelen) == 0) {
|
||||
matchind = i;
|
||||
matchlen = longnamelen;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchlen > 0) {
|
||||
/* See if our match has an adjacent argument */
|
||||
if (optname[matchlen] != '\0') {
|
||||
/* Strip assigner character if present */
|
||||
if (strchr(assigners, optname[matchlen]))
|
||||
*longarg = optname+matchlen+1;
|
||||
else
|
||||
*longarg = optname+matchlen;
|
||||
}
|
||||
|
||||
return matchind;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for assigner in the option */
|
||||
alen = strlen(assigners);
|
||||
for (i=0; (unsigned)i < alen; i++) {
|
||||
char *asn = strchr(optname, assigners[i]);
|
||||
if (asn != NULL) {
|
||||
optnamelen = asn - optname;
|
||||
*longarg = asn+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optnamelen == 0)
|
||||
optnamelen = strlen(optname);
|
||||
|
||||
for (i=0; longopts[i].name != NULL; i++)
|
||||
if (optncmp(optname, longopts[i].name, optnamelen) == 0
|
||||
&& strlen(longopts[i].name) == optnamelen)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if an option has a separate argument (in the following argv[] index) */
|
||||
static int has_separate_argument(int curopt, int argc, char *const argv[],
|
||||
const char *shortopts,
|
||||
const struct option *longopts,
|
||||
const char *assigners, const char *optleaders,
|
||||
int flags)
|
||||
{
|
||||
int longind;
|
||||
char *longarg;
|
||||
|
||||
assert(curopt < argc && like_option(argv[curopt], optleaders));
|
||||
|
||||
/* Check if we have a long option */
|
||||
longind = match_longopt(ultraoptind, argv, longopts, assigners, optleaders,
|
||||
flags, &longarg);
|
||||
if (longind >= 0) {
|
||||
if (longopts[longind].has_arg == no_argument
|
||||
|| longarg != NULL
|
||||
|| (longopts[longind].has_arg == optional_argument
|
||||
&& !(flags & UGO_SEPARATEDOPTIONAL)))
|
||||
return 0;
|
||||
|
||||
return like_optarg(argv[curopt+1], optleaders,
|
||||
(flags & UGO_HYPHENARG) &&
|
||||
longopts[longind].has_arg == required_argument);
|
||||
} else if (!strchr(optleaders, argv[curopt][1])) {
|
||||
/* Short option */
|
||||
char *optpos;
|
||||
|
||||
optpos = strchr(shortopts, argv[curopt][1]);
|
||||
if ((flags & UGO_CASEINSENSITIVE) && optpos == NULL) {
|
||||
if (islower(argv[curopt][1]))
|
||||
optpos = strchr(shortopts, toupper(argv[curopt][1]));
|
||||
else
|
||||
optpos = strchr(shortopts, tolower(argv[curopt][1]));
|
||||
}
|
||||
|
||||
|
||||
return optpos != NULL /* Option found */
|
||||
&& optpos[1] == ':' /* Option takes argument */
|
||||
&& (optpos[2] != ':' || (flags & UGO_SEPARATEDOPTIONAL))
|
||||
&& argv[curopt][2] == '\0' /* Argument is not adjacent */
|
||||
&& like_optarg(argv[curopt+1], /* Is an argument */
|
||||
optleaders,
|
||||
(flags & UGO_HYPHENARG) && optpos[2] != ':');
|
||||
}
|
||||
|
||||
/* No match */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bring the next option, or terminator, up to ultraoptind if there is one
|
||||
* Returns number of words shifted forward
|
||||
*/
|
||||
static int permute_options(int argc, char *argv[], const char *shortopts,
|
||||
const struct option *longopts,
|
||||
const char *assigners, const char *optleaders,
|
||||
int flags)
|
||||
{
|
||||
int curopt = ultraoptind;
|
||||
|
||||
/* If we already have an option or no more possible, give up */
|
||||
if (curopt >= argc || like_option(argv[curopt], optleaders))
|
||||
return 0;
|
||||
|
||||
for ( ; curopt < argc && argv[curopt]; curopt++) {
|
||||
int shiftarg = 0;
|
||||
int i;
|
||||
|
||||
/* Permute options and the option terminator */
|
||||
if (like_option(argv[curopt], optleaders)) {
|
||||
/* Check if we need to shift argument too */
|
||||
shiftarg = has_separate_argument(curopt, argc, argv, shortopts,
|
||||
longopts, assigners, optleaders,
|
||||
flags);
|
||||
} else if (!like_optterm(argv[curopt], optleaders)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Shift option */
|
||||
for (i=curopt; i>ultraoptind; i--) {
|
||||
char *temp = argv[i];
|
||||
argv[i] = argv[i-1];
|
||||
argv[i-1] = temp;
|
||||
|
||||
if (shiftarg) {
|
||||
temp = argv[i+1];
|
||||
argv[i+1] = argv[i];
|
||||
argv[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/* All done */
|
||||
if (shiftarg)
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Couldn't find an option, bummer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle a longopts[longind] matches argv[ultraoptind] actions */
|
||||
static int handle_longopt(int longind, char *longarg, int noseparg,
|
||||
char *const argv[],
|
||||
const struct option *longopts, int *indexptr,
|
||||
const char *optleaders, int flags)
|
||||
{
|
||||
/* Handle assignment arguments */
|
||||
if (longarg && longopts[longind].has_arg == no_argument) {
|
||||
print_error(flags, errorarg, argv[0],
|
||||
longarg-argv[ultraoptind]-1, argv[ultraoptind]);
|
||||
/* TODO: What is a good value to put in ultraoptopt? */
|
||||
/* Looks like GNU getopt() uses val */
|
||||
ultraoptopt = longopts[longind].val;
|
||||
ultraoptind++;
|
||||
return '?';
|
||||
} else if (longarg) {
|
||||
ultraoptind++;
|
||||
ultraoptarg = longarg;
|
||||
|
||||
if (indexptr)
|
||||
*indexptr = longind;
|
||||
|
||||
if (longopts[longind].flag) {
|
||||
*(longopts[longind].flag) = longopts[longind].val;
|
||||
return 0;
|
||||
} else
|
||||
return longopts[longind].val;
|
||||
}
|
||||
|
||||
/* Handle missing required argument */
|
||||
if (longopts[longind].has_arg == required_argument
|
||||
&& (noseparg
|
||||
|| !like_optarg(argv[ultraoptind+1],
|
||||
optleaders,
|
||||
flags & UGO_HYPHENARG))) {
|
||||
print_error(flags, errornoarg, argv[0],
|
||||
strlen(argv[ultraoptind]), argv[ultraoptind]);
|
||||
ultraoptind++;
|
||||
if (flags & UGO_MISSINGCOLON)
|
||||
return ':';
|
||||
else
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* Handle available argument */
|
||||
if ((longopts[longind].has_arg == required_argument
|
||||
|| (longopts[longind].has_arg == optional_argument
|
||||
&& (flags & UGO_SEPARATEDOPTIONAL)))
|
||||
&& !noseparg
|
||||
&& like_optarg(argv[ultraoptind+1],
|
||||
optleaders,
|
||||
(flags & UGO_HYPHENARG) &&
|
||||
longopts[longind].has_arg == required_argument)) {
|
||||
ultraoptarg = argv[ultraoptind+1];
|
||||
ultraoptind += 2;
|
||||
} else
|
||||
ultraoptind++;
|
||||
|
||||
if (indexptr)
|
||||
*indexptr = longind;
|
||||
|
||||
if (longopts[longind].flag) {
|
||||
*(longopts[longind].flag) = longopts[longind].val;
|
||||
return 0;
|
||||
} else
|
||||
return longopts[longind].val;
|
||||
}
|
||||
|
||||
int ultragetopt_tunable(int argc, char *const argv[], const char *shortopts,
|
||||
const struct option *longopts, int *indexptr,
|
||||
const char *assigners, const char *optleaders,
|
||||
int flags)
|
||||
{
|
||||
char *opt; /* Option we are processing */
|
||||
char *optpos; /* Pointer to opt in shortopts */
|
||||
int noseparg = 0; /* Force option not to have a separate argument */
|
||||
|
||||
if (ultraoptreset) {
|
||||
ultraoptind = 1;
|
||||
ultraopterr = 1;
|
||||
ultraoptnum = 0;
|
||||
ultraoptreset = 0;
|
||||
}
|
||||
|
||||
ultraoptarg = NULL;
|
||||
#ifdef ULTRAGETOPT_DEFAULTOPTOPT
|
||||
ultraoptopt = ULTRAGETOPT_DEFAULTOPTOPT -0;
|
||||
#endif
|
||||
|
||||
/* Sanity check (These are specified verbatim in SUS) */
|
||||
if (ultraoptind > argc
|
||||
|| argv[ultraoptind] == NULL)
|
||||
return -1;
|
||||
|
||||
/* No permuting when $POSIXLY_CORRECT is set (to match GNU getopt) */
|
||||
if (getenv("POSIXLY_CORRECT"))
|
||||
flags &= ~UGO_OPTIONPERMUTE;
|
||||
|
||||
/* Get flags from shortopts */
|
||||
for ( ; shortopts && *shortopts; shortopts++) {
|
||||
if (*shortopts == '+')
|
||||
flags &= ~UGO_OPTIONPERMUTE;
|
||||
else if (*shortopts == '-')
|
||||
flags |= UGO_NONOPTARG;
|
||||
else if (*shortopts == ':') {
|
||||
flags |= UGO_NOPRINTERR;
|
||||
flags |= UGO_MISSINGCOLON;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Found non-option */
|
||||
if (!like_option(argv[ultraoptind], optleaders)) {
|
||||
int shifted;
|
||||
|
||||
if (like_optterm(argv[ultraoptind], optleaders)) {
|
||||
if (!(flags & UGO_NOEATDASHDASH))
|
||||
ultraoptind++;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & UGO_NONOPTARG) {
|
||||
ultraoptarg = argv[ultraoptind];
|
||||
ultraoptind++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(flags & UGO_OPTIONPERMUTE))
|
||||
return -1;
|
||||
|
||||
shifted = permute_options(argc, (char **)argv, shortopts, longopts,
|
||||
assigners, optleaders, flags);
|
||||
if (shifted == 0)
|
||||
return -1;
|
||||
else if (shifted == 1)
|
||||
noseparg = 1;
|
||||
|
||||
if (like_optterm(argv[ultraoptind], optleaders)) {
|
||||
if (!(flags & UGO_NOEATDASHDASH))
|
||||
ultraoptind++;
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point we must have an option of some sort */
|
||||
assert(like_option(argv[ultraoptind], optleaders));
|
||||
|
||||
/* Handle --* */
|
||||
if (argv[ultraoptind][0] == argv[ultraoptind][1]) {
|
||||
int longind;
|
||||
char *longarg;
|
||||
|
||||
/* Handle long option */
|
||||
longind = match_longopt(ultraoptind, argv, longopts, assigners,
|
||||
optleaders, flags, &longarg);
|
||||
if (longind < 0) {
|
||||
if (longarg == NULL)
|
||||
print_error(flags, erroropt, argv[0],
|
||||
strlen(argv[ultraoptind]), argv[ultraoptind]);
|
||||
else
|
||||
print_error(flags, erroropt, argv[0],
|
||||
longarg - argv[ultraoptind] - 1, argv[ultraoptind]);
|
||||
|
||||
/* TODO: What is a good value for optopt in this case? */
|
||||
/* Looks like BSD uses 0 */
|
||||
ultraoptopt = 0;
|
||||
ultraoptind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
return handle_longopt(longind, longarg, noseparg, argv,
|
||||
longopts, indexptr, optleaders, flags);
|
||||
}
|
||||
|
||||
/* See if it matches a long-only option */
|
||||
if (longopts != NULL &&
|
||||
ultraoptnum == 0 &&
|
||||
((flags & UGO_SINGLELEADERLONG) ||
|
||||
(flags & UGO_SINGLELEADERONLY))) {
|
||||
int longind;
|
||||
char *longarg;
|
||||
|
||||
longind = match_longopt(ultraoptind, argv, longopts, assigners,
|
||||
optleaders, flags, &longarg);
|
||||
|
||||
if (longind >= 0)
|
||||
return handle_longopt(longind, longarg, noseparg, argv,
|
||||
longopts, indexptr, optleaders, flags);
|
||||
}
|
||||
|
||||
/* No long matches, process short option */
|
||||
opt = argv[ultraoptind] + ultraoptnum + 1;
|
||||
optpos = strchr(shortopts, opt[0]);
|
||||
if (optpos == NULL && (flags & UGO_CASEINSENSITIVE)) {
|
||||
if (islower(opt[0]))
|
||||
optpos = strchr(shortopts, toupper(opt[0]));
|
||||
else
|
||||
optpos = strchr(shortopts, tolower(opt[0]));
|
||||
}
|
||||
|
||||
/* This could indicate ultraoptnum not being reset properly */
|
||||
assert(opt[0] != '\0');
|
||||
|
||||
/* Check for invalid or unrecognized option */
|
||||
if (optpos == NULL || opt[0] == ':') {
|
||||
print_error(flags, erroroptc, argv[0], opt[0]);
|
||||
|
||||
ultraoptopt = opt[0];
|
||||
if (opt[1] != '\0')
|
||||
ultraoptnum++;
|
||||
else {
|
||||
ultraoptnum = 0;
|
||||
ultraoptind++;
|
||||
}
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* Handle arguments */
|
||||
if (optpos[1] == ':') {
|
||||
ultraoptnum = 0;
|
||||
|
||||
/* Handle adjacent arguments -ofile.txt */
|
||||
if (opt[1] != '\0') {
|
||||
/* Skip over assignment character */
|
||||
if ((flags & UGO_SHORTOPTASSIGN) && strchr(assigners, opt[1]))
|
||||
ultraoptarg = opt + 2;
|
||||
else
|
||||
ultraoptarg = opt + 1;
|
||||
|
||||
ultraoptind++;
|
||||
return optpos[0];
|
||||
}
|
||||
|
||||
/* Handle optional argument not present */
|
||||
if ((flags & UGO_OPTIONALARG) /* accept optionals */
|
||||
&& optpos[2] == ':' /* opt takes optional */
|
||||
&& (argv[ultraoptind+1] == NULL /* optional doesn't exist */
|
||||
|| !(flags & UGO_SEPARATEDOPTIONAL) /* separated not accepted */
|
||||
|| like_option(argv[ultraoptind+1], optleaders))) {
|
||||
ultraoptind++;
|
||||
return optpos[0];
|
||||
}
|
||||
|
||||
/* Handle separated argument missing */
|
||||
if (ultraoptind+2 > argc
|
||||
|| noseparg
|
||||
|| !like_optarg(argv[ultraoptind+1],
|
||||
optleaders,
|
||||
(flags & UGO_HYPHENARG))) {
|
||||
ultraoptind++;
|
||||
print_error(flags, errornoargc, argv[0], opt[0]);
|
||||
|
||||
ultraoptopt = opt[0];
|
||||
if (flags & UGO_MISSINGCOLON)
|
||||
return ':';
|
||||
else
|
||||
return '?';
|
||||
}
|
||||
|
||||
ultraoptind += 2;
|
||||
ultraoptarg = argv[ultraoptind-1];
|
||||
return optpos[0];
|
||||
}
|
||||
|
||||
/* Handle argumentless option with assigned option */
|
||||
if ((flags & UGO_SHORTOPTASSIGN)
|
||||
&& opt[1] != '\0' && strchr(assigners, opt[1])) {
|
||||
print_error(flags, errorargc, argv[0], opt[0]);
|
||||
ultraoptnum = 0;
|
||||
ultraoptopt = opt[0];
|
||||
ultraoptind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (opt[1] != '\0') {
|
||||
ultraoptnum++;
|
||||
} else {
|
||||
ultraoptnum = 0;
|
||||
ultraoptind++;
|
||||
}
|
||||
|
||||
return optpos[0];
|
||||
}
|
||||
|
||||
/* POSIX-compliant getopt
|
||||
*
|
||||
* Handles optional argument '::' specifier as an extension for compatibility
|
||||
* with glibc
|
||||
*/
|
||||
int ultragetopt(int argc, char * const argv[], const char *optstring)
|
||||
{
|
||||
int flags = getoptflags;
|
||||
|
||||
#ifdef ULTRAGETOPT_OPTIONPERMUTE
|
||||
flags |= UGO_OPTIONPERMUTE;
|
||||
#endif
|
||||
|
||||
#ifndef ULTRAGETOPT_NO_OPTIONALARG
|
||||
flags |= UGO_OPTIONALARG;
|
||||
#endif
|
||||
|
||||
return ultragetopt_tunable(argc, argv, optstring, NULL, NULL,
|
||||
unixassigners, unixleaders, flags);
|
||||
}
|
||||
|
||||
/* GNU getopt_long workalike
|
||||
*
|
||||
* Argument reordering not yet implemented
|
||||
* Leading + and - under consideration (behavior violates POSIX...)
|
||||
*/
|
||||
int ultragetopt_long(int argc, char *const argv[], const char *shortopts,
|
||||
const struct option *longopts, int *indexptr)
|
||||
{
|
||||
return ultragetopt_tunable(argc, argv, shortopts, longopts, indexptr,
|
||||
unixassigners, unixleaders,
|
||||
getoptflags | UGO_OPTIONPERMUTE | UGO_OPTIONALARG);
|
||||
}
|
||||
|
||||
/* GNU getopt_long_only workalike */
|
||||
int ultragetopt_long_only(int argc, char *const argv[], const char *shortopts,
|
||||
const struct option *longopts, int *indexptr)
|
||||
{
|
||||
return ultragetopt_tunable(argc, argv, shortopts, longopts, indexptr,
|
||||
unixassigners, unixleaders,
|
||||
getoptflags | UGO_SINGLELEADERLONG
|
||||
| UGO_OPTIONPERMUTE | UGO_OPTIONALARG);
|
||||
}
|
||||
|
||||
int ultragetopt_dos(int argc, char * const argv[], const char *optstring)
|
||||
{
|
||||
return ultragetopt_tunable(argc, argv, optstring, NULL, NULL,
|
||||
dosassigners, dosleaders,
|
||||
getoptflags | UGO_CASEINSENSITIVE);
|
||||
}
|
||||
|
||||
int ultragetopt_long_dos(int argc, char *const argv[], const char *shortopts,
|
||||
const struct option *longopts, int *indexptr)
|
||||
{
|
||||
return ultragetopt_tunable(argc, argv, shortopts, longopts, indexptr,
|
||||
dosassigners, dosleaders,
|
||||
getoptflags | UGO_CASEINSENSITIVE
|
||||
| UGO_SINGLELEADERLONG | UGO_SINGLELEADERONLY
|
||||
| UGO_OPTIONPERMUTE | UGO_OPTIONALARG);
|
||||
}
|
||||
|
||||
/* vim:set sts=4 sw=4: */
|
||||
Reference in New Issue
Block a user