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
* POSSIBILITY OF SUCH DAMAGE. | * 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 <assert.h> | ||||
#include <err.h> | |||||
#include <errno.h> | #include <errno.h> | ||||
#if HAVE_NBTOOL_CONFIG_H | |||||
#include "compat_getopt.h" | |||||
#else | |||||
#include <getopt.h> | #include <getopt.h> | ||||
#endif | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND | |||||
#define REPLACE_GETOPT | #define REPLACE_GETOPT | ||||
#endif | |||||
#define _DIAGASSERT(x) assert(x) | |||||
#define __UNCONST(x) (char *)(x) | |||||
#ifdef REPLACE_GETOPT | #ifdef REPLACE_GETOPT | ||||
#ifdef __weak_alias | #ifdef __weak_alias | ||||
if (!*place) | if (!*place) | ||||
++optind; | ++optind; | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(illoptchar, optchar); | |||||
fprintf(stderr, illoptchar, optchar); | |||||
optopt = optchar; | optopt = optchar; | ||||
return BADCH; | return BADCH; | ||||
} | } | ||||
if (++optind >= nargc) { /* no arg */ | if (++optind >= nargc) { /* no arg */ | ||||
place = EMSG; | place = EMSG; | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(recargchar, optchar); | |||||
fprintf(stderr, recargchar, optchar); | |||||
optopt = optchar; | optopt = optchar; | ||||
return BADARG; | return BADARG; | ||||
} else /* white space */ | } else /* white space */ | ||||
if (++optind >= nargc) { /* no arg */ | if (++optind >= nargc) { /* no arg */ | ||||
place = EMSG; | place = EMSG; | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(recargchar, optchar); | |||||
fprintf(stderr, recargchar, optchar); | |||||
optopt = optchar; | optopt = optchar; | ||||
return BADARG; | return BADARG; | ||||
} else | } else | ||||
if (ambiguous) { | if (ambiguous) { | ||||
/* ambiguous abbreviation */ | /* ambiguous abbreviation */ | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(ambig, (int)current_argv_len, | |||||
fprintf(stderr, ambig, (int)current_argv_len, | |||||
current_argv); | current_argv); | ||||
optopt = 0; | optopt = 0; | ||||
return BADCH; | return BADCH; | ||||
if (long_options[match].has_arg == no_argument | if (long_options[match].has_arg == no_argument | ||||
&& has_equal) { | && has_equal) { | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(noarg, (int)current_argv_len, | |||||
fprintf(stderr, noarg, (int)current_argv_len, | |||||
current_argv); | current_argv); | ||||
/* | /* | ||||
* XXX: GNU sets optopt to val regardless of | * XXX: GNU sets optopt to val regardless of | ||||
* indicates no error should be generated | * indicates no error should be generated | ||||
*/ | */ | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(recargstring, current_argv); | |||||
fprintf(stderr, recargstring, current_argv); | |||||
/* | /* | ||||
* XXX: GNU sets optopt to val regardless | * XXX: GNU sets optopt to val regardless | ||||
* of flag | * of flag | ||||
} | } | ||||
} else { /* unknown option */ | } else { /* unknown option */ | ||||
if (PRINT_ERROR) | if (PRINT_ERROR) | ||||
warnx(illoptstring, current_argv); | |||||
fprintf(stderr, illoptstring, current_argv); | |||||
optopt = 0; | optopt = 0; | ||||
return BADCH; | return BADCH; | ||||
} | } |
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#ifdef HAVE_GETOPT_H | |||||
#include <getopt.h> | #include <getopt.h> | ||||
#endif | |||||
#include <time.h> | #include <time.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
printf("eSpeak text-to-speech: %s Data at: %s\n", version, path_data); | 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) | int main(int argc, char **argv) | ||||
{ | { | ||||
static struct option long_options[] = { | static struct option long_options[] = { | ||||
devicename[0] = 0; | devicename[0] = 0; | ||||
option_punctlist[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) { | while (true) { | ||||
c = getopt_long(argc, argv, "a:b:d:f:g:hk:l:mp:qs:v:w:xXz", | c = getopt_long(argc, argv, "a:b:d:f:g:hk:l:mp:qs:v:w:xXz", | ||||
long_options, &option_index); | long_options, &option_index); | ||||
if (c == -1) | if (c == -1) | ||||
break; | break; | ||||
optarg2 = optarg; | optarg2 = optarg; | ||||
#endif | |||||
switch (c) | switch (c) | ||||
{ | { |
/* 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 |
#endif | #endif | ||||
#endif | #endif | ||||
#ifdef HAVE_GETOPT_H | |||||
#include <getopt.h> | #include <getopt.h> | ||||
#endif | |||||
#include <time.h> | #include <time.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#include <locale.h> | #include <locale.h> | ||||
return finished; | 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) | int main(int argc, char **argv) | ||||
{ | { | ||||
static struct option long_options[] = { | static struct option long_options[] = { | ||||
option_multibyte = espeakCHARS_AUTO; | option_multibyte = espeakCHARS_AUTO; | ||||
f_trans = stdout; | 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) { | 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 | 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); | long_options, &option_index); | ||||
if (c == -1) | if (c == -1) | ||||
break; | break; | ||||
optarg2 = optarg; | optarg2 = optarg; | ||||
#endif | |||||
switch (c) | switch (c) | ||||
{ | { |
</Link> | </Link> | ||||
</ItemDefinitionGroup> | </ItemDefinitionGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClCompile Include="..\compat\getopt.c" /> | |||||
<ClCompile Include="..\espeak-ng.c" /> | <ClCompile Include="..\espeak-ng.c" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClInclude Include="..\include\compat\getopt.h" /> | |||||
<ClInclude Include="config.h" /> | <ClInclude Include="config.h" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> |
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | <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> | <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | ||||
</Filter> | </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> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClCompile Include="..\espeak-ng.c"> | <ClCompile Include="..\espeak-ng.c"> | ||||
<Filter>Source Files</Filter> | <Filter>Source Files</Filter> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\compat\getopt.c"> | |||||
<Filter>Source Files\compat</Filter> | |||||
</ClCompile> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ClInclude Include="config.h"> | <ClInclude Include="config.h"> | ||||
<Filter>Header Files</Filter> | <Filter>Header Files</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\include\compat\getopt.h"> | |||||
<Filter>Header Files\compat</Filter> | |||||
</ClInclude> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |