From 55643d6370430a73bbf0c4ce8d7a2e689b9891d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Aug 2017 04:30:53 -0700 Subject: [PATCH] Use getopt to handle options in makehrtf --- CMakeLists.txt | 5 ++ config.h.in | 3 ++ utils/getopt.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ utils/getopt.h | 26 +++++++++ utils/makehrtf.c | 161 ++++++++++++++++++++++++++++++------------------------- 5 files changed, 260 insertions(+), 72 deletions(-) create mode 100644 utils/getopt.c create mode 100644 utils/getopt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5adfac25..25d66d6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -652,6 +652,8 @@ int main() ENDIF() ENDIF() +CHECK_SYMBOL_EXISTS(getopt unistd.h HAVE_GETOPT) + # Check for a 64-bit type CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) IF(NOT HAVE_STDINT_H) @@ -1395,6 +1397,9 @@ IF(ALSOFT_UTILS) TARGET_LINK_LIBRARIES(openal-info OpenAL) ADD_EXECUTABLE(makehrtf utils/makehrtf.c) + IF(NOT HAVE_GETOPT) + SET_PROPERTY(TARGET makehrtf APPEND PROPERTY SOURCE utils/getopt.c) + ENDIF() SET_PROPERTY(TARGET makehrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(HAVE_LIBM) TARGET_LINK_LIBRARIES(makehrtf m) diff --git a/config.h.in b/config.h.in index 56a78448..824ea84f 100644 --- a/config.h.in +++ b/config.h.in @@ -20,6 +20,9 @@ /* Define if we have the _aligned_malloc function */ #cmakedefine HAVE__ALIGNED_MALLOC +/* Define if we have the getopt function */ +#cmakedefine HAVE_GETOPT + /* Define if we have SSE CPU extensions */ #cmakedefine HAVE_SSE #cmakedefine HAVE_SSE2 diff --git a/utils/getopt.c b/utils/getopt.c new file mode 100644 index 00000000..ab1a246e --- /dev/null +++ b/utils/getopt.c @@ -0,0 +1,137 @@ +/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ +#include +#include +#include +#include "getopt.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * Get program name in Windows + */ +const char * _getprogname(void); + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || *place == 0) { /* update scanning pointer */ + optreset = 0; + place = nargv[optind]; + if (optind >= nargc || *place++ != '-') { + /* Argument is absent or is not an option */ + place = EMSG; + return (-1); + } + optopt = *place++; + if (optopt == '-' && *place == 0) { + /* "--" => end of options */ + ++optind; + place = EMSG; + return (-1); + } + if (optopt == 0) { + /* Solitary '-', treat as a '-' option + if the program (eg su) is looking for it. */ + place = EMSG; + if (strchr(ostr, '-') == NULL) + return (-1); + optopt = '-'; + } + } else + optopt = *place++; + + /* See if option letter is one the caller wanted... */ + if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) { + if (*place == 0) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", _getprogname(), + optopt); + return (BADCH); + } + + /* Does this option need an argument? */ + if (oli[1] != ':') { + /* don't need argument */ + optarg = NULL; + if (*place == 0) + ++optind; + } else { + /* Option-argument is either the rest of this argument or the + entire next argument. */ + if (*place) + optarg = place; + else if (nargc > ++optind) + optarg = nargv[optind]; + else { + /* option-argument absent */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + _getprogname(), optopt); + return (BADCH); + } + place = EMSG; + ++optind; + } + return (optopt); /* return option letter */ +} + +const char * _getprogname() { + char *pgmptr = NULL; + _get_pgmptr(&pgmptr); + return strrchr(pgmptr,'\\')+1; +} + diff --git a/utils/getopt.h b/utils/getopt.h new file mode 100644 index 00000000..f894d9d9 --- /dev/null +++ b/utils/getopt.h @@ -0,0 +1,26 @@ +#ifndef GETOPT_H +#define GETOPT_H + +#ifndef _WIN32 + +#include + +#else /* _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern char *optarg; +extern int optind, opterr, optopt, optreset; + +int getopt(int nargc, char * const nargv[], const char *ostr); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_WIN32 */ + +#endif /* !GETOPT_H */ + diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 344754e9..e7dd34c3 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -71,6 +71,11 @@ #ifdef HAVE_STRINGS_H #include #endif +#ifdef HAVE_GETOPT +#include +#else +#include "getopt.h" +#endif // Rely (if naively) on OpenAL's header for the types used for serialization. #include "AL/al.h" @@ -2911,26 +2916,26 @@ static void PrintHelp(const char *argv0, FILE *ofile) fprintf(ofile, " Defaults output to: ./oalsoft_hrtf_%%r.mhr\n"); fprintf(ofile, " -h, --help Displays this help information.\n\n"); fprintf(ofile, "Options:\n"); - fprintf(ofile, " -r= Change the data set sample rate to the specified value and\n"); + fprintf(ofile, " -r Change the data set sample rate to the specified value and\n"); fprintf(ofile, " resample the HRIRs accordingly.\n"); - fprintf(ofile, " -f= Override the FFT window size (default: %u).\n", DEFAULT_FFTSIZE); - fprintf(ofile, " -e={on|off} Toggle diffuse-field equalization (default: %s).\n", (DEFAULT_EQUALIZE ? "on" : "off")); - fprintf(ofile, " -s={on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DEFAULT_SURFACE ? "on" : "off")); - fprintf(ofile, " -l={|none} Specify a limit to the magnitude range of the diffuse-field\n"); + fprintf(ofile, " -f Override the FFT window size (default: %u).\n", DEFAULT_FFTSIZE); + fprintf(ofile, " -e {on|off} Toggle diffuse-field equalization (default: %s).\n", (DEFAULT_EQUALIZE ? "on" : "off")); + fprintf(ofile, " -s {on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DEFAULT_SURFACE ? "on" : "off")); + fprintf(ofile, " -l {|none} Specify a limit to the magnitude range of the diffuse-field\n"); fprintf(ofile, " average (default: %.2f).\n", DEFAULT_LIMIT); - fprintf(ofile, " -w= Specify the size of the truncation window that's applied\n"); + fprintf(ofile, " -w Specify the size of the truncation window that's applied\n"); fprintf(ofile, " after minimum-phase reconstruction (default: %u).\n", DEFAULT_TRUNCSIZE); - fprintf(ofile, " -d={dataset| Specify the model used for calculating the head-delay timing\n"); + fprintf(ofile, " -d {dataset| Specify the model used for calculating the head-delay timing\n"); fprintf(ofile, " sphere} values (default: %s).\n", ((DEFAULT_HEAD_MODEL == HM_DATASET) ? "dataset" : "sphere")); - fprintf(ofile, " -c= Use a customized head radius measured ear-to-ear in meters.\n"); - fprintf(ofile, " -i= Specify an HRIR definition file to use (defaults to stdin).\n"); - fprintf(ofile, " -o= Specify an output file. Overrides command-selected default.\n"); + fprintf(ofile, " -c Use a customized head radius measured ear-to-ear in meters.\n"); + fprintf(ofile, " -i Specify an HRIR definition file to use (defaults to stdin).\n"); + fprintf(ofile, " -o Specify an output file. Overrides command-selected default.\n"); fprintf(ofile, " Use of '%%r' will be substituted with the data set sample rate.\n"); } #ifdef _WIN32 #define main my_main -int main(int argc, const char *argv[]); +int main(int argc, char *argv[]); static char **arglist; static void cleanup_arglist(void) @@ -2950,12 +2955,12 @@ int wmain(int argc, const wchar_t *wargv[]) for(i = 0;i < argc;i++) arglist[i] = ToUTF8(wargv[i]); - return main(argc, (const char**)arglist); + return main(argc, arglist); } #endif // Standard command line dispatch. -int main(int argc, const char *argv[]) +int main(int argc, char *argv[]) { const char *inName = NULL, *outName = NULL; OutputFormatT outFormat; @@ -2967,13 +2972,13 @@ int main(int argc, const char *argv[]) uint truncSize; double radius; double limit; - int argi; + int opt; if(argc < 2 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { fprintf(stdout, "HRTF Processing and Composition Utility\n\n"); PrintHelp(argv[0], stdout); - return 0; + exit(EXIT_SUCCESS); } if(strcmp(argv[1], "--make-mhr") == 0 || strcmp(argv[1], "-m") == 0) @@ -2985,7 +2990,7 @@ int main(int argc, const char *argv[]) { fprintf(stderr, "Error: Invalid command '%s'.\n\n", argv[1]); PrintHelp(argv[0], stderr); - return -1; + exit(EXIT_FAILURE); } outRate = 0; @@ -2998,112 +3003,124 @@ int main(int argc, const char *argv[]) radius = DEFAULT_CUSTOM_RADIUS; experimental = 0; - argi = 2; - while(argi < argc) + optind = 2; + while((opt=getopt(argc, argv, "r:f:e:s:k:w:d:c:e:i:o:xh")) != -1) { - if(strncmp(argv[argi], "-r=", 3) == 0) + switch(opt) { - outRate = strtoul(&argv[argi][3], &end, 10); + case 'r': + outRate = strtoul(optarg, &end, 10); if(end[0] != '\0' || outRate < MIN_RATE || outRate > MAX_RATE) { fprintf(stderr, "Error: Expected a value from %u to %u for '-r'.\n", MIN_RATE, MAX_RATE); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-f=", 3) == 0) - { - fftSize = strtoul(&argv[argi][3], &end, 10); + break; + + case 'f': + fftSize = strtoul(optarg, &end, 10); if(end[0] != '\0' || (fftSize&(fftSize-1)) || fftSize < MIN_FFTSIZE || fftSize > MAX_FFTSIZE) { fprintf(stderr, "Error: Expected a power-of-two value from %u to %u for '-f'.\n", MIN_FFTSIZE, MAX_FFTSIZE); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-e=", 3) == 0) - { - if(strcmp(&argv[argi][3], "on") == 0) + break; + + case 'e': + if(strcmp(optarg, "on") == 0) equalize = 1; - else if(strcmp(&argv[argi][3], "off") == 0) + else if(strcmp(optarg, "off") == 0) equalize = 0; else { fprintf(stderr, "Error: Expected 'on' or 'off' for '-e'.\n"); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-s=", 3) == 0) - { - if(strcmp(&argv[argi][3], "on") == 0) + break; + + case 's': + if(strcmp(optarg, "on") == 0) surface = 1; - else if(strcmp(&argv[argi][3], "off") == 0) + else if(strcmp(optarg, "off") == 0) surface = 0; else { fprintf(stderr, "Error: Expected 'on' or 'off' for '-s'.\n"); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-l=", 3) == 0) - { - if(strcmp(&argv[argi][3], "none") == 0) + break; + + case 'l': + if(strcmp(optarg, "none") == 0) limit = 0.0; else { - limit = strtod(&argv[argi] [3], &end); + limit = strtod(optarg, &end); if(end[0] != '\0' || limit < MIN_LIMIT || limit > MAX_LIMIT) { fprintf(stderr, "Error: Expected 'none' or a value from %.2f to %.2f for '-l'.\n", MIN_LIMIT, MAX_LIMIT); - return -1; + exit(EXIT_FAILURE); } } - } - else if(strncmp(argv[argi], "-w=", 3) == 0) - { - truncSize = strtoul(&argv[argi][3], &end, 10); + break; + + case 'w': + truncSize = strtoul(optarg, &end, 10); if(end[0] != '\0' || truncSize < MIN_TRUNCSIZE || truncSize > MAX_TRUNCSIZE || (truncSize%MOD_TRUNCSIZE)) { fprintf(stderr, "Error: Expected a value from %u to %u in multiples of %u for '-w'.\n", MIN_TRUNCSIZE, MAX_TRUNCSIZE, MOD_TRUNCSIZE); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-d=", 3) == 0) - { - if(strcmp(&argv[argi][3], "dataset") == 0) + break; + + case 'd': + if(strcmp(optarg, "dataset") == 0) model = HM_DATASET; - else if(strcmp(&argv[argi][3], "sphere") == 0) + else if(strcmp(optarg, "sphere") == 0) model = HM_SPHERE; else { fprintf(stderr, "Error: Expected 'dataset' or 'sphere' for '-d'.\n"); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-c=", 3) == 0) - { - radius = strtod(&argv[argi][3], &end); + break; + + case 'c': + radius = strtod(optarg, &end); if(end[0] != '\0' || radius < MIN_CUSTOM_RADIUS || radius > MAX_CUSTOM_RADIUS) { fprintf(stderr, "Error: Expected a value from %.2f to %.2f for '-c'.\n", MIN_CUSTOM_RADIUS, MAX_CUSTOM_RADIUS); - return -1; + exit(EXIT_FAILURE); } - } - else if(strncmp(argv[argi], "-i=", 3) == 0) - inName = &argv[argi][3]; - else if(strncmp(argv[argi], "-o=", 3) == 0) - outName = &argv[argi][3]; - else if(strcmp(argv[argi], "--experimental") == 0) + break; + + case 'i': + inName = optarg; + break; + + case 'o': + outName = optarg; + break; + + case 'x': experimental = 1; - else - { - fprintf(stderr, "Error: Invalid option '%s'.\n", argv[argi]); - return -1; + break; + + case 'h': + PrintHelp(argv[0], stdout); + exit(EXIT_SUCCESS); + + default: /* '?' */ + PrintHelp(argv[0], stderr); + exit(EXIT_FAILURE); } - argi++; } + if(!ProcessDefinition(inName, outRate, fftSize, equalize, surface, limit, truncSize, model, radius, outFormat, experimental, outName)) return -1; fprintf(stdout, "Operation completed.\n"); - return 0; + + return EXIT_SUCCESS; } -- 2.11.4.GIT