515 lines
16 KiB
C++
515 lines
16 KiB
C++
/*************************************************************************/
|
|
/* */
|
|
/* Centre for Speech Technology Research */
|
|
/* University of Edinburgh, UK */
|
|
/* Copyright (c) 1994,1995,1996 */
|
|
/* All Rights Reserved. */
|
|
/* */
|
|
/* Permission is hereby granted, free of charge, to use and distribute */
|
|
/* this software and its documentation without restriction, including */
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
/* distribute, sublicense, and/or sell copies of this work, and to */
|
|
/* permit persons to whom this work is furnished to do so, subject to */
|
|
/* the following conditions: */
|
|
/* 1. The code must retain the above copyright notice, this list of */
|
|
/* conditions and the following disclaimer. */
|
|
/* 2. Any modifications must be clearly marked as such. */
|
|
/* 3. Original authors' names are not deleted. */
|
|
/* 4. The authors' names are not used to endorse or promote products */
|
|
/* derived from this software without specific prior written */
|
|
/* permission. */
|
|
/* */
|
|
/* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
|
|
/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
|
|
/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
|
|
/* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
|
|
/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
|
|
/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
|
|
/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
|
|
/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
|
|
/* THIS SOFTWARE. */
|
|
/* */
|
|
/*************************************************************************/
|
|
/* Author : Paul Taylor */
|
|
/* Date : October 1994 */
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Command Line Utilities */
|
|
/* */
|
|
/* awb merged the help usage and argument definitions April 97 */
|
|
/* */
|
|
/*=======================================================================*/
|
|
#include <cstdlib>
|
|
#include "EST_unix.h"
|
|
#include "EST_String.h"
|
|
#include "EST_io_aux.h"
|
|
#include "EST_Token.h"
|
|
#include "EST_cutils.h"
|
|
#include "EST_TList.h"
|
|
#include "EST_string_aux.h"
|
|
#include "EST_cmd_line.h"
|
|
#include "EST_Pathname.h"
|
|
#include "EST_Features.h"
|
|
|
|
// This is reset by the command line options functions to argv[0]
|
|
EST_String est_progname = "ESTtools";
|
|
|
|
static int valid_option(const EST_Option &option,const char *arg,
|
|
EST_String &sarg);
|
|
static void standard_options(int argc, char **argv, const EST_String &usage);
|
|
static void arg_error(const EST_String &progname, const EST_String &message);
|
|
static void parse_usage(const EST_String &progname, const EST_String &usage,
|
|
EST_Option &options, EST_Option &al);
|
|
static void output_man_options(const EST_String &usage);
|
|
static void output_sgml_options(const EST_String &usage);
|
|
static void output_sgml_synopsis(char **argv, const EST_String &usage);
|
|
|
|
int init_lib_ops(EST_Option &al, EST_Option &op)
|
|
{
|
|
char *envname;
|
|
|
|
// read environment variable operations file if specified
|
|
if ((al.val("-N", 0) != "true") &&
|
|
((envname = getenv("IA_OP_FILE")) != 0))
|
|
if (op.load(getenv("IA_OP_FILE")) != read_ok)
|
|
exit (1);
|
|
|
|
// read command line operations file if specified
|
|
if (al.val("-c", 0) != "")
|
|
if (op.load(al.val("-c")) != read_ok)
|
|
exit (1);
|
|
|
|
// override operations with command line options
|
|
override_lib_ops(op, al);
|
|
|
|
if (al.val("-ops", 0) == "true") // print options if required
|
|
cout << op;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// An attempt to integrate help, usage and argument definitions in
|
|
// one string (seems to work)
|
|
// Still to do:
|
|
// * adding arbitrary "-" at end of files (do we need that?)
|
|
// dealing with environment var specification of extra options
|
|
// override options function (maybe no longer needed)
|
|
// list of named values for argument
|
|
// Way to identify mandatory arguments
|
|
int parse_command_line(int argc,
|
|
char *argv[],
|
|
const EST_String &usage,
|
|
EST_StrList &files,
|
|
EST_Option &al, int make_stdio)
|
|
{
|
|
// Parse the command line arguments returning them in a normalised
|
|
// form in al, and files in files.
|
|
int i;
|
|
EST_Option options;
|
|
EST_String arg;
|
|
(void)make_stdio;
|
|
|
|
// help, version, man_options are always supported
|
|
standard_options(argc,argv,usage);
|
|
|
|
// Find valid options, arguments and defaults
|
|
// sets defaults in al
|
|
est_progname = argv[0];
|
|
parse_usage(argv[0],usage,options,al);
|
|
|
|
for (i=1; i < argc; i++)
|
|
{
|
|
if (!EST_String(argv[i]).contains("-",0)) // its a filename
|
|
files.append(argv[i]);
|
|
else if (streq(argv[i],"-")) // single "-" denotes stdin/out
|
|
files.append("-");
|
|
else if (!valid_option(options,argv[i],arg))
|
|
{
|
|
arg_error(argv[0],
|
|
EST_String(": Unknown option \"")+argv[i]+"\"\n");
|
|
}
|
|
else // valid option, check args
|
|
{
|
|
if (options.val(arg) == "true") // no argument required
|
|
al.add_item(arg, "true");
|
|
else if (options.val(arg) == "<int>")
|
|
{
|
|
if (i+1 == argc)
|
|
arg_error(argv[0],
|
|
EST_String(": missing int argument for \"")+
|
|
arg+"\"\n");
|
|
i++;
|
|
if (!EST_String(argv[i]).matches(RXint))
|
|
arg_error(argv[0],
|
|
EST_String(": argument for \"")+
|
|
arg+"\" not an int\n");
|
|
al.add_item(arg,argv[i]);
|
|
}
|
|
else if ((options.val(arg) == "<float>") ||
|
|
(options.val(arg) == "<double>"))
|
|
{
|
|
if (i+1 == argc)
|
|
arg_error(argv[0],
|
|
EST_String(": missing float argument for \"")+
|
|
arg+"\"\n");
|
|
i++;
|
|
if (!EST_String(argv[i]).matches(RXdouble))
|
|
arg_error(argv[0],
|
|
EST_String(": argument for \"")+
|
|
arg+"\" not a float\n");
|
|
al.add_item(arg,argv[i]);
|
|
}
|
|
else if (options.val(arg) == "<string>")
|
|
{
|
|
if (i+1 == argc)
|
|
arg_error(argv[0],
|
|
EST_String(": missing string argument for \"")+
|
|
arg+"\"\n");
|
|
i++;
|
|
al.add_item(arg,argv[i]);
|
|
}
|
|
else if (options.val(arg) == "<ofile>")
|
|
{
|
|
if (i+1 == argc)
|
|
arg_error(argv[0],
|
|
EST_String(": missing ifile argument for \"")+
|
|
arg+"\"\n");
|
|
i++;
|
|
if (writable_file(argv[i]) == TRUE)
|
|
al.add_item(arg,argv[i]);
|
|
else
|
|
arg_error(argv[0],
|
|
EST_String(": output file not accessible \"")+
|
|
argv[i]+"\"\n");
|
|
}
|
|
else if (options.val(arg) == "<ifile>")
|
|
{
|
|
if (i+1 == argc)
|
|
arg_error(argv[0],
|
|
EST_String(": missing ifile argument for \"")+
|
|
arg+"\"\n");
|
|
i++;
|
|
if (readable_file(argv[i]) == TRUE)
|
|
al.add_item(arg,argv[i]);
|
|
else
|
|
arg_error(argv[0],
|
|
EST_String(": input file not accessible \"")+
|
|
argv[i]+"\"\n");
|
|
|
|
}
|
|
else if (options.val(arg) == "<star>")
|
|
{
|
|
al.add_item(arg,EST_String(argv[i]).after(arg));
|
|
}
|
|
// else string list
|
|
else
|
|
{
|
|
arg_error(argv[0],
|
|
EST_String(": unknown argument type \"")+
|
|
options.val(argv[i])+"\" (misparsed usage string)\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (files.length() == 0)
|
|
files.append("-");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int valid_option(const EST_Option &options,const char *arg,
|
|
EST_String &sarg)
|
|
{
|
|
// Checks to see arg is declared as an option.
|
|
// This would be trivial were it not for options containing *
|
|
// The actual arg name is put in sarg
|
|
EST_Litem *p;
|
|
|
|
for (p = options.list.head(); p != 0; p = p->next())
|
|
{
|
|
if (options.key(p) == arg)
|
|
{
|
|
sarg = arg;
|
|
return TRUE;
|
|
}
|
|
else if ((options.val(p) == "<star>") &&
|
|
(EST_String(arg).contains(options.key(p), 0)))
|
|
{
|
|
sarg = options.key(p);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void parse_usage(const EST_String &progname, const EST_String &usage,
|
|
EST_Option &options, EST_Option &al)
|
|
{
|
|
// Extract option definitions from usage and put them in options
|
|
// If defaults are specified add them al
|
|
EST_TokenStream ts;
|
|
EST_Token t;
|
|
|
|
ts.open_string(usage);
|
|
ts.set_SingleCharSymbols("{}[]|");
|
|
ts.set_PunctuationSymbols("");
|
|
ts.set_PrePunctuationSymbols("");
|
|
|
|
while (!ts.eof())
|
|
{
|
|
t = ts.get();
|
|
if ((t.string().contains("-",0)) &&
|
|
(t.whitespace().contains("\n")))
|
|
{ // An argument
|
|
if ((ts.peek().string() == "<string>") ||
|
|
(ts.peek().string() == "<float>") ||
|
|
(ts.peek().string() == "<double>") ||
|
|
(ts.peek().string() == "<ifile>") ||
|
|
(ts.peek().string() == "<ofile>") ||
|
|
(ts.peek().string() == "<int>"))
|
|
{
|
|
options.add_item(t.string(),ts.get().string());
|
|
if (ts.peek().string() == "{") // a default is given
|
|
{
|
|
ts.get();
|
|
al.add_item(t.string(),ts.get().string());
|
|
if (ts.get() != "}")
|
|
arg_error(progname,
|
|
EST_String(": malformed default value for \"")+
|
|
t.string()+"\" (missing closing brace)\n");
|
|
}
|
|
}
|
|
else if (t.string().contains("*"))
|
|
options.add_item(t.string().before("*"),"<star>");
|
|
// else check for explicit list of names
|
|
else
|
|
options.add_item(t.string(),"true"); // simple argument
|
|
}
|
|
}
|
|
}
|
|
|
|
static void arg_error(const EST_String &progname, const EST_String &message)
|
|
{
|
|
// Output message and pointer to more help then exit
|
|
cerr << progname << message;
|
|
cerr << "Type -h for help on options.\n";
|
|
exit(-1);
|
|
}
|
|
|
|
static void standard_options(int argc, char **argv, const EST_String &usage)
|
|
{
|
|
// A number of options are always supported
|
|
int i;
|
|
|
|
for (i=1; i < argc; i++)
|
|
{
|
|
if (streq(argv[i],"-man_options"))
|
|
{
|
|
output_man_options(usage);
|
|
exit(0);
|
|
}
|
|
if (streq(argv[i],"-sgml_options"))
|
|
{
|
|
output_sgml_options(usage);
|
|
exit(0);
|
|
}
|
|
if (streq(argv[i],"-sgml_synopsis"))
|
|
{
|
|
output_sgml_synopsis(argv, usage);
|
|
exit(0);
|
|
}
|
|
if ((streq(argv[i],"-h")) ||
|
|
(streq(argv[i],"-help")) ||
|
|
(streq(argv[i],"-?")) ||
|
|
(streq(argv[i],"--help")))
|
|
{
|
|
EST_Pathname full(argv[0]);
|
|
cout << "Usage: " << full.filename() << " " << usage << endl;
|
|
exit(0);
|
|
}
|
|
if (((streq(argv[i],"-version")) ||
|
|
(streq(argv[i],"--version")))&&
|
|
(!usage.contains("\n-v")))
|
|
{
|
|
cout << argv[0] << ": " << est_name << " v" << est_tools_version << endl;
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void output_man_options(const EST_String &usage)
|
|
{
|
|
EST_TokenStream ts;
|
|
EST_Token t;
|
|
int in_options = FALSE;
|
|
|
|
ts.open_string(usage);
|
|
ts.set_SingleCharSymbols("{}[]|");
|
|
ts.set_PunctuationSymbols("");
|
|
ts.set_PrePunctuationSymbols("");
|
|
|
|
while (!ts.eof())
|
|
{
|
|
t = ts.get();
|
|
if ((t.string().contains("-",0)) &&
|
|
(t.whitespace().contains("\n")))
|
|
{ // An argument
|
|
fprintf(stdout,"\n.TP 8\n.BI \"%s \" ",(const char *)t.string());
|
|
if ((ts.peek().string() == "<string>") ||
|
|
(ts.peek().string() == "<float>") ||
|
|
(ts.peek().string() == "<double>") ||
|
|
(ts.peek().string() == "<int>"))
|
|
fprintf(stdout,"%s",(const char *)ts.get().string());
|
|
if ((ts.peek().string() == "{"))
|
|
{ // a default value
|
|
ts.get();
|
|
fprintf(stdout," \" {%s}\"",(const char *)ts.get().string());
|
|
ts.get();
|
|
}
|
|
if (!ts.peek().whitespace().contains("\n"))
|
|
fprintf(stdout,"\n");
|
|
in_options = TRUE;
|
|
}
|
|
else if (in_options)
|
|
{
|
|
if (t.whitespace().contains("\n"))
|
|
fprintf(stdout,"\n");
|
|
fprintf(stdout,"%s ",(const char *)t.string());
|
|
}
|
|
}
|
|
if (in_options)
|
|
fprintf(stdout,"\n");
|
|
|
|
|
|
}
|
|
|
|
static void output_sgml_options(const EST_String &usage)
|
|
{
|
|
EST_TokenStream ts;
|
|
EST_Token t;
|
|
EST_String atype;
|
|
int in_options = FALSE;
|
|
|
|
ts.open_string(usage);
|
|
ts.set_SingleCharSymbols("{}[]|");
|
|
ts.set_PunctuationSymbols("");
|
|
ts.set_PrePunctuationSymbols("");
|
|
|
|
fprintf(stdout,"<variablelist>\n");
|
|
|
|
while (!ts.eof())
|
|
{
|
|
t = ts.get();
|
|
if ((t.string().contains("-",0)) &&
|
|
(t.whitespace().contains("\n")))
|
|
{ // An argument
|
|
if (in_options)
|
|
fprintf(stdout,"\n</PARA></LISTITEM>\n</varlistentry>\n\n");
|
|
fprintf(stdout,"<varlistentry><term>%s</term>\n<LISTITEM><PARA>\n", (const char *)t.string());
|
|
if ((ts.peek().string() == "<string>") ||
|
|
(ts.peek().string() == "<float>") ||
|
|
(ts.peek().string() == "<ifile>") ||
|
|
(ts.peek().string() == "<ofile>") ||
|
|
(ts.peek().string() == "<double>") ||
|
|
(ts.peek().string() == "<int>"))
|
|
{ // must strip of the angle brackets to make SGML
|
|
atype = ts.get().string();
|
|
atype.gsub("<","");
|
|
atype.gsub(">","");
|
|
fprintf(stdout,"<replaceable>%s</replaceable>\n",
|
|
(const char *) atype);
|
|
}
|
|
if ((ts.peek().string() == "{"))
|
|
{ // a default value
|
|
ts.get();
|
|
fprintf(stdout," \" {%s}\"",(const char *)ts.get().string());
|
|
ts.get();
|
|
}
|
|
if (!ts.peek().whitespace().contains("\n"))
|
|
fprintf(stdout,"\n");
|
|
in_options = TRUE;
|
|
}
|
|
else if (in_options)
|
|
{
|
|
if (t.whitespace().contains("\n"))
|
|
fprintf(stdout,"\n");
|
|
fprintf(stdout,"%s ",(const char *)t.string());
|
|
}
|
|
}
|
|
if (in_options)
|
|
fprintf(stdout,"</PARA></LISTITEM>\n</varlistentry>\n</variablelist>\n");
|
|
|
|
}
|
|
|
|
static void output_sgml_synopsis(char **argv, const EST_String &usage)
|
|
{
|
|
EST_TokenStream ts;
|
|
EST_Token t;
|
|
EST_String atype;
|
|
int in_options = FALSE;
|
|
|
|
ts.open_string(usage);
|
|
ts.set_SingleCharSymbols("{}[]|");
|
|
ts.set_PunctuationSymbols("");
|
|
ts.set_PrePunctuationSymbols("");
|
|
|
|
EST_Pathname full(argv[0]);
|
|
|
|
fprintf(stdout,"<cmdsynopsis><command>%s</command>",
|
|
(const char *)full.filename());
|
|
|
|
fprintf(stdout,"%s",(const char *)ts.get_upto_eoln().string());
|
|
|
|
while (!ts.eof())
|
|
{
|
|
t = ts.get();
|
|
if ((t.string().contains("-",0)) &&
|
|
(t.whitespace().contains("\n")))
|
|
{ // An argument
|
|
if (in_options)
|
|
fprintf(stdout,"</arg>\n");
|
|
fprintf(stdout,"<arg>%s ", (const char *)t.string());
|
|
if ((ts.peek().string() == "<string>") ||
|
|
(ts.peek().string() == "<float>") ||
|
|
(ts.peek().string() == "<ifile>") ||
|
|
(ts.peek().string() == "<ofile>") ||
|
|
(ts.peek().string() == "<double>") ||
|
|
(ts.peek().string() == "<int>"))
|
|
{ // must strip of the angle brackets to make SGML
|
|
atype = ts.get().string();
|
|
atype.gsub("<","");
|
|
atype.gsub(">","");
|
|
fprintf(stdout,"<replaceable>%s</replaceable>",
|
|
(const char *) atype);
|
|
}
|
|
if ((ts.peek().string() == "{"))
|
|
{ // a default value
|
|
ts.get();
|
|
fprintf(stdout," \" {%s}\"",(const char *)ts.get().string());
|
|
ts.get();
|
|
}
|
|
in_options = TRUE;
|
|
}
|
|
}
|
|
fprintf(stdout,"</arg>\n</cmdsynopsis>\n");
|
|
}
|
|
|
|
EST_String options_general(void)
|
|
{
|
|
// The standard waveform input options
|
|
return
|
|
EST_String("")+
|
|
"-o <ofile> output file" +
|
|
"-otype <string> output file type\n";
|
|
}
|
|
|
|
void option_override(EST_Features &op, EST_Option al,
|
|
const EST_String &option, const EST_String &arg)
|
|
{
|
|
if (al.present(arg))
|
|
op.set(option, al.val(arg));
|
|
}
|
|
|