Logo Search packages:      
Sourcecode: speech-tools version File versions  Download package

cmd_line.cc

/*************************************************************************/
/*                                                                       */
/*                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 argment definitions April 97           */
/*                                                                       */
/*=======================================================================*/
#include <stdlib.h>
#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 argments
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 = next(p))
    {
      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, (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));
}


Generated by  Doxygen 1.6.0   Back to index