/*************************************************************************/ /* */ /* 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 #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) == "") { 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) == "") || (options.val(arg) == "")) { 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) == "") { 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) == "") { 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) == "") { 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) == "") { 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) == "") && (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() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "")) { 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("*"),""); // 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() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "")) 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,"\n"); while (!ts.eof()) { t = ts.get(); if ((t.string().contains("-",0)) && (t.whitespace().contains("\n"))) { // An argument if (in_options) fprintf(stdout,"\n\n\n\n"); fprintf(stdout,"%s\n\n", (const char *)t.string()); if ((ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "")) { // must strip of the angle brackets to make SGML atype = ts.get().string(); atype.gsub("<",""); atype.gsub(">",""); fprintf(stdout,"%s\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,"\n\n\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,"%s", (const char *)full.filename()); fprintf(stdout, (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,"\n"); fprintf(stdout,"%s ", (const char *)t.string()); if ((ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "") || (ts.peek().string() == "")) { // must strip of the angle brackets to make SGML atype = ts.get().string(); atype.gsub("<",""); atype.gsub(">",""); fprintf(stdout,"%s", (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,"\n\n"); } EST_String options_general(void) { // The standard waveform input options return EST_String("")+ "-o output file" + "-otype 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)); }