This makes the espeak-ng.c and speak-ng.c source code easier to read and maintain. It also addresses bugs in command-line argument parsing with the espeak implementation, for example it treats `--compile-phonemes` as `--compile` due to an argument matching bug.master
@@ -29,29 +29,19 @@ | |||
* POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#if HAVE_NBTOOL_CONFIG_H | |||
#include "nbtool_config.h" | |||
#endif | |||
#include <sys/cdefs.h> | |||
__RCSID("$NetBSD: getopt_long.c,v 1.27 2015/09/01 19:39:57 kamil Exp $"); | |||
#include "namespace.h" | |||
#include "config.h" | |||
#include <assert.h> | |||
#include <err.h> | |||
#include <errno.h> | |||
#if HAVE_NBTOOL_CONFIG_H | |||
#include "compat_getopt.h" | |||
#else | |||
#include <getopt.h> | |||
#endif | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND | |||
#define REPLACE_GETOPT | |||
#endif | |||
#define _DIAGASSERT(x) assert(x) | |||
#define __UNCONST(x) (char *)(x) | |||
#ifdef REPLACE_GETOPT | |||
#ifdef __weak_alias | |||
@@ -251,7 +241,7 @@ start: | |||
if (!*place) | |||
++optind; | |||
if (PRINT_ERROR) | |||
warnx(illoptchar, optchar); | |||
fprintf(stderr, illoptchar, optchar); | |||
optopt = optchar; | |||
return BADCH; | |||
} | |||
@@ -263,7 +253,7 @@ start: | |||
if (++optind >= nargc) { /* no arg */ | |||
place = EMSG; | |||
if (PRINT_ERROR) | |||
warnx(recargchar, optchar); | |||
fprintf(stderr, recargchar, optchar); | |||
optopt = optchar; | |||
return BADARG; | |||
} else /* white space */ | |||
@@ -286,7 +276,7 @@ start: | |||
if (++optind >= nargc) { /* no arg */ | |||
place = EMSG; | |||
if (PRINT_ERROR) | |||
warnx(recargchar, optchar); | |||
fprintf(stderr, recargchar, optchar); | |||
optopt = optchar; | |||
return BADARG; | |||
} else | |||
@@ -407,7 +397,7 @@ getopt_long(int nargc, char * const *nargv, const char *options, | |||
if (ambiguous) { | |||
/* ambiguous abbreviation */ | |||
if (PRINT_ERROR) | |||
warnx(ambig, (int)current_argv_len, | |||
fprintf(stderr, ambig, (int)current_argv_len, | |||
current_argv); | |||
optopt = 0; | |||
return BADCH; | |||
@@ -416,7 +406,7 @@ getopt_long(int nargc, char * const *nargv, const char *options, | |||
if (long_options[match].has_arg == no_argument | |||
&& has_equal) { | |||
if (PRINT_ERROR) | |||
warnx(noarg, (int)current_argv_len, | |||
fprintf(stderr, noarg, (int)current_argv_len, | |||
current_argv); | |||
/* | |||
* XXX: GNU sets optopt to val regardless of | |||
@@ -448,7 +438,7 @@ getopt_long(int nargc, char * const *nargv, const char *options, | |||
* indicates no error should be generated | |||
*/ | |||
if (PRINT_ERROR) | |||
warnx(recargstring, current_argv); | |||
fprintf(stderr, recargstring, current_argv); | |||
/* | |||
* XXX: GNU sets optopt to val regardless | |||
* of flag | |||
@@ -462,7 +452,7 @@ getopt_long(int nargc, char * const *nargv, const char *options, | |||
} | |||
} else { /* unknown option */ | |||
if (PRINT_ERROR) | |||
warnx(illoptstring, current_argv); | |||
fprintf(stderr, illoptstring, current_argv); | |||
optopt = 0; | |||
return BADCH; | |||
} |
@@ -25,9 +25,7 @@ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <ctype.h> | |||
#ifdef HAVE_GETOPT_H | |||
#include <getopt.h> | |||
#endif | |||
#include <time.h> | |||
#include <sys/stat.h> | |||
@@ -296,22 +294,6 @@ static void PrintVersion() | |||
printf("eSpeak text-to-speech: %s Data at: %s\n", version, path_data); | |||
} | |||
#ifndef HAVE_GETOPT_H | |||
struct option { | |||
char *name; | |||
int has_arg; | |||
int *flag; | |||
int val; | |||
}; | |||
int optind; | |||
static int optional_argument; | |||
static const char *arg_opts = "abdfgklpsvw"; // which options have arguments | |||
static char *opt_string = ""; | |||
#define no_argument 0 | |||
#define required_argument 1 | |||
#define optional_argument 2 | |||
#endif | |||
int main(int argc, char **argv) | |||
{ | |||
static struct option long_options[] = { | |||
@@ -375,51 +357,6 @@ int main(int argc, char **argv) | |||
devicename[0] = 0; | |||
option_punctlist[0] = 0; | |||
#ifndef HAVE_GETOPT_H | |||
optind = 1; | |||
opt_string = ""; | |||
while (optind < argc) { | |||
int len; | |||
char *p; | |||
if ((c = *opt_string) == 0) { | |||
opt_string = argv[optind]; | |||
if (opt_string[0] != '-') | |||
break; | |||
optind++; | |||
opt_string++; | |||
c = *opt_string; | |||
} | |||
opt_string++; | |||
p = optarg2 = opt_string; | |||
if (c == '-') { | |||
if (p[0] == 0) | |||
break; // -- means don't interpret further - as commands | |||
opt_string = ""; | |||
for (ix = 0;; ix++) { | |||
if (long_options[ix].name == 0) | |||
break; | |||
len = strlen(long_options[ix].name); | |||
if (memcmp(long_options[ix].name, p, len) == 0) { | |||
c = long_options[ix].val; | |||
optarg2 = NULL; | |||
if ((long_options[ix].has_arg != 0) && (p[len] == '=')) | |||
optarg2 = &p[len+1]; | |||
break; | |||
} | |||
} | |||
} else if (strchr(arg_opts, c) != NULL) { | |||
opt_string = ""; | |||
if (optarg2[0] == 0) { | |||
// the option's value is in the next argument | |||
optarg2 = argv[optind++]; | |||
} | |||
} | |||
#else | |||
while (true) { | |||
c = getopt_long(argc, argv, "a:b:d:f:g:hk:l:mp:qs:v:w:xXz", | |||
long_options, &option_index); | |||
@@ -428,7 +365,6 @@ int main(int argc, char **argv) | |||
if (c == -1) | |||
break; | |||
optarg2 = optarg; | |||
#endif | |||
switch (c) | |||
{ |
@@ -0,0 +1,49 @@ | |||
/* Compatibility shim for <getopt.h> | |||
* | |||
* Copyright (C) 2006 to 2013 by Jonathan Duddington | |||
* email: [email protected] | |||
* Copyright (C) 2016 Reece H. Dunn | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program; if not, see: <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef GETOPT_H_COMPAT_SHIM | |||
#define GETOPT_H_COMPAT_SHIM | |||
#if defined(HAVE_GETOPT_H) | |||
#pragma GCC system_header // Silence "warning: #include_next is a GCC extension" | |||
#include_next <getopt.h> | |||
#else | |||
struct option { | |||
char *name; | |||
int has_arg; | |||
int *flag; | |||
int val; | |||
}; | |||
extern int optind; | |||
extern char *optarg; | |||
#define no_argument 0 | |||
#define required_argument 1 | |||
#define optional_argument 2 | |||
int | |||
getopt_long(int nargc, char * const *nargv, const char *options, | |||
const struct option *long_options, int *idx); | |||
#endif | |||
#endif |
@@ -40,9 +40,7 @@ | |||
#endif | |||
#endif | |||
#ifdef HAVE_GETOPT_H | |||
#include <getopt.h> | |||
#endif | |||
#include <time.h> | |||
#include <signal.h> | |||
#include <locale.h> | |||
@@ -286,22 +284,6 @@ static int WavegenFile(void) | |||
return finished; | |||
} | |||
#ifndef HAVE_GETOPT_H | |||
struct option { | |||
char *name; | |||
int has_arg; | |||
int *flag; | |||
int val; | |||
}; | |||
int optind; | |||
static int optional_argument; | |||
static const char *arg_opts = "abfgklpsvw"; // which options have arguments | |||
static char *opt_string = ""; | |||
#define no_argument 0 | |||
#define required_argument 1 | |||
#define optional_argument 2 | |||
#endif | |||
int main(int argc, char **argv) | |||
{ | |||
static struct option long_options[] = { | |||
@@ -361,51 +343,6 @@ int main(int argc, char **argv) | |||
option_multibyte = espeakCHARS_AUTO; | |||
f_trans = stdout; | |||
#ifndef HAVE_GETOPT_H | |||
optind = 1; | |||
opt_string = ""; | |||
while (optind < argc) { | |||
int len; | |||
char *p; | |||
if ((c = *opt_string) == 0) { | |||
opt_string = argv[optind]; | |||
if (opt_string[0] != '-') | |||
break; | |||
optind++; | |||
opt_string++; | |||
c = *opt_string; | |||
} | |||
opt_string++; | |||
p = optarg2 = opt_string; | |||
if (c == '-') { | |||
if (p[0] == 0) | |||
break; // -- means don't interpret further - as commands | |||
opt_string = ""; | |||
for (ix = 0;; ix++) { | |||
if (long_options[ix].name == 0) | |||
break; | |||
len = strlen(long_options[ix].name); | |||
if (memcmp(long_options[ix].name, p, len) == 0) { | |||
c = long_options[ix].val; | |||
optarg2 = NULL; | |||
if ((long_options[ix].has_arg != 0) && (p[len] == '=')) | |||
optarg2 = &p[len+1]; | |||
break; | |||
} | |||
} | |||
} else if (strchr(arg_opts, c) != NULL) { | |||
opt_string = ""; | |||
if (optarg2[0] == 0) { | |||
// the option's value is in the next argument | |||
optarg2 = argv[optind++]; | |||
} | |||
} | |||
#else | |||
while (true) { | |||
c = getopt_long(argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value | |||
long_options, &option_index); | |||
@@ -414,7 +351,6 @@ int main(int argc, char **argv) | |||
if (c == -1) | |||
break; | |||
optarg2 = optarg; | |||
#endif | |||
switch (c) | |||
{ |
@@ -150,9 +150,11 @@ | |||
</Link> | |||
</ItemDefinitionGroup> | |||
<ItemGroup> | |||
<ClCompile Include="..\compat\getopt.c" /> | |||
<ClCompile Include="..\espeak-ng.c" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ClInclude Include="..\include\compat\getopt.h" /> | |||
<ClInclude Include="config.h" /> | |||
</ItemGroup> | |||
<ItemGroup> |
@@ -13,15 +13,27 @@ | |||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | |||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | |||
</Filter> | |||
<Filter Include="Header Files\compat"> | |||
<UniqueIdentifier>{c530f203-dd49-4aa0-a7a3-5116f781f03c}</UniqueIdentifier> | |||
</Filter> | |||
<Filter Include="Source Files\compat"> | |||
<UniqueIdentifier>{2ab8716c-709b-4284-9dc7-ec9610d37eab}</UniqueIdentifier> | |||
</Filter> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ClCompile Include="..\espeak-ng.c"> | |||
<Filter>Source Files</Filter> | |||
</ClCompile> | |||
<ClCompile Include="..\compat\getopt.c"> | |||
<Filter>Source Files\compat</Filter> | |||
</ClCompile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ClInclude Include="config.h"> | |||
<Filter>Header Files</Filter> | |||
</ClInclude> | |||
<ClInclude Include="..\include\compat\getopt.h"> | |||
<Filter>Header Files\compat</Filter> | |||
</ClInclude> | |||
</ItemGroup> | |||
</Project> |