From 8c13f5dbba942c8956a8d510cbde5992dd2fc28c Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sun, 25 Feb 2024 14:45:31 -0500 Subject: [PATCH] xopt => getopt_long. I give up on xopt. It didn't help me as much as I had hoped, and I had problems building for mingw with only some versions of GCC. Not worth any further time. --- GNUmakefile | 16 +- deps/xopt/.circleci/Dockerfile.test | 17 - deps/xopt/.circleci/config.yml | 7 - deps/xopt/.dockerignore | 1 - deps/xopt/.editorconfig | 18 - deps/xopt/.gitignore | 6 - deps/xopt/CMakeLists.txt | 43 - deps/xopt/README.md | 9 - deps/xopt/snprintf.c | 2099 ------------------------ deps/xopt/test/.gitignore | 2 - deps/xopt/test/autohelp-1.out | 12 - deps/xopt/test/autohelp.c | 100 -- deps/xopt/test/macro-1.out | 11 - deps/xopt/test/macro.c | 116 -- deps/xopt/test/nocondense-1.out | 3 - deps/xopt/test/nocondense-sloppy-1.out | 3 - deps/xopt/test/nocondense-sloppy-2.out | 3 - deps/xopt/test/nocondense-sloppy-3.out | 14 - deps/xopt/test/nocondense-sloppy.c | 149 -- deps/xopt/test/nocondense.c | 149 -- deps/xopt/test/optional-longarg-1.out | 11 - deps/xopt/test/optional-longarg.c | 116 -- deps/xopt/test/required-1.out | 12 - deps/xopt/test/required.c | 128 -- deps/xopt/test/simple-1.out | 11 - deps/xopt/test/simple.c | 128 -- deps/xopt/test/sloppyshorts-1.out | 14 - deps/xopt/test/sloppyshorts.c | 149 -- deps/xopt/test/test-case.sh | 46 - deps/xopt/xopt.c | 584 ------- deps/xopt/xopt.h | 225 --- src/main.c | 487 +++--- 32 files changed, 263 insertions(+), 4426 deletions(-) delete mode 100644 deps/xopt/.circleci/Dockerfile.test delete mode 100644 deps/xopt/.circleci/config.yml delete mode 120000 deps/xopt/.dockerignore delete mode 100644 deps/xopt/.editorconfig delete mode 100644 deps/xopt/.gitignore delete mode 100644 deps/xopt/CMakeLists.txt delete mode 100644 deps/xopt/README.md delete mode 100644 deps/xopt/snprintf.c delete mode 100644 deps/xopt/test/.gitignore delete mode 100644 deps/xopt/test/autohelp-1.out delete mode 100644 deps/xopt/test/autohelp.c delete mode 100644 deps/xopt/test/macro-1.out delete mode 100644 deps/xopt/test/macro.c delete mode 100644 deps/xopt/test/nocondense-1.out delete mode 100644 deps/xopt/test/nocondense-sloppy-1.out delete mode 100644 deps/xopt/test/nocondense-sloppy-2.out delete mode 100644 deps/xopt/test/nocondense-sloppy-3.out delete mode 100644 deps/xopt/test/nocondense-sloppy.c delete mode 100644 deps/xopt/test/nocondense.c delete mode 100644 deps/xopt/test/optional-longarg-1.out delete mode 100644 deps/xopt/test/optional-longarg.c delete mode 100644 deps/xopt/test/required-1.out delete mode 100644 deps/xopt/test/required.c delete mode 100644 deps/xopt/test/simple-1.out delete mode 100644 deps/xopt/test/simple.c delete mode 100644 deps/xopt/test/sloppyshorts-1.out delete mode 100644 deps/xopt/test/sloppyshorts.c delete mode 100755 deps/xopt/test/test-case.sh delete mode 100644 deps/xopt/xopt.c delete mode 100644 deps/xopt/xopt.h diff --git a/GNUmakefile b/GNUmakefile index cbb3a374..c4cb42da 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -245,7 +245,6 @@ $(APP_OBJS): CFLAGS += \ -Ideps/quickjs \ -Ideps/sqlite \ -Ideps/valgrind \ - -Ideps/xopt \ -Wdouble-promotion \ -Werror ifeq ($(UNAME_M),x86_64) @@ -497,18 +496,6 @@ $(SQLITE_OBJS): CFLAGS += \ -Wno-unused-function \ -Wno-unused-variable -XOPT_SOURCES := deps/xopt/xopt.c -XOPT_OBJS := $(call get_objs,XOPT_SOURCES) -$(filter $(BUILD_DIR)/win%,$(XOPT_OBJS)): CFLAGS += \ - -DHAVE_SNPRINTF \ - -DHAVE_VSNPRINTF \ - -DHAVE_VASNPRINTF \ - -DHAVE_VASPRINTF \ - -Dvsnprintf=rpl_vsnprintf -$(XOPT_OBJS): CFLAGS += \ - -Wno-implicit-const-int-float-conversion \ - -Wno-pointer-to-int-cast - QUICKJS_SOURCES := \ deps/quickjs/cutils.c \ deps/quickjs/libbf.c \ @@ -637,8 +624,7 @@ ALL_APP_OBJS := \ $(QUICKJS_OBJS) \ $(SODIUM_OBJS) \ $(SQLITE_OBJS) \ - $(UV_OBJS) \ - $(XOPT_OBJS) + $(UV_OBJS) DEPS = $(ALL_APP_OBJS:.o=.d) -include $(DEPS) diff --git a/deps/xopt/.circleci/Dockerfile.test b/deps/xopt/.circleci/Dockerfile.test deleted file mode 100644 index 4f521408..00000000 --- a/deps/xopt/.circleci/Dockerfile.test +++ /dev/null @@ -1,17 +0,0 @@ -FROM alpine:3.7 AS base -WORKDIR /src -RUN apk --update add alpine-sdk cmake bash -COPY . ./ -WORKDIR /src/build - -# Debug -FROM base -RUN cmake .. -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=On -RUN cmake --build . -RUN ctest -VV - -# Release -FROM base -RUN cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=On -RUN cmake --build . -RUN ctest -VV diff --git a/deps/xopt/.circleci/config.yml b/deps/xopt/.circleci/config.yml deleted file mode 100644 index 2a69c9f1..00000000 --- a/deps/xopt/.circleci/config.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: 2 -jobs: - build: - machine: true - steps: - - checkout - - run: docker build -f .circleci/Dockerfile.test . diff --git a/deps/xopt/.dockerignore b/deps/xopt/.dockerignore deleted file mode 120000 index 3e4e48b0..00000000 --- a/deps/xopt/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -.gitignore \ No newline at end of file diff --git a/deps/xopt/.editorconfig b/deps/xopt/.editorconfig deleted file mode 100644 index 4c017f8a..00000000 --- a/deps/xopt/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -root = true - -[*] -indent_style = tab -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.coffee] -indent_style = space - -[{package.json,*.yml}] -indent_style = space -indent_size = 2 - -[*.md] -trim_trailing_whitespace = false diff --git a/deps/xopt/.gitignore b/deps/xopt/.gitignore deleted file mode 100644 index 29b85d04..00000000 --- a/deps/xopt/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.sw[a-p] -/bin/ -/build/ -/.tup/ -/*.o -/*.a diff --git a/deps/xopt/CMakeLists.txt b/deps/xopt/CMakeLists.txt deleted file mode 100644 index 44779392..00000000 --- a/deps/xopt/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -cmake_minimum_required (VERSION 3.8) -project (xopt) - -add_library (xopt STATIC "${CMAKE_CURRENT_SOURCE_DIR}/xopt.c") - -if (APPLE OR UNIX) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic -std=c11 -D_XOPEN_SOURCE=600 -fdiagnostics-color=always -fvisibility=hidden") - set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g3 -O0") - set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast") -endif () - -function (_xopt_test name) - if (NOT TARGET "xopt-test-${name}") - add_executable ("xopt-test-${name}" "${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.c") - target_link_libraries ("xopt-test-${name}" xopt) - endif () - - set (testname "xopt-${name}-test") - set (testnum 1) - - while (TEST "${testname}-${testnum}") - math (EXPR testnum "${testnum}+1") - endwhile () - - add_test ( - NAME "${testname}-${testnum}" - COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test/test-case.sh" $ "${CMAKE_CURRENT_SOURCE_DIR}/test/${name}-${testnum}.out" ${ARGN} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test") -endfunction () - -if (BUILD_TESTING) - enable_testing () - _xopt_test (simple --some-int=10 --some-double=14.5 foo bar -- --some-other=20) - _xopt_test (macro --some-int=10 --some-double=14.5 foo bar -- --some-other=20) - _xopt_test (required --some-int=10 --some-double=14.5 --some-required=1337 foo bar -- --some-other=20) - _xopt_test (optional-longarg -i 10 -d 14.5 foo bar -- --some-other=20) - _xopt_test (autohelp --help -- --is-not-passed ignoreme) - _xopt_test (sloppyshorts -i10 -d 14.5 "-ssome string" -m -mm -mmm foo bar -- --is-not-passed ignoreme) - _xopt_test (nocondense-sloppy -i 10 -d 14.5 -s "some string" -m -mm -mmm foo bar -- --is-not-passed ignoreme) - _xopt_test (nocondense-sloppy -i 10 -d 14.5 "-ssome string" -m -mm -mmm foo bar -- --is-not-passed ignoreme) - _xopt_test (nocondense-sloppy -i 10 -d 14.5 "-ssome string" -m -m -m -m -m -m foo bar -- --is-not-passed ignoreme) - _xopt_test (nocondense -i 10 -d 14.5 "-ssome string" -m -mm -mmm foo bar -- --is-not-passed ignoreme) -endif () diff --git a/deps/xopt/README.md b/deps/xopt/README.md deleted file mode 100644 index 09419b8a..00000000 --- a/deps/xopt/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# XOpt [![CircleCI](https://circleci.com/gh/Qix-/xopt.svg?style=svg)](https://circleci.com/gh/Qix-/xopt) -The sane answer to POpt. - -XOpt is a command line argument parsing library written in ANSI C. XOpt -accepts arguments in GNU format and focuses on clean definition, taking stress -off the implementation. - -# License -Originally by Josh Junon, released under [CC0](https://creativecommons.org/publicdomain/zero/1.0/). Go nuts. diff --git a/deps/xopt/snprintf.c b/deps/xopt/snprintf.c deleted file mode 100644 index ad42afc5..00000000 --- a/deps/xopt/snprintf.c +++ /dev/null @@ -1,2099 +0,0 @@ -/* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */ - -/* - * Copyright (c) 1995 Patrick Powell. - * - * This code is based on code written by Patrick Powell . - * It may be used for any purpose as long as this notice remains intact on all - * source code distributions. - */ - -/* - * Copyright (c) 2008 Holger Weiss. - * - * This version of the code is maintained by Holger Weiss . - * My changes to the code may freely be used, modified and/or redistributed for - * any purpose. It would be nice if additions and fixes to this file (including - * trivial code cleanups) would be sent back in order to let me include them in - * the version available at . - * However, this is not a requirement for using or redistributing (possibly - * modified) versions of this file, nor is leaving this notice intact mandatory. - */ - -/* - * History - * - * 2008-01-20 Holger Weiss for C99-snprintf 1.1: - * - * Fixed the detection of infinite floating point values on IRIX (and - * possibly other systems) and applied another few minor cleanups. - * - * 2008-01-06 Holger Weiss for C99-snprintf 1.0: - * - * Added a lot of new features, fixed many bugs, and incorporated various - * improvements done by Andrew Tridgell , Russ Allbery - * , Hrvoje Niksic , Damien Miller - * , and others for the Samba, INN, Wget, and OpenSSH - * projects. The additions include: support the "e", "E", "g", "G", and - * "F" conversion specifiers (and use conversion style "f" or "F" for the - * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j", - * "t", and "z" length modifiers; support the "#" flag and the (non-C99) - * "'" flag; use localeconv(3) (if available) to get both the current - * locale's decimal point character and the separator between groups of - * digits; fix the handling of various corner cases of field width and - * precision specifications; fix various floating point conversion bugs; - * handle infinite and NaN floating point values; don't attempt to write to - * the output buffer (which may be NULL) if a size of zero was specified; - * check for integer overflow of the field width, precision, and return - * values and during the floating point conversion; use the OUTCHAR() macro - * instead of a function for better performance; provide asprintf(3) and - * vasprintf(3) functions; add new test cases. The replacement functions - * have been renamed to use an "rpl_" prefix, the function calls in the - * main project (and in this file) must be redefined accordingly for each - * replacement function which is needed (by using Autoconf or other means). - * Various other minor improvements have been applied and the coding style - * was cleaned up for consistency. - * - * 2007-07-23 Holger Weiss for Mutt 1.5.13: - * - * C99 compliant snprintf(3) and vsnprintf(3) functions return the number - * of characters that would have been written to a sufficiently sized - * buffer (excluding the '\0'). The original code simply returned the - * length of the resulting output string, so that's been fixed. - * - * 1998-03-05 Michael Elkins for Mutt 0.90.8: - * - * The original code assumed that both snprintf(3) and vsnprintf(3) were - * missing. Some systems only have snprintf(3) but not vsnprintf(3), so - * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. - * - * 1998-01-27 Thomas Roessler for Mutt 0.89i: - * - * The PGP code was using unsigned hexadecimal formats. Unfortunately, - * unsigned formats simply didn't work. - * - * 1997-10-22 Brandon Long for Mutt 0.87.1: - * - * Ok, added some minimal floating point support, which means this probably - * requires libm on most operating systems. Don't yet support the exponent - * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just - * wasn't being exercised in ways which showed it, so that's been fixed. - * Also, formatted the code to Mutt conventions, and removed dead code left - * over from the original. Also, there is now a builtin-test, run with: - * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf - * - * 2996-09-15 Brandon Long for Mutt 0.43: - * - * This was ugly. It is still ugly. I opted out of floating point - * numbers, but the formatter understands just about everything from the - * normal C string format, at least as far as I can tell from the Solaris - * 2.5 printf(3S) man page. - */ - -/* - * ToDo - * - * - Add wide character support. - * - Add support for "%a" and "%A" conversions. - * - Create test routines which predefine the expected results. Our test cases - * usually expose bugs in system implementations rather than in ours :-) - */ - -/* - * Usage - * - * 1) The following preprocessor macros should be defined to 1 if the feature or - * file in question is available on the target system (by using Autoconf or - * other means), though basic functionality should be available as long as - * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly: - * - * HAVE_VSNPRINTF - * HAVE_SNPRINTF - * HAVE_VASPRINTF - * HAVE_ASPRINTF - * HAVE_STDARG_H - * HAVE_STDDEF_H - * HAVE_STDINT_H - * HAVE_STDLIB_H - * HAVE_INTTYPES_H - * HAVE_LOCALE_H - * HAVE_LOCALECONV - * HAVE_LCONV_DECIMAL_POINT - * HAVE_LCONV_THOUSANDS_SEP - * HAVE_LONG_DOUBLE - * HAVE_LONG_LONG_INT - * HAVE_UNSIGNED_LONG_LONG_INT - * HAVE_INTMAX_T - * HAVE_UINTMAX_T - * HAVE_UINTPTR_T - * HAVE_PTRDIFF_T - * HAVE_VA_COPY - * HAVE___VA_COPY - * - * 2) The calls to the functions which should be replaced must be redefined - * throughout the project files (by using Autoconf or other means): - * - * #define vsnprintf rpl_vsnprintf - * #define snprintf rpl_snprintf - * #define vasprintf rpl_vasprintf - * #define asprintf rpl_asprintf - * - * 3) The required replacement functions should be declared in some header file - * included throughout the project files: - * - * #if HAVE_CONFIG_H - * #include - * #endif - * #if HAVE_STDARG_H - * #include - * #if !HAVE_VSNPRINTF - * int rpl_vsnprintf(char *, size_t, const char *, va_list); - * #endif - * #if !HAVE_SNPRINTF - * int rpl_snprintf(char *, size_t, const char *, ...); - * #endif - * #if !HAVE_VASPRINTF - * int rpl_vasprintf(char **, const char *, va_list); - * #endif - * #if !HAVE_ASPRINTF - * int rpl_asprintf(char **, const char *, ...); - * #endif - * #endif - * - * Autoconf macros for handling step 1 and step 2 are available at - * . - */ - -#if HAVE_CONFIG_H -#include -#endif /* HAVE_CONFIG_H */ - -#if TEST_SNPRINTF -#include /* For pow(3), NAN, and INFINITY. */ -#include /* For strcmp(3). */ -#if defined(__NetBSD__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NeXT__) || \ - defined(__bsd__) -#define OS_BSD 1 -#elif defined(sgi) || defined(__sgi) -#ifndef __c99 -#define __c99 /* Force C99 mode to get included on IRIX 6.5.30. */ -#endif /* !defined(__c99) */ -#define OS_IRIX 1 -#define OS_SYSV 1 -#elif defined(__svr4__) -#define OS_SYSV 1 -#elif defined(__linux__) -#define OS_LINUX 1 -#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */ -#if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */ -#ifdef HAVE_SNPRINTF -#undef HAVE_SNPRINTF -#endif /* defined(HAVE_SNPRINTF) */ -#ifdef HAVE_VSNPRINTF -#undef HAVE_VSNPRINTF -#endif /* defined(HAVE_VSNPRINTF) */ -#ifdef HAVE_ASPRINTF -#undef HAVE_ASPRINTF -#endif /* defined(HAVE_ASPRINTF) */ -#ifdef HAVE_VASPRINTF -#undef HAVE_VASPRINTF -#endif /* defined(HAVE_VASPRINTF) */ -#ifdef snprintf -#undef snprintf -#endif /* defined(snprintf) */ -#ifdef vsnprintf -#undef vsnprintf -#endif /* defined(vsnprintf) */ -#ifdef asprintf -#undef asprintf -#endif /* defined(asprintf) */ -#ifdef vasprintf -#undef vasprintf -#endif /* defined(vasprintf) */ -#else /* By default, we assume a modern system for testing. */ -#ifndef HAVE_STDARG_H -#define HAVE_STDARG_H 1 -#endif /* HAVE_STDARG_H */ -#ifndef HAVE_STDDEF_H -#define HAVE_STDDEF_H 1 -#endif /* HAVE_STDDEF_H */ -#ifndef HAVE_STDINT_H -#define HAVE_STDINT_H 1 -#endif /* HAVE_STDINT_H */ -#ifndef HAVE_STDLIB_H -#define HAVE_STDLIB_H 1 -#endif /* HAVE_STDLIB_H */ -#ifndef HAVE_INTTYPES_H -#define HAVE_INTTYPES_H 1 -#endif /* HAVE_INTTYPES_H */ -#ifndef HAVE_LOCALE_H -#define HAVE_LOCALE_H 1 -#endif /* HAVE_LOCALE_H */ -#ifndef HAVE_LOCALECONV -#define HAVE_LOCALECONV 1 -#endif /* !defined(HAVE_LOCALECONV) */ -#ifndef HAVE_LCONV_DECIMAL_POINT -#define HAVE_LCONV_DECIMAL_POINT 1 -#endif /* HAVE_LCONV_DECIMAL_POINT */ -#ifndef HAVE_LCONV_THOUSANDS_SEP -#define HAVE_LCONV_THOUSANDS_SEP 1 -#endif /* HAVE_LCONV_THOUSANDS_SEP */ -#ifndef HAVE_LONG_DOUBLE -#define HAVE_LONG_DOUBLE 1 -#endif /* !defined(HAVE_LONG_DOUBLE) */ -#ifndef HAVE_LONG_LONG_INT -#define HAVE_LONG_LONG_INT 1 -#endif /* !defined(HAVE_LONG_LONG_INT) */ -#ifndef HAVE_UNSIGNED_LONG_LONG_INT -#define HAVE_UNSIGNED_LONG_LONG_INT 1 -#endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */ -#ifndef HAVE_INTMAX_T -#define HAVE_INTMAX_T 1 -#endif /* !defined(HAVE_INTMAX_T) */ -#ifndef HAVE_UINTMAX_T -#define HAVE_UINTMAX_T 1 -#endif /* !defined(HAVE_UINTMAX_T) */ -#ifndef HAVE_UINTPTR_T -#define HAVE_UINTPTR_T 1 -#endif /* !defined(HAVE_UINTPTR_T) */ -#ifndef HAVE_PTRDIFF_T -#define HAVE_PTRDIFF_T 1 -#endif /* !defined(HAVE_PTRDIFF_T) */ -#ifndef HAVE_VA_COPY -#define HAVE_VA_COPY 1 -#endif /* !defined(HAVE_VA_COPY) */ -#ifndef HAVE___VA_COPY -#define HAVE___VA_COPY 1 -#endif /* !defined(HAVE___VA_COPY) */ -#endif /* HAVE_CONFIG_H */ -#define snprintf rpl_snprintf -#define vsnprintf rpl_vsnprintf -#define asprintf rpl_asprintf -#define vasprintf rpl_vasprintf -#endif /* TEST_SNPRINTF */ - -#if !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || !HAVE_VASPRINTF -#include /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */ -#ifdef VA_START -#undef VA_START -#endif /* defined(VA_START) */ -#ifdef VA_SHIFT -#undef VA_SHIFT -#endif /* defined(VA_SHIFT) */ -#if HAVE_STDARG_H -#include -#define VA_START(ap, last) va_start(ap, last) -#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */ -#else /* Assume is available. */ -#include -#define VA_START(ap, last) va_start(ap) /* "last" is ignored. */ -#define VA_SHIFT(ap, value, type) value = va_arg(ap, type) -#endif /* HAVE_STDARG_H */ - -#if !HAVE_VASPRINTF -#if HAVE_STDLIB_H -#include /* For malloc(3). */ -#endif /* HAVE_STDLIB_H */ -#ifdef VA_COPY -#undef VA_COPY -#endif /* defined(VA_COPY) */ -#ifdef VA_END_COPY -#undef VA_END_COPY -#endif /* defined(VA_END_COPY) */ -#if HAVE_VA_COPY -#define VA_COPY(dest, src) va_copy(dest, src) -#define VA_END_COPY(ap) va_end(ap) -#elif HAVE___VA_COPY -#define VA_COPY(dest, src) __va_copy(dest, src) -#define VA_END_COPY(ap) va_end(ap) -#else -#define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list)) -#define VA_END_COPY(ap) /* No-op. */ -#define NEED_MYMEMCPY 1 -static void *mymemcpy(void *, void *, size_t); -#endif /* HAVE_VA_COPY */ -#endif /* !HAVE_VASPRINTF */ - -#if !HAVE_VSNPRINTF -#include /* For ERANGE and errno. */ -#include /* For *_MAX. */ -#if HAVE_INTTYPES_H -#include /* For intmax_t (if not defined in ). */ -#endif /* HAVE_INTTYPES_H */ -#if HAVE_LOCALE_H -#include /* For localeconv(3). */ -#endif /* HAVE_LOCALE_H */ -#if HAVE_STDDEF_H -#include /* For ptrdiff_t. */ -#endif /* HAVE_STDDEF_H */ -#if HAVE_STDINT_H -#include /* For intmax_t. */ -#endif /* HAVE_STDINT_H */ - -/* Support for unsigned long long int. We may also need ULLONG_MAX. */ -#ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */ -#ifdef UINT_MAX -#define ULONG_MAX UINT_MAX -#else -#define ULONG_MAX INT_MAX -#endif /* defined(UINT_MAX) */ -#endif /* !defined(ULONG_MAX) */ -#ifdef ULLONG -#undef ULLONG -#endif /* defined(ULLONG) */ -#if HAVE_UNSIGNED_LONG_LONG_INT -#define ULLONG unsigned long long int -#ifndef ULLONG_MAX -#define ULLONG_MAX ULONG_MAX -#endif /* !defined(ULLONG_MAX) */ -#else -#define ULLONG unsigned long int -#ifdef ULLONG_MAX -#undef ULLONG_MAX -#endif /* defined(ULLONG_MAX) */ -#define ULLONG_MAX ULONG_MAX -#endif /* HAVE_LONG_LONG_INT */ - -/* Support for uintmax_t. We also need UINTMAX_MAX. */ -#ifdef UINTMAX_T -#undef UINTMAX_T -#endif /* defined(UINTMAX_T) */ -#if HAVE_UINTMAX_T || defined(uintmax_t) -#define UINTMAX_T uintmax_t -#ifndef UINTMAX_MAX -#define UINTMAX_MAX ULLONG_MAX -#endif /* !defined(UINTMAX_MAX) */ -#else -#define UINTMAX_T ULLONG -#ifdef UINTMAX_MAX -#undef UINTMAX_MAX -#endif /* defined(UINTMAX_MAX) */ -#define UINTMAX_MAX ULLONG_MAX -#endif /* HAVE_UINTMAX_T || defined(uintmax_t) */ - -/* Support for long double. */ -#ifndef LDOUBLE -#if HAVE_LONG_DOUBLE -#define LDOUBLE long double -#else -#define LDOUBLE double -#endif /* HAVE_LONG_DOUBLE */ -#endif /* !defined(LDOUBLE) */ - -/* Support for long long int. */ -#ifndef LLONG -#if HAVE_LONG_LONG_INT -#define LLONG long long int -#else -#define LLONG long int -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !defined(LLONG) */ - -/* Support for intmax_t. */ -#ifndef INTMAX_T -#if HAVE_INTMAX_T || defined(intmax_t) -#define INTMAX_T intmax_t -#else -#define INTMAX_T LLONG -#endif /* HAVE_INTMAX_T || defined(intmax_t) */ -#endif /* !defined(INTMAX_T) */ - -/* Support for uintptr_t. */ -#ifndef UINTPTR_T -#if HAVE_UINTPTR_T || defined(uintptr_t) -#define UINTPTR_T uintptr_t -#else -#define UINTPTR_T unsigned long int -#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */ -#endif /* !defined(UINTPTR_T) */ - -/* Support for ptrdiff_t. */ -#ifndef PTRDIFF_T -#if HAVE_PTRDIFF_T || defined(ptrdiff_t) -#define PTRDIFF_T ptrdiff_t -#else -#define PTRDIFF_T long int -#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */ -#endif /* !defined(PTRDIFF_T) */ - -/* - * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99: - * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an - * unsigned type if necessary. This should work just fine in practice. - */ -#ifndef UPTRDIFF_T -#define UPTRDIFF_T PTRDIFF_T -#endif /* !defined(UPTRDIFF_T) */ - -/* - * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7). - * However, we'll simply use size_t and convert it to a signed type if - * necessary. This should work just fine in practice. - */ -#ifndef SSIZE_T -#define SSIZE_T size_t -#endif /* !defined(SSIZE_T) */ - -/* Either ERANGE or E2BIG should be available everywhere. */ -#ifndef ERANGE -#define ERANGE E2BIG -#endif /* !defined(ERANGE) */ -#ifndef EOVERFLOW -#define EOVERFLOW ERANGE -#endif /* !defined(EOVERFLOW) */ - -/* - * Buffer size to hold the octal string representation of UINT128_MAX without - * nul-termination ("3777777777777777777777777777777777777777777"). - */ -#ifdef MAX_CONVERT_LENGTH -#undef MAX_CONVERT_LENGTH -#endif /* defined(MAX_CONVERT_LENGTH) */ -#define MAX_CONVERT_LENGTH 43 - -/* Format read states. */ -#define PRINT_S_DEFAULT 0 -#define PRINT_S_FLAGS 1 -#define PRINT_S_WIDTH 2 -#define PRINT_S_DOT 3 -#define PRINT_S_PRECISION 4 -#define PRINT_S_MOD 5 -#define PRINT_S_CONV 6 - -/* Format flags. */ -#define PRINT_F_MINUS (1 << 0) -#define PRINT_F_PLUS (1 << 1) -#define PRINT_F_SPACE (1 << 2) -#define PRINT_F_NUM (1 << 3) -#define PRINT_F_ZERO (1 << 4) -#define PRINT_F_QUOTE (1 << 5) -#define PRINT_F_UP (1 << 6) -#define PRINT_F_UNSIGNED (1 << 7) -#define PRINT_F_TYPE_G (1 << 8) -#define PRINT_F_TYPE_E (1 << 9) - -/* Conversion flags. */ -#define PRINT_C_CHAR 1 -#define PRINT_C_SHORT 2 -#define PRINT_C_LONG 3 -#define PRINT_C_LLONG 4 -#define PRINT_C_LDOUBLE 5 -#define PRINT_C_SIZE 6 -#define PRINT_C_PTRDIFF 7 -#define PRINT_C_INTMAX 8 - -#ifndef MAX -#define MAX(x, y) ((x >= y) ? x : y) -#endif /* !defined(MAX) */ -#ifndef CHARTOINT -#define CHARTOINT(ch) (ch - '0') -#endif /* !defined(CHARTOINT) */ -#ifndef ISDIGIT -#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9') -#endif /* !defined(ISDIGIT) */ -#ifndef ISNAN -#define ISNAN(x) (x != x) -#endif /* !defined(ISNAN) */ -#ifndef ISINF -#define ISINF(x) (x != 0.0 && x + x == x) -#endif /* !defined(ISINF) */ - -#ifdef OUTCHAR -#undef OUTCHAR -#endif /* defined(OUTCHAR) */ -#define OUTCHAR(str, len, size, ch) \ -do { \ - if (len + 1 < size) \ - str[len] = ch; \ - (len)++; \ -} while (/* CONSTCOND */ 0) - -static void fmtstr(char *, size_t *, size_t, const char *, int, int, int); -static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int); -static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *); -static void printsep(char *, size_t *, size_t); -static int getnumsep(int); -static int getexponent(LDOUBLE); -static int convert(UINTMAX_T, char *, size_t, int, int); -static UINTMAX_T cast(LDOUBLE); -static UINTMAX_T myround(LDOUBLE); -static LDOUBLE mypow10(int); - -extern int errno; - -int -rpl_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - LDOUBLE fvalue; - INTMAX_T value; - unsigned char cvalue; - const char *strvalue; - INTMAX_T *intmaxptr; - PTRDIFF_T *ptrdiffptr; - SSIZE_T *sizeptr; - LLONG *llongptr; - long int *longptr; - int *intptr; - short int *shortptr; - signed char *charptr; - size_t len = 0; - int overflow = 0; - int base = 0; - int cflags = 0; - int flags = 0; - int width = 0; - int precision = -1; - int state = PRINT_S_DEFAULT; - char ch = *format++; - - /* - * C99 says: "If `n' is zero, nothing is written, and `s' may be a null - * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer - * even if a size larger than zero was specified. At least NetBSD's - * snprintf(3) does the same, as well as other versions of this file. - * (Though some of these versions will write to a non-NULL buffer even - * if a size of zero was specified, which violates the standard.) - */ - if (str == NULL && size != 0) - size = 0; - - while (ch != '\0') - switch (state) { - case PRINT_S_DEFAULT: - if (ch == '%') - state = PRINT_S_FLAGS; - else - OUTCHAR(str, len, size, ch); - ch = *format++; - break; - case PRINT_S_FLAGS: - switch (ch) { - case '-': - flags |= PRINT_F_MINUS; - ch = *format++; - break; - case '+': - flags |= PRINT_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= PRINT_F_SPACE; - ch = *format++; - break; - case '#': - flags |= PRINT_F_NUM; - ch = *format++; - break; - case '0': - flags |= PRINT_F_ZERO; - ch = *format++; - break; - case '\'': /* SUSv2 flag (not in C99). */ - flags |= PRINT_F_QUOTE; - ch = *format++; - break; - default: - state = PRINT_S_WIDTH; - break; - } - break; - case PRINT_S_WIDTH: - if (ISDIGIT(ch)) { - ch = CHARTOINT(ch); - if (width > (INT_MAX - ch) / 10) { - overflow = 1; - goto out; - } - width = 10 * width + ch; - ch = *format++; - } else if (ch == '*') { - /* - * C99 says: "A negative field width argument is - * taken as a `-' flag followed by a positive - * field width." (7.19.6.1, 5) - */ - if ((width = va_arg(args, int)) < 0) { - flags |= PRINT_F_MINUS; - width = -width; - } - ch = *format++; - state = PRINT_S_DOT; - } else - state = PRINT_S_DOT; - break; - case PRINT_S_DOT: - if (ch == '.') { - state = PRINT_S_PRECISION; - ch = *format++; - } else - state = PRINT_S_MOD; - break; - case PRINT_S_PRECISION: - if (precision == -1) - precision = 0; - if (ISDIGIT(ch)) { - ch = CHARTOINT(ch); - if (precision > (INT_MAX - ch) / 10) { - overflow = 1; - goto out; - } - precision = 10 * precision + ch; - ch = *format++; - } else if (ch == '*') { - /* - * C99 says: "A negative precision argument is - * taken as if the precision were omitted." - * (7.19.6.1, 5) - */ - if ((precision = va_arg(args, int)) < 0) - precision = -1; - ch = *format++; - state = PRINT_S_MOD; - } else - state = PRINT_S_MOD; - break; - case PRINT_S_MOD: - switch (ch) { - case 'h': - ch = *format++; - if (ch == 'h') { /* It's a char. */ - ch = *format++; - cflags = PRINT_C_CHAR; - } else - cflags = PRINT_C_SHORT; - break; - case 'l': - ch = *format++; - if (ch == 'l') { /* It's a long long. */ - ch = *format++; - cflags = PRINT_C_LLONG; - } else - cflags = PRINT_C_LONG; - break; - case 'L': - cflags = PRINT_C_LDOUBLE; - ch = *format++; - break; - case 'j': - cflags = PRINT_C_INTMAX; - ch = *format++; - break; - case 't': - cflags = PRINT_C_PTRDIFF; - ch = *format++; - break; - case 'z': - cflags = PRINT_C_SIZE; - ch = *format++; - break; - } - state = PRINT_S_CONV; - break; - case PRINT_S_CONV: - switch (ch) { - case 'd': - /* FALLTHROUGH */ - case 'i': - switch (cflags) { - case PRINT_C_CHAR: - value = (signed char)va_arg(args, int); - break; - case PRINT_C_SHORT: - value = (short int)va_arg(args, int); - break; - case PRINT_C_LONG: - value = va_arg(args, long int); - break; - case PRINT_C_LLONG: - value = va_arg(args, LLONG); - break; - case PRINT_C_SIZE: - value = va_arg(args, SSIZE_T); - break; - case PRINT_C_INTMAX: - value = va_arg(args, INTMAX_T); - break; - case PRINT_C_PTRDIFF: - value = va_arg(args, PTRDIFF_T); - break; - default: - value = va_arg(args, int); - break; - } - fmtint(str, &len, size, value, 10, width, - precision, flags); - break; - case 'X': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'x': - base = 16; - /* FALLTHROUGH */ - case 'o': - if (base == 0) - base = 8; - /* FALLTHROUGH */ - case 'u': - if (base == 0) - base = 10; - flags |= PRINT_F_UNSIGNED; - switch (cflags) { - case PRINT_C_CHAR: - value = (unsigned char)va_arg(args, - unsigned int); - break; - case PRINT_C_SHORT: - value = (unsigned short int)va_arg(args, - unsigned int); - break; - case PRINT_C_LONG: - value = va_arg(args, unsigned long int); - break; - case PRINT_C_LLONG: - value = va_arg(args, ULLONG); - break; - case PRINT_C_SIZE: - value = va_arg(args, size_t); - break; - case PRINT_C_INTMAX: - value = va_arg(args, UINTMAX_T); - break; - case PRINT_C_PTRDIFF: - value = va_arg(args, UPTRDIFF_T); - break; - default: - value = va_arg(args, unsigned int); - break; - } - fmtint(str, &len, size, value, base, width, - precision, flags); - break; - case 'A': - /* Not yet supported, we'll use "%F". */ - /* FALLTHROUGH */ - case 'F': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'a': - /* Not yet supported, we'll use "%f". */ - /* FALLTHROUGH */ - case 'f': - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'E': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'e': - flags |= PRINT_F_TYPE_E; - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'G': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'g': - flags |= PRINT_F_TYPE_G; - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - /* - * If the precision is zero, it is treated as - * one (cf. C99: 7.19.6.1, 8). - */ - if (precision == 0) - precision = 1; - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'c': - cvalue = va_arg(args, int); - OUTCHAR(str, len, size, cvalue); - break; - case 's': - strvalue = va_arg(args, char *); - fmtstr(str, &len, size, strvalue, width, - precision, flags); - break; - case 'p': - /* - * C99 says: "The value of the pointer is - * converted to a sequence of printing - * characters, in an implementation-defined - * manner." (C99: 7.19.6.1, 8) - */ - if ((strvalue = va_arg(args, void *)) == NULL) - /* - * We use the glibc format. BSD prints - * "0x0", SysV "0". - */ - fmtstr(str, &len, size, "(nil)", width, - -1, flags); - else { - /* - * We use the BSD/glibc format. SysV - * omits the "0x" prefix (which we emit - * using the PRINT_F_NUM flag). - */ - flags |= PRINT_F_NUM; - flags |= PRINT_F_UNSIGNED; - fmtint(str, &len, size, - (UINTPTR_T)strvalue, 16, width, - precision, flags); - } - break; - case 'n': - switch (cflags) { - case PRINT_C_CHAR: - charptr = va_arg(args, signed char *); - *charptr = len; - break; - case PRINT_C_SHORT: - shortptr = va_arg(args, short int *); - *shortptr = len; - break; - case PRINT_C_LONG: - longptr = va_arg(args, long int *); - *longptr = len; - break; - case PRINT_C_LLONG: - llongptr = va_arg(args, LLONG *); - *llongptr = len; - break; - case PRINT_C_SIZE: - /* - * C99 says that with the "z" length - * modifier, "a following `n' conversion - * specifier applies to a pointer to a - * signed integer type corresponding to - * size_t argument." (7.19.6.1, 7) - */ - sizeptr = va_arg(args, SSIZE_T *); - *sizeptr = len; - break; - case PRINT_C_INTMAX: - intmaxptr = va_arg(args, INTMAX_T *); - *intmaxptr = len; - break; - case PRINT_C_PTRDIFF: - ptrdiffptr = va_arg(args, PTRDIFF_T *); - *ptrdiffptr = len; - break; - default: - intptr = va_arg(args, int *); - *intptr = len; - break; - } - break; - case '%': /* Print a "%" character verbatim. */ - OUTCHAR(str, len, size, ch); - break; - default: /* Skip other characters. */ - break; - } - ch = *format++; - state = PRINT_S_DEFAULT; - base = cflags = flags = width = 0; - precision = -1; - break; - } -out: - if (len < size) - str[len] = '\0'; - else if (size > 0) - str[size - 1] = '\0'; - - if (overflow || len >= INT_MAX) { - errno = overflow ? EOVERFLOW : ERANGE; - return -1; - } - return (int)len; -} - -static void -fmtstr(char *str, size_t *len, size_t size, const char *value, int width, - int precision, int flags) -{ - int padlen, strln; /* Amount to pad. */ - int noprecision = (precision == -1); - - if (value == NULL) /* We're forgiving. */ - value = "(null)"; - - /* If a precision was specified, don't read the string past it. */ - for (strln = 0; value[strln] != '\0' && - (noprecision || strln < precision); strln++) - continue; - - if ((padlen = width - strln) < 0) - padlen = 0; - if (flags & PRINT_F_MINUS) /* Left justify. */ - padlen = -padlen; - - while (padlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen--; - } - while (*value != '\0' && (noprecision || precision-- > 0)) { - OUTCHAR(str, *len, size, *value); - value++; - } - while (padlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen++; - } -} - -static void -fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width, - int precision, int flags) -{ - UINTMAX_T uvalue; - char iconvert[MAX_CONVERT_LENGTH]; - char sign = 0; - char hexprefix = 0; - int spadlen = 0; /* Amount to space pad. */ - int zpadlen = 0; /* Amount to zero pad. */ - int pos; - int separators = (flags & PRINT_F_QUOTE); - int noprecision = (precision == -1); - - if (flags & PRINT_F_UNSIGNED) - uvalue = value; - else { - uvalue = (value >= 0) ? value : -value; - if (value < 0) - sign = '-'; - else if (flags & PRINT_F_PLUS) /* Do a sign. */ - sign = '+'; - else if (flags & PRINT_F_SPACE) - sign = ' '; - } - - pos = convert(uvalue, iconvert, sizeof(iconvert), base, - flags & PRINT_F_UP); - - if (flags & PRINT_F_NUM && uvalue != 0) { - /* - * C99 says: "The result is converted to an `alternative form'. - * For `o' conversion, it increases the precision, if and only - * if necessary, to force the first digit of the result to be a - * zero (if the value and precision are both 0, a single 0 is - * printed). For `x' (or `X') conversion, a nonzero result has - * `0x' (or `0X') prefixed to it." (7.19.6.1, 6) - */ - switch (base) { - case 8: - if (precision <= pos) - precision = pos + 1; - break; - case 16: - hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x'; - break; - } - } - - if (separators) /* Get the number of group separators we'll print. */ - separators = getnumsep(pos); - - zpadlen = precision - pos - separators; - spadlen = width /* Minimum field width. */ - - separators /* Number of separators. */ - - MAX(precision, pos) /* Number of integer digits. */ - - ((sign != 0) ? 1 : 0) /* Will we print a sign? */ - - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */ - - if (zpadlen < 0) - zpadlen = 0; - if (spadlen < 0) - spadlen = 0; - - /* - * C99 says: "If the `0' and `-' flags both appear, the `0' flag is - * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a - * precision is specified, the `0' flag is ignored." (7.19.6.1, 6) - */ - if (flags & PRINT_F_MINUS) /* Left justify. */ - spadlen = -spadlen; - else if (flags & PRINT_F_ZERO && noprecision) { - zpadlen += spadlen; - spadlen = 0; - } - while (spadlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - spadlen--; - } - if (sign != 0) /* Sign. */ - OUTCHAR(str, *len, size, sign); - if (hexprefix != 0) { /* A "0x" or "0X" prefix. */ - OUTCHAR(str, *len, size, '0'); - OUTCHAR(str, *len, size, hexprefix); - } - while (zpadlen > 0) { /* Leading zeros. */ - OUTCHAR(str, *len, size, '0'); - zpadlen--; - } - while (pos > 0) { /* The actual digits. */ - pos--; - OUTCHAR(str, *len, size, iconvert[pos]); - if (separators > 0 && pos > 0 && pos % 3 == 0) - printsep(str, len, size); - } - while (spadlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - spadlen++; - } -} - -static void -fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width, - int precision, int flags, int *overflow) -{ - LDOUBLE ufvalue; - UINTMAX_T intpart; - UINTMAX_T fracpart; - UINTMAX_T mask; - const char *infnan = NULL; - char iconvert[MAX_CONVERT_LENGTH]; - char fconvert[MAX_CONVERT_LENGTH]; - char econvert[4]; /* "e-12" (without nul-termination). */ - char esign = 0; - char sign = 0; - int leadfraczeros = 0; - int exponent = 0; - int emitpoint = 0; - int omitzeros = 0; - int omitcount = 0; - int padlen = 0; - int epos = 0; - int fpos = 0; - int ipos = 0; - int separators = (flags & PRINT_F_QUOTE); - int estyle = (flags & PRINT_F_TYPE_E); -#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - struct lconv *lc = localeconv(); -#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ - - /* - * AIX' man page says the default is 0, but C99 and at least Solaris' - * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX - * defaults to 6. - */ - if (precision == -1) - precision = 6; - - if (fvalue < 0.0) - sign = '-'; - else if (flags & PRINT_F_PLUS) /* Do a sign. */ - sign = '+'; - else if (flags & PRINT_F_SPACE) - sign = ' '; - - if (ISNAN(fvalue)) - infnan = (flags & PRINT_F_UP) ? "NAN" : "nan"; - else if (ISINF(fvalue)) - infnan = (flags & PRINT_F_UP) ? "INF" : "inf"; - - if (infnan != NULL) { - if (sign != 0) - iconvert[ipos++] = sign; - while (*infnan != '\0') - iconvert[ipos++] = *infnan++; - fmtstr(str, len, size, iconvert, width, ipos, flags); - return; - } - - /* "%e" (or "%E") or "%g" (or "%G") conversion. */ - if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) { - if (flags & PRINT_F_TYPE_G) { - /* - * For "%g" (and "%G") conversions, the precision - * specifies the number of significant digits, which - * includes the digits in the integer part. The - * conversion will or will not be using "e-style" (like - * "%e" or "%E" conversions) depending on the precision - * and on the exponent. However, the exponent can be - * affected by rounding the converted value, so we'll - * leave this decision for later. Until then, we'll - * assume that we're going to do an "e-style" conversion - * (in order to get the exponent calculated). For - * "e-style", the precision must be decremented by one. - */ - precision--; - /* - * For "%g" (and "%G") conversions, trailing zeros are - * removed from the fractional portion of the result - * unless the "#" flag was specified. - */ - if (!(flags & PRINT_F_NUM)) - omitzeros = 1; - } - exponent = getexponent(fvalue); - estyle = 1; - } - -again: - /* - * Sorry, we only support 9, 19, or 38 digits (that is, the number of - * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value - * minus one) past the decimal point due to our conversion method. - */ - switch (sizeof(UINTMAX_T)) { - case 16: - if (precision > 38) - precision = 38; - break; - case 8: - if (precision > 19) - precision = 19; - break; - default: - if (precision > 9) - precision = 9; - break; - } - - ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue; - if (estyle) /* We want exactly one integer digit. */ - ufvalue /= mypow10(exponent); - - if ((intpart = cast(ufvalue)) == UINTMAX_MAX) { - *overflow = 1; - return; - } - - /* - * Factor of ten with the number of digits needed for the fractional - * part. For example, if the precision is 3, the mask will be 1000. - */ - mask = mypow10(precision); - /* - * We "cheat" by converting the fractional part to integer by - * multiplying by a factor of ten. - */ - if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) { - /* - * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000 - * (because precision = 3). Now, myround(1000 * 0.99962) will - * return 1000. So, the integer part must be incremented by one - * and the fractional part must be set to zero. - */ - intpart++; - fracpart = 0; - if (estyle && intpart == 10) { - /* - * The value was rounded up to ten, but we only want one - * integer digit if using "e-style". So, the integer - * part must be set to one and the exponent must be - * incremented by one. - */ - intpart = 1; - exponent++; - } - } - - /* - * Now that we know the real exponent, we can check whether or not to - * use "e-style" for "%g" (and "%G") conversions. If we don't need - * "e-style", the precision must be adjusted and the integer and - * fractional parts must be recalculated from the original value. - * - * C99 says: "Let P equal the precision if nonzero, 6 if the precision - * is omitted, or 1 if the precision is zero. Then, if a conversion - * with style `E' would have an exponent of X: - * - * - if P > X >= -4, the conversion is with style `f' (or `F') and - * precision P - (X + 1). - * - * - otherwise, the conversion is with style `e' (or `E') and precision - * P - 1." (7.19.6.1, 8) - * - * Note that we had decremented the precision by one. - */ - if (flags & PRINT_F_TYPE_G && estyle && - precision + 1 > exponent && exponent >= -4) { - precision -= exponent; - estyle = 0; - goto again; - } - - if (estyle) { - if (exponent < 0) { - exponent = -exponent; - esign = '-'; - } else - esign = '+'; - - /* - * Convert the exponent. The sizeof(econvert) is 4. So, the - * econvert buffer can hold e.g. "e+99" and "e-99". We don't - * support an exponent which contains more than two digits. - * Therefore, the following stores are safe. - */ - epos = convert(exponent, econvert, 2, 10, 0); - /* - * C99 says: "The exponent always contains at least two digits, - * and only as many more digits as necessary to represent the - * exponent." (7.19.6.1, 8) - */ - if (epos == 1) - econvert[epos++] = '0'; - econvert[epos++] = esign; - econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e'; - } - - /* Convert the integer part and the fractional part. */ - ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0); - if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */ - fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0); - - leadfraczeros = precision - fpos; - - if (omitzeros) { - if (fpos > 0) /* Omit trailing fractional part zeros. */ - while (omitcount < fpos && fconvert[omitcount] == '0') - omitcount++; - else { /* The fractional part is zero, omit it completely. */ - omitcount = precision; - leadfraczeros = 0; - } - precision -= omitcount; - } - - /* - * Print a decimal point if either the fractional part is non-zero - * and/or the "#" flag was specified. - */ - if (precision > 0 || flags & PRINT_F_NUM) - emitpoint = 1; - if (separators) /* Get the number of group separators we'll print. */ - separators = getnumsep(ipos); - - padlen = width /* Minimum field width. */ - - ipos /* Number of integer digits. */ - - epos /* Number of exponent characters. */ - - precision /* Number of fractional digits. */ - - separators /* Number of group separators. */ - - (emitpoint ? 1 : 0) /* Will we print a decimal point? */ - - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */ - - if (padlen < 0) - padlen = 0; - - /* - * C99 says: "If the `0' and `-' flags both appear, the `0' flag is - * ignored." (7.19.6.1, 6) - */ - if (flags & PRINT_F_MINUS) /* Left justifty. */ - padlen = -padlen; - else if (flags & PRINT_F_ZERO && padlen > 0) { - if (sign != 0) { /* Sign. */ - OUTCHAR(str, *len, size, sign); - sign = 0; - } - while (padlen > 0) { /* Leading zeros. */ - OUTCHAR(str, *len, size, '0'); - padlen--; - } - } - while (padlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen--; - } - if (sign != 0) /* Sign. */ - OUTCHAR(str, *len, size, sign); - while (ipos > 0) { /* Integer part. */ - ipos--; - OUTCHAR(str, *len, size, iconvert[ipos]); - if (separators > 0 && ipos > 0 && ipos % 3 == 0) - printsep(str, len, size); - } - if (emitpoint) { /* Decimal point. */ -#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - if (lc->decimal_point != NULL && *lc->decimal_point != '\0') - OUTCHAR(str, *len, size, *lc->decimal_point); - else /* We'll always print some decimal point character. */ -#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ - OUTCHAR(str, *len, size, '.'); - } - while (leadfraczeros > 0) { /* Leading fractional part zeros. */ - OUTCHAR(str, *len, size, '0'); - leadfraczeros--; - } - while (fpos > omitcount) { /* The remaining fractional part. */ - fpos--; - OUTCHAR(str, *len, size, fconvert[fpos]); - } - while (epos > 0) { /* Exponent. */ - epos--; - OUTCHAR(str, *len, size, econvert[epos]); - } - while (padlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen++; - } -} - -static void -printsep(char *str, size_t *len, size_t size) -{ -#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP - struct lconv *lc = localeconv(); - int i; - - if (lc->thousands_sep != NULL) - for (i = 0; lc->thousands_sep[i] != '\0'; i++) - OUTCHAR(str, *len, size, lc->thousands_sep[i]); - else -#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ - OUTCHAR(str, *len, size, ','); -} - -static int -getnumsep(int digits) -{ - int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3; -#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP - int strln; - struct lconv *lc = localeconv(); - - /* We support an arbitrary separator length (including zero). */ - if (lc->thousands_sep != NULL) { - for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) - continue; - separators *= strln; - } -#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ - return separators; -} - -static int -getexponent(LDOUBLE value) -{ - LDOUBLE tmp = (value >= 0.0) ? value : -value; - int exponent = 0; - - /* - * We check for 99 > exponent > -99 in order to work around possible - * endless loops which could happen (at least) in the second loop (at - * least) if we're called with an infinite value. However, we checked - * for infinity before calling this function using our ISINF() macro, so - * this might be somewhat paranoid. - */ - while (tmp < 1.0 && tmp > 0.0 && --exponent > -99) - tmp *= 10; - while (tmp >= 10.0 && ++exponent < 99) - tmp /= 10; - - return exponent; -} - -static int -convert(UINTMAX_T value, char *buf, size_t size, int base, int caps) -{ - const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef"; - size_t pos = 0; - - /* We return an unterminated buffer with the digits in reverse order. */ - do { - buf[pos++] = digits[value % base]; - value /= base; - } while (value != 0 && pos < size); - - return (int)pos; -} - -static UINTMAX_T -cast(LDOUBLE value) -{ - UINTMAX_T result; - - /* - * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be - * represented exactly as an LDOUBLE value (but is less than LDBL_MAX), - * it may be increased to the nearest higher representable value for the - * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE - * value although converting the latter to UINTMAX_T would overflow. - */ - if (value >= UINTMAX_MAX) - return UINTMAX_MAX; - - result = value; - /* - * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to - * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates - * the standard). Sigh. - */ - return (result <= value) ? result : result - 1; -} - -static UINTMAX_T -myround(LDOUBLE value) -{ - UINTMAX_T intpart = cast(value); - - return ((value -= intpart) < 0.5) ? intpart : intpart + 1; -} - -static LDOUBLE -mypow10(int exponent) -{ - LDOUBLE result = 1; - - while (exponent > 0) { - result *= 10; - exponent--; - } - while (exponent < 0) { - result /= 10; - exponent++; - } - return result; -} -#endif /* !HAVE_VSNPRINTF */ - -#if !HAVE_VASPRINTF -#if NEED_MYMEMCPY -void * -mymemcpy(void *dst, void *src, size_t len) -{ - const char *from = src; - char *to = dst; - - /* No need for optimization, we use this only to replace va_copy(3). */ - while (len-- > 0) - *to++ = *from++; - return dst; -} -#endif /* NEED_MYMEMCPY */ - -int -rpl_vasprintf(char **ret, const char *format, va_list ap) -{ - size_t size; - int len; - va_list aq; - - VA_COPY(aq, ap); - len = vsnprintf(NULL, 0, format, aq); - VA_END_COPY(aq); - if (len < 0 || (*ret = malloc(size = len + 1)) == NULL) - return -1; - return vsnprintf(*ret, size, format, ap); -} -#endif /* !HAVE_VASPRINTF */ - -#if !HAVE_SNPRINTF -#if HAVE_STDARG_H -int -rpl_snprintf(char *str, size_t size, const char *format, ...) -#else -int -rpl_snprintf(va_alist) va_dcl -#endif /* HAVE_STDARG_H */ -{ -#if !HAVE_STDARG_H - char *str; - size_t size; - char *format; -#endif /* HAVE_STDARG_H */ - va_list ap; - int len; - - VA_START(ap, format); - VA_SHIFT(ap, str, char *); - VA_SHIFT(ap, size, size_t); - VA_SHIFT(ap, format, const char *); - len = vsnprintf(str, size, format, ap); - va_end(ap); - return len; -} -#endif /* !HAVE_SNPRINTF */ - -#if !HAVE_ASPRINTF -#if HAVE_STDARG_H -int -rpl_asprintf(char **ret, const char *format, ...) -#else -int -rpl_asprintf(va_alist) va_dcl -#endif /* HAVE_STDARG_H */ -{ -#if !HAVE_STDARG_H - char **ret; - char *format; -#endif /* HAVE_STDARG_H */ - va_list ap; - int len; - - VA_START(ap, format); - VA_SHIFT(ap, ret, char **); - VA_SHIFT(ap, format, const char *); - len = vasprintf(ret, format, ap); - va_end(ap); - return len; -} -#endif /* !HAVE_ASPRINTF */ -#else /* Dummy declaration to avoid empty translation unit warnings. */ -int main(void); -#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */ - -#if TEST_SNPRINTF -int -main(void) -{ - const char *float_fmt[] = { - /* "%E" and "%e" formats. */ -#if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX - "%.16e", - "%22.16e", - "%022.16e", - "%-22.16e", - "%#+'022.16e", -#endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */ - "foo|%#+0123.9E|bar", - "%-123.9e", - "%123.9e", - "%+23.9e", - "%+05.8e", - "%-05.8e", - "%05.8e", - "%+5.8e", - "%-5.8e", - "% 5.8e", - "%5.8e", - "%+4.9e", -#if !OS_LINUX /* glibc sometimes gets these wrong. */ - "%+#010.0e", - "%#10.1e", - "%10.5e", - "% 10.5e", - "%5.0e", - "%5.e", - "%#5.0e", - "%#5.e", - "%3.2e", - "%3.1e", - "%-1.5e", - "%1.5e", - "%01.3e", - "%1.e", - "%.1e", - "%#.0e", - "%+.0e", - "% .0e", - "%.0e", - "%#.e", - "%+.e", - "% .e", - "%.e", - "%4e", - "%e", - "%E", -#endif /* !OS_LINUX */ - /* "%F" and "%f" formats. */ -#if !OS_BSD && !OS_IRIX - "% '022f", - "%+'022f", - "%-'22f", - "%'22f", -#if HAVE_LONG_LONG_INT - "%.16f", - "%22.16f", - "%022.16f", - "%-22.16f", - "%#+'022.16f", -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !OS_BSD && !OS_IRIX */ - "foo|%#+0123.9F|bar", - "%-123.9f", - "%123.9f", - "%+23.9f", - "%+#010.0f", - "%#10.1f", - "%10.5f", - "% 10.5f", - "%+05.8f", - "%-05.8f", - "%05.8f", - "%+5.8f", - "%-5.8f", - "% 5.8f", - "%5.8f", - "%5.0f", - "%5.f", - "%#5.0f", - "%#5.f", - "%+4.9f", - "%3.2f", - "%3.1f", - "%-1.5f", - "%1.5f", - "%01.3f", - "%1.f", - "%.1f", - "%#.0f", - "%+.0f", - "% .0f", - "%.0f", - "%#.f", - "%+.f", - "% .f", - "%.f", - "%4f", - "%f", - "%F", - /* "%G" and "%g" formats. */ -#if !OS_BSD && !OS_IRIX && !OS_LINUX - "% '022g", - "%+'022g", - "%-'22g", - "%'22g", -#if HAVE_LONG_LONG_INT - "%.16g", - "%22.16g", - "%022.16g", - "%-22.16g", - "%#+'022.16g", -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */ - "foo|%#+0123.9G|bar", - "%-123.9g", - "%123.9g", - "%+23.9g", - "%+05.8g", - "%-05.8g", - "%05.8g", - "%+5.8g", - "%-5.8g", - "% 5.8g", - "%5.8g", - "%+4.9g", -#if !OS_LINUX /* glibc sometimes gets these wrong. */ - "%+#010.0g", - "%#10.1g", - "%10.5g", - "% 10.5g", - "%5.0g", - "%5.g", - "%#5.0g", - "%#5.g", - "%3.2g", - "%3.1g", - "%-1.5g", - "%1.5g", - "%01.3g", - "%1.g", - "%.1g", - "%#.0g", - "%+.0g", - "% .0g", - "%.0g", - "%#.g", - "%+.g", - "% .g", - "%.g", - "%4g", - "%g", - "%G", -#endif /* !OS_LINUX */ - NULL - }; - double float_val[] = { - -4.136, - -134.52, - -5.04030201, - -3410.01234, - -999999.999999, - -913450.29876, - -913450.2, - -91345.2, - -9134.2, - -913.2, - -91.2, - -9.2, - -9.9, - 4.136, - 134.52, - 5.04030201, - 3410.01234, - 999999.999999, - 913450.29876, - 913450.2, - 91345.2, - 9134.2, - 913.2, - 91.2, - 9.2, - 9.9, - 9.96, - 9.996, - 9.9996, - 9.99996, - 9.999996, - 9.9999996, - 9.99999996, - 0.99999996, - 0.99999999, - 0.09999999, - 0.00999999, - 0.00099999, - 0.00009999, - 0.00000999, - 0.00000099, - 0.00000009, - 0.00000001, - 0.0000001, - 0.000001, - 0.00001, - 0.0001, - 0.001, - 0.01, - 0.1, - 1.0, - 1.5, - -1.5, - -1.0, - -0.1, -#if !OS_BSD /* BSD sometimes gets these wrong. */ -#ifdef INFINITY - INFINITY, - -INFINITY, -#endif /* defined(INFINITY) */ -#ifdef NAN - NAN, -#endif /* defined(NAN) */ -#endif /* !OS_BSD */ - 0 - }; - const char *long_fmt[] = { - "foo|%0123ld|bar", -#if !OS_IRIX - "% '0123ld", - "%+'0123ld", - "%-'123ld", - "%'123ld", -#endif /* !OS_IRiX */ - "%123.9ld", - "% 123.9ld", - "%+123.9ld", - "%-123.9ld", - "%0123ld", - "% 0123ld", - "%+0123ld", - "%-0123ld", - "%10.5ld", - "% 10.5ld", - "%+10.5ld", - "%-10.5ld", - "%010ld", - "% 010ld", - "%+010ld", - "%-010ld", - "%4.2ld", - "% 4.2ld", - "%+4.2ld", - "%-4.2ld", - "%04ld", - "% 04ld", - "%+04ld", - "%-04ld", - "%5.5ld", - "%+22.33ld", - "%01.3ld", - "%1.5ld", - "%-1.5ld", - "%44ld", - "%4ld", - "%4.0ld", - "%4.ld", - "%.44ld", - "%.4ld", - "%.0ld", - "%.ld", - "%ld", - NULL - }; - long int long_val[] = { -#ifdef LONG_MAX - LONG_MAX, -#endif /* LONG_MAX */ -#ifdef LONG_MIN - LONG_MIN, -#endif /* LONG_MIN */ - -91340, - 91340, - 341, - 134, - 0203, - -1, - 1, - 0 - }; - const char *ulong_fmt[] = { - /* "%u" formats. */ - "foo|%0123lu|bar", -#if !OS_IRIX - "% '0123lu", - "%+'0123lu", - "%-'123lu", - "%'123lu", -#endif /* !OS_IRiX */ - "%123.9lu", - "% 123.9lu", - "%+123.9lu", - "%-123.9lu", - "%0123lu", - "% 0123lu", - "%+0123lu", - "%-0123lu", - "%5.5lu", - "%+22.33lu", - "%01.3lu", - "%1.5lu", - "%-1.5lu", - "%44lu", - "%lu", - /* "%o" formats. */ - "foo|%#0123lo|bar", - "%#123.9lo", - "%# 123.9lo", - "%#+123.9lo", - "%#-123.9lo", - "%#0123lo", - "%# 0123lo", - "%#+0123lo", - "%#-0123lo", - "%#5.5lo", - "%#+22.33lo", - "%#01.3lo", - "%#1.5lo", - "%#-1.5lo", - "%#44lo", - "%#lo", - "%123.9lo", - "% 123.9lo", - "%+123.9lo", - "%-123.9lo", - "%0123lo", - "% 0123lo", - "%+0123lo", - "%-0123lo", - "%5.5lo", - "%+22.33lo", - "%01.3lo", - "%1.5lo", - "%-1.5lo", - "%44lo", - "%lo", - /* "%X" and "%x" formats. */ - "foo|%#0123lX|bar", - "%#123.9lx", - "%# 123.9lx", - "%#+123.9lx", - "%#-123.9lx", - "%#0123lx", - "%# 0123lx", - "%#+0123lx", - "%#-0123lx", - "%#5.5lx", - "%#+22.33lx", - "%#01.3lx", - "%#1.5lx", - "%#-1.5lx", - "%#44lx", - "%#lx", - "%#lX", - "%123.9lx", - "% 123.9lx", - "%+123.9lx", - "%-123.9lx", - "%0123lx", - "% 0123lx", - "%+0123lx", - "%-0123lx", - "%5.5lx", - "%+22.33lx", - "%01.3lx", - "%1.5lx", - "%-1.5lx", - "%44lx", - "%lx", - "%lX", - NULL - }; - unsigned long int ulong_val[] = { -#ifdef ULONG_MAX - ULONG_MAX, -#endif /* ULONG_MAX */ - 91340, - 341, - 134, - 0203, - 1, - 0 - }; - const char *llong_fmt[] = { - "foo|%0123lld|bar", - "%123.9lld", - "% 123.9lld", - "%+123.9lld", - "%-123.9lld", - "%0123lld", - "% 0123lld", - "%+0123lld", - "%-0123lld", - "%5.5lld", - "%+22.33lld", - "%01.3lld", - "%1.5lld", - "%-1.5lld", - "%44lld", - "%lld", - NULL - }; - LLONG llong_val[] = { -#ifdef LLONG_MAX - LLONG_MAX, -#endif /* LLONG_MAX */ -#ifdef LLONG_MIN - LLONG_MIN, -#endif /* LLONG_MIN */ - -91340, - 91340, - 341, - 134, - 0203, - -1, - 1, - 0 - }; - const char *string_fmt[] = { - "foo|%10.10s|bar", - "%-10.10s", - "%10.10s", - "%10.5s", - "%5.10s", - "%10.1s", - "%1.10s", - "%10.0s", - "%0.10s", - "%-42.5s", - "%2.s", - "%.10s", - "%.1s", - "%.0s", - "%.s", - "%4s", - "%s", - NULL - }; - const char *string_val[] = { - "Hello", - "Hello, world!", - "Sound check: One, two, three.", - "This string is a little longer than the other strings.", - "1", - "", - NULL - }; -#if !OS_SYSV /* SysV uses a different format than we do. */ - const char *pointer_fmt[] = { - "foo|%p|bar", - "%42p", - "%p", - NULL - }; - const char *pointer_val[] = { - *pointer_fmt, - *string_fmt, - *string_val, - NULL - }; -#endif /* !OS_SYSV */ - char buf1[1024], buf2[1024]; - double value, digits = 9.123456789012345678901234567890123456789; - int i, j, r1, r2, failed = 0, num = 0; - -/* - * Use -DTEST_NILS in order to also test the conversion of nil values. Might - * segfault on systems which don't support converting a NULL pointer with "%s" - * and lets some test cases fail against BSD and glibc due to bugs in their - * implementations. - */ -#ifndef TEST_NILS -#define TEST_NILS 0 -#elif TEST_NILS -#undef TEST_NILS -#define TEST_NILS 1 -#endif /* !defined(TEST_NILS) */ -#ifdef TEST -#undef TEST -#endif /* defined(TEST) */ -#define TEST(fmt, val) \ -do { \ - for (i = 0; fmt[i] != NULL; i++) \ - for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ - r1 = sprintf(buf1, fmt[i], val[j]); \ - r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ - if (strcmp(buf1, buf2) != 0 || r1 != r2) { \ - (void)printf("Results don't match, " \ - "format string: %s\n" \ - "\t sprintf(3): [%s] (%d)\n" \ - "\tsnprintf(3): [%s] (%d)\n", \ - fmt[i], buf1, r1, buf2, r2); \ - failed++; \ - } \ - num++; \ - } \ -} while (/* CONSTCOND */ 0) - -#if HAVE_LOCALE_H - (void)setlocale(LC_ALL, ""); -#endif /* HAVE_LOCALE_H */ - - (void)puts("Testing our snprintf(3) against your system's sprintf(3)."); - TEST(float_fmt, float_val); - TEST(long_fmt, long_val); - TEST(ulong_fmt, ulong_val); - TEST(llong_fmt, llong_val); - TEST(string_fmt, string_val); -#if !OS_SYSV /* SysV uses a different format than we do. */ - TEST(pointer_fmt, pointer_val); -#endif /* !OS_SYSV */ - (void)printf("Result: %d out of %d tests failed.\n", failed, num); - - (void)fputs("Checking how many digits we support: ", stdout); - for (i = 0; i < 100; i++) { - value = pow(10, i) * digits; - (void)sprintf(buf1, "%.1f", value); - (void)snprintf(buf2, sizeof(buf2), "%.1f", value); - if (strcmp(buf1, buf2) != 0) { - (void)printf("apparently %d.\n", i); - break; - } - } - return (failed == 0) ? 0 : 1; -} -#endif /* TEST_SNPRINTF */ - -/* vim: set joinspaces textwidth=80: */ - diff --git a/deps/xopt/test/.gitignore b/deps/xopt/test/.gitignore deleted file mode 100644 index ad70de1a..00000000 --- a/deps/xopt/test/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/*-test -/*.o diff --git a/deps/xopt/test/autohelp-1.out b/deps/xopt/test/autohelp-1.out deleted file mode 100644 index 3fb75ae4..00000000 --- a/deps/xopt/test/autohelp-1.out +++ /dev/null @@ -1,12 +0,0 @@ -args: «--help» «--» «--is-not-passed» «ignoreme» - -usage: autohelp-test-case [opts...] [--] [extras...] - -Tests the simple parser macro - --i, --some-int=n Some integer value. Can set to whatever number you like. --f Some float value. ---some-double=n Some double value. --?, --help Shows this help message - -[end of arguments] diff --git a/deps/xopt/test/autohelp.c b/deps/xopt/test/autohelp.c deleted file mode 100644 index e36a8ae3..00000000 --- a/deps/xopt/test/autohelp.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - bool help; -} SimpleConfig; - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - 0, - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 0, - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - "autohelp-test-case", - 0, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "[opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (!err) { - err = config.help - ? "--help was passed but autohelp didn't fire" - : "--help was not passed - it is required for this test case"; - } - - fprintf(stderr, "Error: %s\n", err); - -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 0; - goto exit; -} diff --git a/deps/xopt/test/macro-1.out b/deps/xopt/test/macro-1.out deleted file mode 100644 index f66b2ae2..00000000 --- a/deps/xopt/test/macro-1.out +++ /dev/null @@ -1,11 +0,0 @@ -args: «--some-int=10» «--some-double=14.5» «foo» «bar» «--» «--some-other=20» - -someInt: 10 -someFloat: 0.000000 -someDouble: 14.500000 -help: 0 - -extra count: 3 -- foo -- bar -- --some-other=20 diff --git a/deps/xopt/test/macro.c b/deps/xopt/test/macro.c deleted file mode 100644 index 12679110..00000000 --- a/deps/xopt/test/macro.c +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - bool help; -} SimpleConfig; - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - "some-float", - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - const char **extrasPtr = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - argv[0], - 0, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "[opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (err) { - fprintf(stderr, "Error: %s\n", err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - - exit_code = 0; -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 2; - goto exit; -} diff --git a/deps/xopt/test/nocondense-1.out b/deps/xopt/test/nocondense-1.out deleted file mode 100644 index e739d2b7..00000000 --- a/deps/xopt/test/nocondense-1.out +++ /dev/null @@ -1,3 +0,0 @@ -args: «-i» «10» «-d» «14.5» «-ssome string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme» - -Error: short option parameters must be separated, not condensed: -ssome string diff --git a/deps/xopt/test/nocondense-sloppy-1.out b/deps/xopt/test/nocondense-sloppy-1.out deleted file mode 100644 index ce90682c..00000000 --- a/deps/xopt/test/nocondense-sloppy-1.out +++ /dev/null @@ -1,3 +0,0 @@ -args: «-i» «10» «-d» «14.5» «-s» «some string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme» - -Error: short options cannot be combined: -mm diff --git a/deps/xopt/test/nocondense-sloppy-2.out b/deps/xopt/test/nocondense-sloppy-2.out deleted file mode 100644 index 13f5271c..00000000 --- a/deps/xopt/test/nocondense-sloppy-2.out +++ /dev/null @@ -1,3 +0,0 @@ -args: «-i» «10» «-d» «14.5» «-ssome string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme» - -Error: short options cannot be combined: -mm diff --git a/deps/xopt/test/nocondense-sloppy-3.out b/deps/xopt/test/nocondense-sloppy-3.out deleted file mode 100644 index 8ec905fb..00000000 --- a/deps/xopt/test/nocondense-sloppy-3.out +++ /dev/null @@ -1,14 +0,0 @@ -args: «-i» «10» «-d» «14.5» «-ssome string» «-m» «-m» «-m» «-m» «-m» «-m» «foo» «bar» «--» «--is-not-passed» «ignoreme» - -someInt: 10 -someFloat: 0.000000 -someDouble: 14.500000 -someString: some string -multiCount: 6 -help: 0 - -extra count: 4 -- foo -- bar -- --is-not-passed -- ignoreme diff --git a/deps/xopt/test/nocondense-sloppy.c b/deps/xopt/test/nocondense-sloppy.c deleted file mode 100644 index 4570eb15..00000000 --- a/deps/xopt/test/nocondense-sloppy.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - const char *someString; - int multiCount; - bool help; -} SimpleConfig; - -static void on_verbose(const char *v, void *data, const struct xoptOption *option, bool longArg, const char **err) { - (void) v; - (void) longArg; - (void) err; - int *count = (int *)(((char *) data) + option->offset); - ++*count; -} - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - "some-float", - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "some-string", - 's', - offsetof(SimpleConfig, someString), - 0, - XOPT_TYPE_STRING, - "s", - "Some string value." - }, - { - 0, - 'm', - offsetof(SimpleConfig, multiCount), - &on_verbose, - XOPT_TYPE_BOOL, - 0, - "Specify multiple times to increase count" - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - const char **extrasPtr = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.someFloat = 0.0f; - config.someString = 0; - config.multiCount = 0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - argv[0], - XOPT_CTX_SLOPPYSHORTS | XOPT_CTX_NOCONDENSE, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "[opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (err) { - fprintf(stderr, "Error: %s\n", err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(someString, s); - P(multiCount, d); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - - exit_code = 0; -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 2; - goto exit; -} diff --git a/deps/xopt/test/nocondense.c b/deps/xopt/test/nocondense.c deleted file mode 100644 index eb4b85f9..00000000 --- a/deps/xopt/test/nocondense.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - const char *someString; - int multiCount; - bool help; -} SimpleConfig; - -static void on_verbose(const char *v, void *data, const struct xoptOption *option, bool longArg, const char **err) { - (void) v; - (void) longArg; - (void) err; - int *count = (int *)(((char *) data) + option->offset); - ++*count; -} - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - "some-float", - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "some-string", - 's', - offsetof(SimpleConfig, someString), - 0, - XOPT_TYPE_STRING, - "s", - "Some string value." - }, - { - 0, - 'm', - offsetof(SimpleConfig, multiCount), - &on_verbose, - XOPT_TYPE_BOOL, - 0, - "Specify multiple times to increase count" - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - const char **extrasPtr = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.someFloat = 0.0f; - config.someString = 0; - config.multiCount = 0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - argv[0], - XOPT_CTX_NOCONDENSE, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "[opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (err) { - fprintf(stderr, "Error: %s\n", err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(someString, s); - P(multiCount, d); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - - exit_code = 0; -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 2; - goto exit; -} diff --git a/deps/xopt/test/optional-longarg-1.out b/deps/xopt/test/optional-longarg-1.out deleted file mode 100644 index e2a5f5ad..00000000 --- a/deps/xopt/test/optional-longarg-1.out +++ /dev/null @@ -1,11 +0,0 @@ -args: «-i» «10» «-d» «14.5» «foo» «bar» «--» «--some-other=20» - -someInt: 10 -someFloat: 0.000000 -someDouble: 14.500000 -help: 0 - -extra count: 3 -- foo -- bar -- --some-other=20 diff --git a/deps/xopt/test/optional-longarg.c b/deps/xopt/test/optional-longarg.c deleted file mode 100644 index 3c97b6b2..00000000 --- a/deps/xopt/test/optional-longarg.c +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - bool help; -} SimpleConfig; - -xoptOption options[] = { - { - 0, - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - 0, - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - 0, - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - const char **extrasPtr = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - argv[0], - 0, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "macro-test [opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (err) { - fprintf(stderr, "Error: %s\n", err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - - exit_code = 0; -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 2; - goto exit; -} diff --git a/deps/xopt/test/required-1.out b/deps/xopt/test/required-1.out deleted file mode 100644 index 663b7fe1..00000000 --- a/deps/xopt/test/required-1.out +++ /dev/null @@ -1,12 +0,0 @@ -args: «--some-int=10» «--some-double=14.5» «--some-required=1337» «foo» «bar» «--» «--some-other=20» - -someInt: 10 -someFloat: 0.000000 -someDouble: 14.500000 -someRequired: 1337 -help: 0 - -extra count: 3 -- foo -- bar -- --some-other=20 diff --git a/deps/xopt/test/required.c b/deps/xopt/test/required.c deleted file mode 100644 index 6adf0876..00000000 --- a/deps/xopt/test/required.c +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - int someRequired; - bool help; -} SimpleConfig; - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - "some-float", - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "some-required", - 'r', - offsetof(SimpleConfig, someRequired), - 0, - XOPT_TYPE_INT | XOPT_REQUIRED, - "n", - "Some value" - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - const char **extrasPtr = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.someRequired = 0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - argv[0], - 0, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "[opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (err) { - fprintf(stderr, "Error: %s\n", err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(someRequired, d); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - - exit_code = 0; -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 2; - goto exit; -} diff --git a/deps/xopt/test/simple-1.out b/deps/xopt/test/simple-1.out deleted file mode 100644 index f66b2ae2..00000000 --- a/deps/xopt/test/simple-1.out +++ /dev/null @@ -1,11 +0,0 @@ -args: «--some-int=10» «--some-double=14.5» «foo» «bar» «--» «--some-other=20» - -someInt: 10 -someFloat: 0.000000 -someDouble: 14.500000 -help: 0 - -extra count: 3 -- foo -- bar -- --some-other=20 diff --git a/deps/xopt/test/simple.c b/deps/xopt/test/simple.c deleted file mode 100644 index c8dd844e..00000000 --- a/deps/xopt/test/simple.c +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - bool help; -} SimpleConfig; - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - "some-float", - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int result; - const char *err; - xoptContext *ctx; - SimpleConfig config; - const char **extras = 0; - const char **extrasPtr = 0; - int extraCount; - - result = 0; - err = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.help = 0; - - /* create context */ - ctx = xopt_context("xopt-test", options, - XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, &err); - if (err) { - fprintf(stderr, "Error: %s\n", err); - result = 1; - goto exit; - } - - /* parse */ - extraCount = xopt_parse(ctx, argc, argv, &config, &extras, &err); - if (err) { - fprintf(stderr, "Error: %s\n", err); - result = 2; - goto exit; - } - - /* help? */ - if (config.help) { - xoptAutohelpOptions opts; - opts.usage = "[options] [extras...]"; - opts.prefix = "A simple demonstration of the XOpt options parser library."; - opts.suffix = "End argument list."; - opts.spacer = 10; - - xopt_autohelp(ctx, stderr, &opts, &err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - -exit: - if (extras) free(extras); /* DO NOT free individual strings */ - if (ctx) free(ctx); /* they point to argv strings */ - return result; -} diff --git a/deps/xopt/test/sloppyshorts-1.out b/deps/xopt/test/sloppyshorts-1.out deleted file mode 100644 index d9286cd8..00000000 --- a/deps/xopt/test/sloppyshorts-1.out +++ /dev/null @@ -1,14 +0,0 @@ -args: «-i10» «-d» «14.5» «-ssome string» «-m» «-mm» «-mmm» «foo» «bar» «--» «--is-not-passed» «ignoreme» - -someInt: 10 -someFloat: 0.000000 -someDouble: 14.500000 -someString: some string -multiCount: 6 -help: 0 - -extra count: 4 -- foo -- bar -- --is-not-passed -- ignoreme diff --git a/deps/xopt/test/sloppyshorts.c b/deps/xopt/test/sloppyshorts.c deleted file mode 100644 index 9f3d23b8..00000000 --- a/deps/xopt/test/sloppyshorts.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include - -#include "../xopt.h" - -typedef struct { - int someInt; - float someFloat; - double someDouble; - const char *someString; - int multiCount; - bool help; -} SimpleConfig; - -static void on_verbose(const char *v, void *data, const struct xoptOption *option, bool longArg, const char **err) { - (void) v; - (void) longArg; - (void) err; - int *count = (int *)(((char *) data) + option->offset); - ++*count; -} - -xoptOption options[] = { - { - "some-int", - 'i', - offsetof(SimpleConfig, someInt), - 0, - XOPT_TYPE_INT, - "n", - "Some integer value. Can set to whatever number you like." - }, - { - "some-float", - 'f', - offsetof(SimpleConfig, someFloat), - 0, - XOPT_TYPE_FLOAT, - "n", - "Some float value." - }, - { - "some-double", - 'd', - offsetof(SimpleConfig, someDouble), - 0, - XOPT_TYPE_DOUBLE, - "n", - "Some double value." - }, - { - "some-string", - 's', - offsetof(SimpleConfig, someString), - 0, - XOPT_TYPE_STRING, - "s", - "Some string value." - }, - { - 0, - 'm', - offsetof(SimpleConfig, multiCount), - &on_verbose, - XOPT_TYPE_BOOL, - 0, - "Specify multiple times to increase count" - }, - { - "help", - '?', - offsetof(SimpleConfig, help), - 0, - XOPT_TYPE_BOOL, - 0, - "Shows this help message" - }, - XOPT_NULLOPTION -}; - -int main(int argc, const char **argv) { - int exit_code = 1; - const char *err = NULL; - SimpleConfig config; - const char **extras = NULL; - const char **extrasPtr = NULL; - int extraCount = 0; - - /* show arguments */ - fputs("args:", stderr); - for (int i = 1; i < argc; i++) { - fprintf(stderr, " «%s»", argv[i]); - } - fputs("\n\n", stderr); - - /* setup defaults */ - config.someInt = 0; - config.someDouble = 0.0; - config.someFloat = 0.0f; - config.someString = 0; - config.multiCount = 0; - config.help = 0; - - XOPT_SIMPLE_PARSE( - argv[0], - XOPT_CTX_SLOPPYSHORTS, - &options[0], &config, - argc, argv, - &extraCount, &extras, - &err, - stderr, - "[opts...] [--] [extras...]", - "Tests the simple parser macro", - "[end of arguments]", - 15); - - if (err) { - fprintf(stderr, "Error: %s\n", err); - goto exit; - } - - /* print */ -#define P(field, delim) fprintf(stderr, #field ":\t%" #delim "\n", \ - config.field) - - P(someInt, d); - P(someFloat, f); - P(someDouble, f); - P(someString, s); - P(multiCount, d); - P(help, d); - - fprintf(stderr, "\nextra count: %d\n", extraCount); - extrasPtr = extras; - while (extraCount--) { - fprintf(stderr, "- %s\n", *extrasPtr++); - } - -#undef P - - exit_code = 0; -exit: - free(extras); /* DO NOT free individual strings */ - return exit_code; -xopt_help: - exit_code = 2; - goto exit; -} diff --git a/deps/xopt/test/test-case.sh b/deps/xopt/test/test-case.sh deleted file mode 100755 index 00fb5ae6..00000000 --- a/deps/xopt/test/test-case.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# -# To be used with CMake builds located in /build/ -# - -set -uo pipefail -exec >&2 - -casebin="$1" -caseout="$2" -shift 2 - -function die { - echo -e "error: $*" - exit 1 -} - -cd "$(dirname "$0")" - -if [ -z "$casebin" ]; then - die 'no test case executable specified' -fi - -if [ -z "$caseout" ]; then - die 'no test case output (some-case.out) specified' -fi - -if [ ! -x "$casebin" ]; then - die "test case does not exist or is not executable: $casebin" -fi - -if [ ! -f "$caseout" ]; then - die "test case expected output file does not exist: $caseout" -fi - -output="$("$casebin" "$@" 2>&1)" -r=$? -if [ $r -eq 139 ]; then - die "xopt test case failed with SEGFAULT ($r)" -fi - -diff="$(diff -U0 -d -t "$caseout" - <<< "$output" 2>&1)" -if [ ! -z "$diff" ]; then - die "xopt test case didn't match expected output: '$caseout'\n$diff" -fi diff --git a/deps/xopt/xopt.c b/deps/xopt/xopt.c deleted file mode 100644 index 7a020b46..00000000 --- a/deps/xopt/xopt.c +++ /dev/null @@ -1,584 +0,0 @@ -/** - * XOpt - command line parsing library - * - * Copyright (c) 2015-2019 Josh Junon - * - * 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. - */ - -#ifndef XOPT_NOSTANDARD -# define HAVE_STDARG_H 1 -# define HAVE_STDLIB_H 1 -# define HAVE_ASPRINTF_H 1 -# define vasprintf rpl_vasprintf -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "./xopt.h" -#include "./snprintf.c" - -#define EXTRAS_INIT 10 -#define ERRBUF_SIZE 1024 * 4 - -static char errbuf[ERRBUF_SIZE]; - -struct xoptContext { - const xoptOption *options; - long flags; - const char *name; - bool doubledash; - size_t options_count; - bool *required; - jmp_buf *jmp; -}; - -static void _xopt_set_err(xoptContext *ctx, const char **err, const char *const fmt, ...); -static int _xopt_parse_arg(xoptContext *ctx, int argc, const char **argv, - int *argi, void *data, const char **err); -static void _xopt_assert_increment(xoptContext *ctx, const char ***extras, int extrasCount, - size_t *extrasCapac, const char **err); -static int _xopt_get_size(const char *arg); -static int _xopt_get_arg(const xoptContext *ctx, const char *arg, size_t len, - int size, const xoptOption **option, size_t *option_index); -static void _xopt_set(xoptContext *ctx, void *data, const xoptOption *option, const char *val, - bool longArg, const char **err); -static void _xopt_default_callback(const char *value, void *data, - const xoptOption *option, bool longArg, const char **err); - -xoptContext* xopt_context(const char *name, const xoptOption *options, long flags, - const char **err) { - xoptContext* ctx; - *err = 0; - - /* malloc context and check */ - ctx = malloc(sizeof(xoptContext)); - if (!ctx) { - ctx = 0; - _xopt_set_err(NULL, err, "could not allocate context"); - } else { - const xoptOption *cur; - - ctx->options = options; - ctx->flags = flags; - ctx->name = name; - ctx->doubledash = false; - ctx->required = NULL; - ctx->jmp = NULL; - - ctx->options_count = 0; - cur = options; - for (; cur->longArg || cur->shortArg; cur++) ++ctx->options_count; - } - - return ctx; -} - -static int _xopt_parse_impl(xoptContext *ctx, int argc, const char **argv, void *data, - const char ***inextras, const char **err, int *extrasCount, size_t *extrasCapac, - const char ***extras, int *argi) { - int parseResult; - size_t i; - - *err = 0; - *argi = 0; - *extrasCount = 0; - *extrasCapac = EXTRAS_INIT; - *extras = malloc(sizeof(**extras) * EXTRAS_INIT); - - jmp_buf jmp; - ctx->jmp = &jmp; - if (setjmp(jmp)) { - goto end; - } - - /* check if extras malloc'd okay */ - if (!*extras) { - _xopt_set_err(ctx, err, "could not allocate extras array"); - } - - /* increment argument counter if we aren't - instructed to check argv[0] */ - if (!(ctx->flags & XOPT_CTX_KEEPFIRST)) { - ++(*argi); - } - - /* set up required parameters list */ - ctx->required = malloc(sizeof(*ctx->required) * ctx->options_count); - for (i = 0; i < ctx->options_count; i++) { - ctx->required[i] = (ctx->options[i].options & XOPT_REQUIRED) > 0; - } - - /* iterate over passed command line arguments */ - for (; *argi < argc; (*argi)++) { - /* parse, breaking if there was a failure - parseResult is 0 if option, 1 if extra, or 2 if double-dash was encountered */ - parseResult = _xopt_parse_arg(ctx, argc, argv, argi, data, err); - - /* is the argument an extra? */ - switch (parseResult) { - case 0: /* option */ - /* make sure we're super-posix'd if specified to be - (check that no extras have been specified when an option is parsed, - enforcing options to be specific before [extra] arguments */ - if ((ctx->flags & XOPT_CTX_POSIXMEHARDER) && *extrasCount) { - _xopt_set_err(ctx, err, "options cannot be specified after arguments: %s", argv[*argi]); - goto end; - } - break; - case 1: /* extra */ - /* make sure we have enough room, or realloc if we don't - - check that it succeeded */ - _xopt_assert_increment(ctx, extras, *extrasCount, extrasCapac, err); - - /* add extra to list */ - (*extras)[(*extrasCount)++] = argv[*argi]; - break; - case 2: /* "--" was encountered */ - /* nothing to do here - "--" was already handled for us */ - break; - } - } - -end: - if (!*err) { - for (i = 0; i < ctx->options_count; i++) { - if (ctx->required[i]) { - const xoptOption *opt = &ctx->options[i]; - if (opt->longArg) { - _xopt_set_err(ctx, err, "missing required option: --%s", opt->longArg); - } else { - _xopt_set_err(ctx, err, "missing required option: -%c", opt->shortArg); - } - break; - } - } - } - - free(ctx->required); - - if (!*err) { - /* append null terminator to extras */ - _xopt_assert_increment(ctx, extras, *extrasCount, extrasCapac, err); - if (!*err) { - (*extras)[*extrasCount] = 0; - } - } - - if (*err) { - free(*extras); - *inextras = 0; - return 0; - } - - *inextras = *extras; - return *extrasCount; -} - -int xopt_parse(xoptContext *ctx, int argc, const char **argv, void *data, - const char ***inextras, const char **err) { - /* avoid longjmp clobbering */ - int extrasCount; - size_t extrasCapac; - const char **extras; - int argi; - return _xopt_parse_impl(ctx, argc, argv, data, inextras, err, &extrasCount, &extrasCapac, &extras, &argi); -} - -void xopt_autohelp(xoptContext *ctx, FILE *stream, const xoptAutohelpOptions *options, - const char **err) { - const xoptOption *o; - size_t i, width = 0, twidth; - const char *nl = ""; - size_t spacer = options ? options->spacer : 2; - - *err = 0; - - /* make sure that if we ever write a call to _set_err() in the future here, - that we won't accidentally cause segfaults - we have an assertion in place - for ctx->jmp != NULL, so we make sure we'd trigger that assertion */ - ctx->jmp = NULL; - - if (options && options->usage) { - fprintf(stream, "%susage: %s %s\n", nl, ctx->name, options->usage); - nl = "\n"; - } - - if (options && options->prefix) { - fprintf(stream, "%s%s\n\n", nl, options->prefix); - nl = "\n"; - } - - /* find max width */ - for (i = 0; ctx->options[i].longArg || ctx->options[i].shortArg; i++) { - o = &ctx->options[i]; - twidth = 0; - if (o->longArg) { - twidth += 2 + strlen(o->longArg); - if (o->argDescrip) { - twidth += 1 + strlen(o->argDescrip); - } - } - if (ctx->options[i].shortArg) { - twidth += 2; - } - if (ctx->options[i].shortArg && ctx->options[i].longArg) { - twidth += 2; /* `, ` */ - } - - width = width > twidth ? width : twidth; - } - - /* print */ - for (i = 0; ctx->options[i].longArg || ctx->options[i].shortArg; i++) { - o = &ctx->options[i]; - twidth = 0; - if (o->shortArg) { - fprintf(stream, "-%c", o->shortArg); - twidth += 2; - } - - if (o->shortArg && o->longArg) { - fprintf(stream, ", "); - twidth += 2; - } - - if (o->longArg) { - fprintf(stream, "--%s", o->longArg); - twidth += 2 + strlen(o->longArg); - if (o->argDescrip) { - fprintf(stream, "=%s", o->argDescrip); - twidth += 1 + strlen(o->argDescrip); - } - } - - if (o->descrip) { - for (; twidth < (width + spacer); twidth++) { - fprintf(stream, " "); - } - - if (o->options & XOPT_REQUIRED) { - fprintf(stream, "(Required) %s\n", o->descrip); - } else { - fprintf(stream, "%s\n", o->descrip); - } - } - } - - if (options && options->suffix) { - fprintf(stream, "%s%s\n", nl, options->suffix); - } -} - -static void _xopt_set_err(xoptContext *ctx, const char **err, const char *const fmt, ...) { - va_list list; - va_start(list, fmt); - rpl_vsnprintf(&errbuf[0], ERRBUF_SIZE, fmt, list); - va_end(list); - *err = &errbuf[0]; - - if (ctx != NULL) { - assert(ctx->jmp != NULL); - longjmp(*ctx->jmp, 1); - } -} - -static int _xopt_parse_arg(xoptContext *ctx, int argc, const char **argv, - int *argi, void *data, const char **err) { - int size; - size_t length; - bool isExtra = false; - const xoptOption *option = NULL; - size_t option_index = 0; - const char* arg = argv[*argi]; - - /* are we in doubledash mode? */ - if (ctx->doubledash) { - return 1; - } - - /* get argument 'size' (long/short/extra) */ - size = _xopt_get_size(arg); - - /* adjust to parse from beginning of actual content */ - arg += size; - length = strlen(arg); - - if (size == 1 && length == 0) { - /* it's just a singular dash - treat it as an extra arg */ - return 1; - } - - if (size == 2 && length == 0) { - /* double-dash - everything after this is an extra */ - ctx->doubledash = 1; - return 2; - } - - switch (size) { - int argRequirement; - char *valStart; - case 1: /* short */ - /* parse all */ - while (length--) { - /* get argument or error if not found and strict mode enabled. */ - argRequirement = _xopt_get_arg(ctx, arg++, 1, size, &option, &option_index); - if (!option) { - if (ctx->flags & XOPT_CTX_STRICT) { - _xopt_set_err(ctx, err, "invalid option: -%c", arg[-1]); - } - break; - } - - if (argRequirement > 0 && length > 0 && !(ctx->flags & XOPT_CTX_SLOPPYSHORTS)) { - _xopt_set_err(ctx, err, "short option parameters must be separated, not condensed: %s", argv[*argi]); - } - - switch (argRequirement) { - case 0: /* flag; doesn't take an argument */ - if (length > 0 && (ctx->flags & XOPT_CTX_NOCONDENSE)) { - _xopt_set_err(ctx, err, "short options cannot be combined: %s", argv[*argi]); - } - - _xopt_set(ctx, data, option, 0, false, err); - break; - case 1: /* argument is optional */ - /* is there another argument, and is it a non-option? */ - if (*argi + 1 < argc && _xopt_get_size(argv[*argi + 1]) == 0) { - _xopt_set(ctx, data, option, argv[++*argi], false, err); - } else { - _xopt_set(ctx, data, option, 0, false, err); - } - break; - case 2: /* requires an argument */ - /* is it the last in a set of condensed options? */ - if (length == 0) { - /* is there another argument? */ - if (*argi + 1 < argc) { - /* is the next argument actually an option? - this indicates no value was passed */ - if (_xopt_get_size(argv[*argi + 1])) { - _xopt_set_err(ctx, err, "missing option value: -%c", - option->shortArg); - } else { - _xopt_set(ctx, data, option, argv[++*argi], false, err); - } - } else { - _xopt_set_err(ctx, err, "missing option value: -%c", - option->shortArg); - } - } else { - _xopt_set(ctx, data, option, arg, false, err); - length = 0; - } - break; - } - } - break; - case 2: /* long */ - /* find first equals sign */ - valStart = strchr(arg, '='); - - /* is there a value? */ - if (valStart) { - /* we also increase valStart here in order to lop off - the equals sign */ - length = valStart++ - arg; - - /* but not really, if it's null */ - if (!*valStart) { - valStart = 0; - } - } - - /* get the option */ - argRequirement = _xopt_get_arg(ctx, arg, length, size, &option, &option_index); - if (!option) { - _xopt_set_err(ctx, err, "invalid option: --%.*s", length, arg); - } else { - switch (argRequirement) { - case 0: /* flag; doesn't take an argument */ - if (valStart) { - _xopt_set_err(ctx, err, "option doesn't take a value: --%s", arg); - } - - _xopt_set(ctx, data, option, valStart, true, err); - break; - case 2: /* requires an argument */ - if (!valStart) { - _xopt_set_err(ctx, err, "missing option value: --%s", arg); - } - break; - } - - _xopt_set(ctx, data, option, valStart, true, err); - } - - break; - case 0: /* extra */ - isExtra = true; - break; - } - - if (option) { - /* indicate that we've seen this option and thus is no longer required */ - ctx->required[option_index] = false; - } - - return isExtra ? 1 : 0; -} - -static void _xopt_assert_increment(xoptContext *ctx, const char ***extras, int extrasCount, - size_t *extrasCapac, const char **err) { - /* have we hit the list size limit? */ - if ((size_t) extrasCount == *extrasCapac) { - /* increase capcity, realloc, and check for success */ - *extrasCapac += EXTRAS_INIT; - *extras = realloc(*extras, sizeof(**extras) * *extrasCapac); - if (!*extras) { - _xopt_set_err(ctx, err, "could not realloc arguments array"); - } - } -} - -static int _xopt_get_size(const char *arg) { - int size; - for (size = 0; size < 2; size++) { - if (arg[size] != '-') { - break; - } - } - return size; -} - -static int _xopt_get_arg(const xoptContext *ctx, const char *arg, size_t len, - int size, const xoptOption **option, size_t *option_index) { - size_t i; - - *option = 0; - - /* find the argument */ - for (i = 0; i < ctx->options_count; i++) { - const xoptOption *opt = &ctx->options[i]; - - if ((size == 1 && opt->shortArg == arg[0]) - || (opt->longArg && strlen(opt->longArg) == len && !strncmp(opt->longArg, arg, len))) { - *option_index = i; - *option = opt; - break; - } - } - - /* determine the optionality of a value */ - if (!*option || (*option)->options & XOPT_TYPE_BOOL) { - return 0; - } else if ((*option)->options & XOPT_PARAM_OPTIONAL) { - return 1; - } else { - return 2; - } -} - -static void _xopt_set(xoptContext *ctx, void *data, const xoptOption *option, const char *val, - bool longArg, const char **err) { - /* determine callback */ - xoptCallback callback = option->callback ? option->callback : &_xopt_default_callback; - - /* dispatch callback */ - callback(val, data, option, longArg, err); - - /* we check err here instead of relying upon longjmp() - since we can't call _set_err() with a context */ - if (*err) { - assert(ctx->jmp != NULL); - longjmp(*ctx->jmp, 1); - } -} - -static void _xopt_default_callback(const char *value, void *data, - const xoptOption *option, bool longArg, const char **err) { - void *target; - char *parsePtr = 0; - - /* is a value specified? */ - if ((!value || !strlen(value)) && !(option->options & XOPT_TYPE_BOOL)) { - /* we reach this point when they specified an optional, non-boolean - option but didn't specify a custom handler (therefore, it's not - optional). - - to fix, just remove the optional flag or specify a callback to handle - it yourself. - */ - return; - } - - /* get location */ - target = ((char*) data) + option->offset; - - /* switch on the type */ - switch (option->options & 0x3F) { - case XOPT_TYPE_BOOL: - /* booleans are special in that they won't have an argument passed - into this callback */ - *((_Bool*) target) = true; - break; - case XOPT_TYPE_STRING: - /* lifetime here works out fine; argv can usually be assumed static-like - in nature */ - *((const char**) target) = value; - break; - case XOPT_TYPE_INT: - *((int*) target) = (int) strtol(value, &parsePtr, 0); - break; - case XOPT_TYPE_LONG: - *((long*) target) = strtol(value, &parsePtr, 0); - break; - case XOPT_TYPE_FLOAT: - *((float*) target) = (float) strtod(value, &parsePtr); - break; - case XOPT_TYPE_DOUBLE: - *((double*) target) = strtod(value, &parsePtr); - break; - default: /* something wonky, or the implementation specifies two types */ - fprintf(stderr, "warning: XOpt argument type invalid: %ld\n", - option->options & 0x2F); - break; - } - - /* check that our parsing functions worked */ - if (parsePtr && *parsePtr) { - if (longArg) { - _xopt_set_err(NULL, err, "value isn't a valid number: --%s=%s", - (void*) option->longArg, value); - } else { - _xopt_set_err(NULL, err, "value isn't a valid number: -%c %s", - option->shortArg, value); - } - } -} - diff --git a/deps/xopt/xopt.h b/deps/xopt/xopt.h deleted file mode 100644 index 59071f8d..00000000 --- a/deps/xopt/xopt.h +++ /dev/null @@ -1,225 +0,0 @@ -/** - * XOpt - command line parsing library - * - * Copyright (c) 2015 Josh Junon. - * - * 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. - */ -#ifndef XOPT_H__ -#define XOPT_H__ -#pragma once - -#include -#include - -struct xoptOption; - -#ifndef offsetof -# define offsetof(T, member) (size_t)(&(((T*)0)->member)) -#endif - -/** - * Callback type for handling values. - * Called when a command line argument has been - * processed. - */ -typedef void (*xoptCallback)( - const char *value, /* string cmd line option */ - void *data, /* custom data structure */ - const struct xoptOption *option, /* detected option */ - bool longArg, /* true if the long-arg version - was used */ - const char **err); /* err output */ - -enum xoptOptionFlag { - XOPT_TYPE_STRING = 0x1, /* const char* type */ - XOPT_TYPE_INT = 0x2, /* int type */ - XOPT_TYPE_LONG = 0x4, /* long type */ - XOPT_TYPE_FLOAT = 0x8, /* float type */ - XOPT_TYPE_DOUBLE = 0x10, /* double type */ - XOPT_TYPE_BOOL = 0x20, /* boolean (int) type */ - - XOPT_PARAM_OPTIONAL = 0x40, /* whether the argument value is - optional */ - XOPT_REQUIRED = 0x80 /* indicates the flag must be - present on the command line */ -}; - -enum xoptContextFlag { - XOPT_CTX_KEEPFIRST = 0x1, /* don't ignore argv[0] */ - XOPT_CTX_POSIXMEHARDER = 0x2, /* options cannot come after - extra arguments */ - XOPT_CTX_NOCONDENSE = 0x4, /* don't allow short args to be - condensed (i.e. `ls -laF') */ - XOPT_CTX_SLOPPYSHORTS = 0x8, /* allow short arg values to be - directly after the character */ - XOPT_CTX_STRICT = 0x10 /* fails on invalid arguments */ -}; - -typedef struct xoptOption { - const char *longArg; /* --long-arg-name, or 0 for short - arg only */ - const char shortArg; /* -s hort arg character, or '\0' - for long arg only */ - size_t offset; /* offsetof(type, property) for - automatic configuration handler */ - xoptCallback callback; /* callback for resolved option - handling */ - long options; /* xoptOptionFlag options */ - const char *argDescrip; /* --argument=argDescrip (autohelp) */ - const char *descrip; /* argument explanation (autohelp) */ -} xoptOption; - -/* option list terminator */ -#define XOPT_NULLOPTION {0, 0, 0, 0, 0, 0, 0} - -typedef struct xoptContext xoptContext; - -typedef struct xoptAutohelpOptions { - const char *usage; /* usage string, or null */ - const char *prefix; /* printed before options, or null */ - const char *suffix; /* printed after options, or null */ - size_t spacer; /* number of spaces between option and - description */ -} xoptAutohelpOptions; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Creates an XOpt context to be used with - * subsequent calls to XOpt functions - */ -xoptContext* -xopt_context( - const char *name, /* name of the argument set (usually - name of the cli binary file/cmd */ - const xoptOption *options, /* list of xoptOption objects, - terminated with XOPT_NULLOPTION */ - long flags, /* xoptContextFlag flags */ - const char **err); /* pointer to a const char* that - receives an err should one occur - - set to 0 if command completed - successfully */ - -/** - * Parses the command line of a program - * and returns the number of non-options - * returned to the `extras' pointer (see - * below) - */ -int -xopt_parse( - xoptContext *ctx, /* previously created XOpt context */ - int argc, /* argc, from int main() */ - const char **argv, /* argv, from int main() */ - void *data, /* a custom data object whos type - corresponds to `.offset' values - specified in the options list; - populated with values interpreted - from the command line */ - const char ***extras, /* receives a list of extra non-option - arguments (i.e. files, subcommands, - etc.) - length of which is returned - by the function call */ - const char **err); /* pointer to a const char* that - receives an err should one occur - - set to 0 if command completed - successfully */ - -/** - * Generates and prints a help message - * and prints it to a FILE stream. - * If `defaults' is supplied, uses - * offsets (values) defined by the options - * list to show default options - */ -void -xopt_autohelp( - xoptContext *ctx, /* previously created XOpt context */ - FILE *stream, /* a stream to print to - if 0, - defaults to `stderr'. */ - const xoptAutohelpOptions *options, /* configuration options to tailor - autohelp output */ - const char **err); /* pointer to a const char* that - receives an err should one occur - - set to 0 if command completed - successfully */ - -/** - * Generates a default option parser that's sane for most cases. - * - * Assumes there's a `help` property that is boolean-checkable that exists on the - * config pointer passed to `config_ptr` (i.e. does a lookup of `config_ptr->help`). - * - * In the event help is invoked, xopt will `goto xopt_help`. It is up to you to define such - * a label in order to recover. In this case, extrav will still be allocated and will still need to be - * freed. - * - * To be extra clear, you need to free `extrav_ptr` is if `*err_ptr` is not `NULL`. - * - * `name` is the name of the binary you'd like to pass to the context (welcome to use `argv[0]` here), - * `options` is a reference to the xoptOptions array you've specified, - * `config_ptr` is a *pointer* to your configuration instance, - * `argc` and `argv` are the int/const char ** passed into main, - * `extrac_ptr` and `extrav_ptr` are pointers to an `int`/`const char **` - * (so `int*` and `const char ***`, respectively) that receive the parsed extra args - * (note that, unless there is an error, `extrav_ptr` is owned by your program and must - * be `free()`'d when you're done using it, even if there are zero extra arguments), - * and `err_ptr` is a pointer to a `const char *` (so a `const char **`) that receives any error - * strings in the event of a problem. These errors are statically allocated so no need to - * free them. This variable should be initialized to NULL and checked after calling - * `XOPT_SIMPLE_PARSE()`. - * - * `autohelp_file`, `autohelp_usage`, `autohelp_prefix`, `autohelp_suffix` and `autohelp_spacer` are all - * parameters to the `xoptAutohelpOptions` struct (with the exception of `autohelp_file`, which must be a - * `FILE*` reference (e.g. `stdout` or `stderr`) which receives the rendered autohelp text). Consult the - * `xoptAutohelpOptions` struct above for documentation as to valid values for each of these properties. - */ -#define XOPT_SIMPLE_PARSE(name, flags, options, config_ptr, argc, argv, extrac_ptr, extrav_ptr, err_ptr, autohelp_file, autohelp_usage, autohelp_prefix, autohelp_suffix, autohelp_spacer) do { \ - xoptContext *_xopt_ctx; \ - *(err_ptr) = NULL; \ - _xopt_ctx = xopt_context((name), (options), ((flags) ^ XOPT_CTX_POSIXMEHARDER ^ XOPT_CTX_STRICT), (err_ptr)); \ - if (*(err_ptr)) break; \ - *extrac_ptr = xopt_parse(_xopt_ctx, (argc), (argv), (config_ptr), (extrav_ptr), (err_ptr)); \ - if ((config_ptr)->help) { \ - xoptAutohelpOptions __xopt_autohelp_opts; \ - __xopt_autohelp_opts.usage = (autohelp_usage); \ - __xopt_autohelp_opts.prefix = (autohelp_prefix); \ - __xopt_autohelp_opts.suffix = (autohelp_suffix); \ - __xopt_autohelp_opts.spacer = (autohelp_spacer); \ - xopt_autohelp(_xopt_ctx, (autohelp_file), &__xopt_autohelp_opts, (err_ptr)); \ - if (*(err_ptr)) goto __xopt_end_free_extrav; \ - goto xopt_help; \ - } \ - if (*(err_ptr)) goto __xopt_end_free_ctx; \ - __xopt_end_free_ctx: \ - free(_xopt_ctx); \ - break; \ - __xopt_end_free_extrav: \ - free(*(extrav_ptr)); \ - free(_xopt_ctx); \ - break; \ - } while (false) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/main.c b/src/main.c index f861ab96..7a000a7e 100644 --- a/src/main.c +++ b/src/main.c @@ -11,8 +11,8 @@ #include "backtrace.h" #include "sqlite3.h" -#include "xopt.h" +#include #include #include @@ -41,47 +41,13 @@ struct backtrace_state* g_backtrace_state; const char* k_db_path_default = "db.sqlite"; -#define XOPT_PARSE( \ - name, flags, options, config_ptr, argc, argv, extrac_ptr, extrav_ptr, err_ptr, autohelp_file, autohelp_usage, autohelp_prefix, autohelp_suffix, autohelp_spacer) \ - do \ - { \ - xoptContext* _xopt_ctx; \ - *(err_ptr) = NULL; \ - _xopt_ctx = xopt_context((name), (options), ((flags) ^ XOPT_CTX_POSIXMEHARDER), (err_ptr)); \ - if (*(err_ptr)) \ - break; \ - *extrac_ptr = xopt_parse(_xopt_ctx, (argc), (argv), (config_ptr), (extrav_ptr), (err_ptr)); \ - if ((config_ptr)->help) \ - { \ - xoptAutohelpOptions __xopt_autohelp_opts; \ - __xopt_autohelp_opts.usage = (autohelp_usage); \ - __xopt_autohelp_opts.prefix = (autohelp_prefix); \ - __xopt_autohelp_opts.suffix = (autohelp_suffix); \ - __xopt_autohelp_opts.spacer = (autohelp_spacer); \ - xopt_autohelp(_xopt_ctx, (autohelp_file), &__xopt_autohelp_opts, (err_ptr)); \ - if (*(err_ptr)) \ - goto __xopt_end_free_extrav; \ - free(_xopt_ctx); \ - goto xopt_help; \ - } \ - if (*(err_ptr)) \ - goto __xopt_end_free_ctx; \ - __xopt_end_free_ctx: \ - free(_xopt_ctx); \ - break; \ - __xopt_end_free_extrav: \ - free(*(extrav_ptr)); \ - free(_xopt_ctx); \ - break; \ - } while (false) - #if !TARGET_OS_IPHONE && !defined(__ANDROID__) static int _tf_command_test(const char* file, int argc, char* argv[]); static int _tf_command_import(const char* file, int argc, char* argv[]); static int _tf_command_export(const char* file, int argc, char* argv[]); static int _tf_command_run(const char* file, int argc, char* argv[]); static int _tf_command_sandbox(const char* file, int argc, char* argv[]); -static int _tf_command_usage(const char* file, int argc, char* argv[]); +static int _tf_command_usage(const char* file); typedef struct _command_t { @@ -101,140 +67,182 @@ const command_t k_commands[] = { static int _tf_command_test(const char* file, int argc, char* argv[]) { #if !defined(__ANDROID__) - typedef struct args_t + tf_test_options_t test_options = { - const char* tests; - bool help; - } args_t; - - xoptOption options[] = { - { "tests", 't', offsetof(args_t, tests), NULL, XOPT_TYPE_STRING, NULL, "Comma-separated list of test names to run." }, - { "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, - XOPT_NULLOPTION, - }; - - args_t args = { 0 }; - const char** extras = NULL; - int extra_count = 0; - const char* err = NULL; - XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "test [options]", "options:", NULL, 15); - if (err) - { - fprintf(stderr, "Error: %s\n", err); - return 2; - } - - tf_test_options_t test_options = { .exe_path = file, - .tests = args.tests, }; + bool show_usage = false; + + while (!show_usage) + { + static struct option k_options[] = + { + { "tests", required_argument, NULL, 't' }, + { "help", no_argument, NULL, 'h' }, + { 0 }, + }; + int c = getopt_long(argc, argv, "t:h", k_options, NULL); + if (c == -1) + { + break; + } + + switch (c) + { + case '?': + case 'h': + default: + show_usage = true; + break; + case 't': + test_options.tests = optarg; + break; + } + } + + for (int i = optind; i < argc; i++) + { + tf_printf("Unexpected argument: %s\n", argv[i]); + show_usage = true; + } + + if (show_usage) + { + tf_printf("\n%s test [options]\n\n", file); + tf_printf("options\n"); + tf_printf(" -t, --tests tests Comma-separated list of tests to run. (default: all)\n"); + tf_printf(" -h, --help Show this usage information.\n"); + return EXIT_FAILURE; + } + tf_tests(&test_options); - if (extras) - { - free((void*)extras); - } - return 0; -xopt_help: - if (extras) - { - free((void*)extras); - } + return EXIT_SUCCESS; +#else + return EXIT_FAILURE; #endif - return 1; } static int _tf_command_import(const char* file, int argc, char* argv[]) { - typedef struct args_t - { - const char* user; - const char* db_path; - bool help; - } args_t; + const char* user = "import"; + const char* db_path = k_db_path_default; + bool show_usage = false; - xoptOption options[] = { - { "user", 'u', offsetof(args_t, user), NULL, XOPT_TYPE_STRING, NULL, "User into whose account apps will be imported (default: \"import\")." }, - { "db-path", 'd', offsetof(args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." }, - { "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, - XOPT_NULLOPTION, - }; - - args_t args = { .user = "import", .db_path = k_db_path_default }; - const char** extras = NULL; - int extra_count = 0; - const char* err = NULL; - XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, - "import [options] [paths] ...", "options:", NULL, 15); - if (err) + while (!show_usage) { - fprintf(stderr, "Error: %s\n", err); - return 2; + static struct option k_options[] = + { + { "user", required_argument, NULL, 'u' }, + { "db-path", required_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { 0 }, + }; + int c = getopt_long(argc, argv, "u:d:h", k_options, NULL); + if (c == -1) + { + break; + } + + switch (c) + { + case '?': + case 'h': + default: + show_usage = true; + break; + case 'u': + user = optarg; + break; + case 'd': + db_path = optarg; + break; + } } - tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, args.db_path); - if (extra_count) + if (show_usage) { - for (int i = 0; i < extra_count; i++) + tf_printf("\n%s import [options] [paths...]\n\n", file); + tf_printf("options:\n"); + tf_printf(" -u, --user user User into whose account apps will be imported (default: \"import\").\n"); + tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default); + tf_printf(" -h, --help Show this usage information.\n"); + return EXIT_FAILURE; + } + + tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path); + if (optind < argc) + { + for (int i = optind; i < argc; i++) { - tf_printf("Importing %s...\n", extras[i]); - tf_ssb_import(ssb, args.user, extras[i]); + tf_printf("Importing %s...\n", argv[i]); + tf_ssb_import(ssb, user, argv[i]); } } else { tf_printf("Importing %s...\n", "apps"); - tf_ssb_import(ssb, args.user, "apps"); + tf_ssb_import(ssb, user, "apps"); } tf_ssb_destroy(ssb); - - if (extras) - { - free((void*)extras); - } - return 0; - -xopt_help: - if (extras) - { - free((void*)extras); - } - return 1; + return EXIT_SUCCESS; } static int _tf_command_export(const char* file, int argc, char* argv[]) { - typedef struct args_t - { - const char* user; - const char* db_path; - bool help; - } args_t; + const char* user = "core"; + const char* db_path = k_db_path_default; + bool show_usage = false; - xoptOption options[] = { - { "db-path", 'd', offsetof(args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." }, - { "user", 'u', offsetof(args_t, user), NULL, XOPT_TYPE_STRING, NULL, "User into whose apps will be exported (default: \"core\")." }, - { "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, - XOPT_NULLOPTION, - }; - - args_t args = { .user = "core", .db_path = k_db_path_default }; - const char** extras = NULL; - int extra_count = 0; - const char* err = NULL; - XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, - "export [options] [paths] ...", "options:", NULL, 15); - if (err) + while (!show_usage) { - fprintf(stderr, "Error: %s\n", err); - return 2; - } - tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, args.db_path); - if (extra_count) - { - for (int i = 0; i < extra_count; i++) + static const struct option k_options[] = { - tf_printf("Exporting %s...\n", extras[i]); - tf_ssb_export(ssb, extras[i]); + { "user", required_argument, NULL, 'u' }, + { "db-path", required_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { 0 }, + }; + int c = getopt_long(argc, argv, "u:d:h", k_options, NULL); + if (c == -1) + { + break; + } + + switch (c) + { + case '?': + case 'h': + default: + show_usage = true; + break; + case 'u': + user = optarg; + break; + case 'd': + db_path = optarg; + break; + } + } + + if (show_usage) + { + tf_printf("\n%s export [options] [paths...]\n\n", file); + tf_printf("options:\n"); + tf_printf(" -u, --user user User from whose account apps will be exported (default: \"core\").\n"); + tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default); + tf_printf(" -h, --help Show this usage information.\n"); + tf_printf("\n"); + tf_printf("paths Paths of apps to export (example: /~core/ssb /~user/app).\n"); + return EXIT_FAILURE; + } + + tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path); + if (optind < argc) + { + for (int i = optind; i < argc; i++) + { + tf_printf("Exporting %s...\n", argv[i]); + tf_ssb_export(ssb, argv[i]); } } else @@ -253,25 +261,13 @@ static int _tf_command_export(const char* file, int argc, char* argv[]) for (int i = 0; i < (int)_countof(k_export); i++) { char buffer[256]; - snprintf(buffer, sizeof(buffer), "/~%s/%s", args.user, k_export[i]); + snprintf(buffer, sizeof(buffer), "/~%s/%s", user, k_export[i]); tf_printf("Exporting %s...\n", buffer); tf_ssb_export(ssb, buffer); } } tf_ssb_destroy(ssb); - - if (extras) - { - free((void*)extras); - } - return 0; - -xopt_help: - if (extras) - { - free((void*)extras); - } - return 1; + return EXIT_SUCCESS; } #endif @@ -412,21 +408,6 @@ static void _shed_privileges() static int _tf_command_run(const char* file, int argc, char* argv[]) { - xoptOption options[] = { - { "script", 's', offsetof(tf_run_args_t, script), NULL, XOPT_TYPE_STRING, NULL, "Script to run (default: core/core.js)." }, - { "ssb-port", 'b', offsetof(tf_run_args_t, ssb_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run SSB (default: 8008)." }, - { "http-port", 'p', offsetof(tf_run_args_t, http_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run Tilde Friends web server (default: 12345)." }, - { "https-port", 'q', offsetof(tf_run_args_t, https_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run secure Tilde Friends web server (default: 12346)." }, - { "db-path", 'd', offsetof(tf_run_args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." }, - { "count", 'n', offsetof(tf_run_args_t, count), NULL, XOPT_TYPE_INT, NULL, "Number of instances to run." }, - { "args", 'a', offsetof(tf_run_args_t, args), NULL, XOPT_TYPE_STRING, NULL, "Arguments of the form key=value,foo=bar,verbose=true." }, - { "one-proc", 'o', offsetof(tf_run_args_t, one_proc), NULL, XOPT_TYPE_BOOL, NULL, "Run everything in one process (unsafely!)." }, - { "zip", 'z', offsetof(tf_run_args_t, zip), NULL, XOPT_TYPE_STRING, NULL, "Zip archive from which to load files." }, - { "verbose", 'v', offsetof(tf_run_args_t, verbose), NULL, XOPT_TYPE_BOOL, NULL, "Log raw messages." }, - { "help", 'h', offsetof(tf_run_args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, - XOPT_NULLOPTION, - }; - tf_run_args_t args = { .count = 1, .script = "core/core.js", @@ -435,16 +416,86 @@ static int _tf_command_run(const char* file, int argc, char* argv[]) .ssb_port = 8008, .db_path = k_db_path_default, }; - const char** extras = NULL; - int extra_count = 0; - const char* err = NULL; - XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, - "run [options] [paths] ...", "options:", NULL, 15); + bool show_usage = false; - if (err) + while (!show_usage) { - fprintf(stderr, "Error: %s\n", err); - return 2; + static const struct option k_options[] = + { + { "script", required_argument, NULL, 's' }, + { "ssb-port", required_argument, NULL, 'b' }, + { "http-port", required_argument, NULL, 'p' }, + { "https-port", required_argument, NULL, 'q' }, + { "db-path", required_argument, NULL, 'd' }, + { "count", required_argument, NULL, 'n' }, + { "args", required_argument, NULL, 'a' }, + { "one-proc", no_argument, NULL, 'o' }, + { "zip", required_argument, NULL, 'z' }, + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + }; + int c = getopt_long(argc, argv, "s:b:p:q:d:n:a:oz:vh", k_options, NULL); + if (c == -1) + { + break; + } + + switch (c) + { + case '?': + case 'h': + default: + show_usage = true; + break; + case 's': + args.script = optarg; + break; + case 'b': + args.ssb_port = atoi(optarg); + break; + case 'p': + args.http_port = atoi(optarg); + break; + case 'q': + args.https_port = atoi(optarg); + break; + case 'd': + args.db_path = optarg; + break; + case 'n': + args.count = atoi(optarg); + break; + case 'a': + args.args = optarg; + break; + case 'o': + args.one_proc = true; + break; + case 'z': + args.zip = optarg; + break; + case 'v': + args.verbose = true; + break; + } + } + + if (show_usage) + { + tf_printf("\n%s run [options]\n\n", file); + tf_printf("options\n"); + tf_printf(" -s, --script script Script to run (default: core/core.js).\n"); + tf_printf(" -b, --ssb-port port Port on which to run SSB (default: 8008, 0 disables).\n"); + tf_printf(" -p, --http-port port Port on which to run Tilde Friends web server (default: 12345).\n"); + tf_printf(" -q, --https-port port Port on which to run secure Tilde Friends web server (default: 12346).\n"); + tf_printf(" -d, --db-path path SQLite database path (default: %s).\n", k_db_path_default); + tf_printf(" -n, --count count Number of instances to run.\n"); + tf_printf(" -a, --args args Arguments of the format key=value,foo=bar,verbose=true.\n"); + tf_printf(" -o, --one-proc Run everything in one process (unsafely!).\n"); + tf_printf(" -z, --zip path Zip archive from which to load files.\n"); + tf_printf(" -v, --verbose Log raw messages.\n"); + tf_printf(" -h, --help Show this usage information.\n"); + return EXIT_FAILURE; } int result = 0; @@ -479,44 +530,41 @@ static int _tf_command_run(const char* file, int argc, char* argv[]) tf_free(data); tf_free(threads); } - - if (extras) - { - free((void*)extras); - } return result; - -xopt_help: - if (extras) - { - free((void*)extras); - } - return 1; } static int _tf_command_sandbox(const char* file, int argc, char* argv[]) { - typedef struct args_t - { - const char* script; - bool help; - } args_t; + bool show_usage = false; - xoptOption options[] = { - { "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, - XOPT_NULLOPTION, - }; - - args_t args = { 0 }; - const char** extras = NULL; - int extra_count = 0; - const char* err = NULL; - XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, - "sandbox [options]", "options:", NULL, 15); - if (err) + while (!show_usage) { - fprintf(stderr, "Error: %s\n", err); - return 2; + static const struct option k_options[] = + { + { "help", no_argument, NULL, 'h' }, + { 0 }, + }; + int c = getopt_long(argc, argv, "h", k_options, NULL); + if (c == -1) + { + break; + } + switch (c) + { + case '?': + case 'h': + default: + show_usage = true; + break; + } + } + + if (show_usage) + { + tf_printf("\nUsage: %s sandbox [options]\n\n", file); + tf_printf("options:\n"); + tf_printf(" -h, --help Show this usage information.\n"); + return EXIT_FAILURE; } #if defined(__linux__) @@ -528,22 +576,11 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[]) /* The caller will trigger tf_task_activate with a message. */ tf_task_run(task); tf_task_destroy(task); - if (extras) - { - free((void*)extras); - } - return 0; - -xopt_help: - if (extras) - { - free((void*)extras); - } - return 1; + return EXIT_SUCCESS; } #if !defined(__ANDROID__) -static int _tf_command_usage(const char* file, int argc, char* argv[]) +static int _tf_command_usage(const char* file) { tf_printf("Usage: %s command [command-options]\n", file); tf_printf("commands:\n"); @@ -675,15 +712,15 @@ int main(int argc, char* argv[]) const command_t* command = &k_commands[i]; if (strcmp(argv[1], command->name) == 0) { - result = command->callback(argv[0], argc - 2, argv + 2); + result = command->callback(argv[0], argc - 1, argv + 1); goto done; } } - result = _tf_command_usage(argv[0], argc, argv); + result = _tf_command_usage(argv[0]); } else { - result = _tf_command_run(argv[0], argc - 1, argv + 1); + result = _tf_command_run(argv[0], argc, argv); } done: tf_mem_shutdown();