Edinburgh Speech Tools  2.1-release
cmd_line.cc
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1994,1995,1996 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Paul Taylor */
34 /* Date : October 1994 */
35 /*-----------------------------------------------------------------------*/
36 /* Command Line Utilities */
37 /* */
38 /* awb merged the help usage and argument definitions April 97 */
39 /* */
40 /*=======================================================================*/
41 #include <cstdlib>
42 #include "EST_unix.h"
43 #include "EST_String.h"
44 #include "EST_io_aux.h"
45 #include "EST_Token.h"
46 #include "EST_cutils.h"
47 #include "EST_TList.h"
48 #include "EST_string_aux.h"
49 #include "EST_cmd_line.h"
50 #include "EST_Pathname.h"
51 #include "EST_Features.h"
52 
53 #include <iostream>
54 using namespace std;
55 
56 // This is reset by the command line options functions to argv[0]
57 EST_String est_progname = "ESTtools";
58 
59 static int valid_option(const EST_Option &option,const char *arg,
60  EST_String &sarg);
61 static void standard_options(int argc, char **argv, const EST_String &usage);
62 static void arg_error(const EST_String &progname, const EST_String &message);
63 static void parse_usage(const EST_String &progname, const EST_String &usage,
64  EST_Option &options, EST_Option &al);
65 static void output_man_options(const EST_String &usage);
66 static void output_sgml_options(const EST_String &usage);
67 static void output_sgml_synopsis(char **argv, const EST_String &usage);
68 
70 {
71  char *envname;
72 
73  // read environment variable operations file if specified
74  if ((al.val("-N", 0) != "true") &&
75  ((envname = getenv("IA_OP_FILE")) != 0))
76  if (op.load(getenv("IA_OP_FILE")) != read_ok)
77  exit (1);
78 
79  // read command line operations file if specified
80  if (al.val("-c", 0) != "")
81  if (op.load(al.val("-c")) != read_ok)
82  exit (1);
83 
84  // override operations with command line options
85  override_lib_ops(op, al);
86 
87  if (al.val("-ops", 0) == "true") // print options if required
88  cout << op;
89 
90  return 0;
91 }
92 
93 // An attempt to integrate help, usage and argument definitions in
94 // one string (seems to work)
95 // Still to do:
96 // * adding arbitrary "-" at end of files (do we need that?)
97 // dealing with environment var specification of extra options
98 // override options function (maybe no longer needed)
99 // list of named values for argument
100 // Way to identify mandatory arguments
101 int parse_command_line(int argc,
102  char *argv[],
103  const EST_String &usage,
104  EST_StrList &files,
105  EST_Option &al, int make_stdio)
106 {
107  // Parse the command line arguments returning them in a normalised
108  // form in al, and files in files.
109  int i;
110  EST_Option options;
111  EST_String arg;
112  (void)make_stdio;
113 
114  // help, version, man_options are always supported
115  standard_options(argc,argv,usage);
116 
117  // Find valid options, arguments and defaults
118  // sets defaults in al
119  est_progname = argv[0];
120  parse_usage(argv[0],usage,options,al);
121 
122  for (i=1; i < argc; i++)
123  {
124  if (!EST_String(argv[i]).contains("-",0)) // its a filename
125  files.append(argv[i]);
126  else if (streq(argv[i],"-")) // single "-" denotes stdin/out
127  files.append("-");
128  else if (!valid_option(options,argv[i],arg))
129  {
130  arg_error(argv[0],
131  EST_String(": Unknown option \"")+argv[i]+"\"\n");
132  }
133  else // valid option, check args
134  {
135  if (options.val(arg) == "true") // no argument required
136  al.add_item(arg, "true");
137  else if (options.val(arg) == "<int>")
138  {
139  if (i+1 == argc)
140  arg_error(argv[0],
141  EST_String(": missing int argument for \"")+
142  arg+"\"\n");
143  i++;
144  if (!EST_String(argv[i]).matches(RXint))
145  arg_error(argv[0],
146  EST_String(": argument for \"")+
147  arg+"\" not an int\n");
148  al.add_item(arg,argv[i]);
149  }
150  else if ((options.val(arg) == "<float>") ||
151  (options.val(arg) == "<double>"))
152  {
153  if (i+1 == argc)
154  arg_error(argv[0],
155  EST_String(": missing float argument for \"")+
156  arg+"\"\n");
157  i++;
158  if (!EST_String(argv[i]).matches(RXdouble))
159  arg_error(argv[0],
160  EST_String(": argument for \"")+
161  arg+"\" not a float\n");
162  al.add_item(arg,argv[i]);
163  }
164  else if (options.val(arg) == "<string>")
165  {
166  if (i+1 == argc)
167  arg_error(argv[0],
168  EST_String(": missing string argument for \"")+
169  arg+"\"\n");
170  i++;
171  al.add_item(arg,argv[i]);
172  }
173  else if (options.val(arg) == "<ofile>")
174  {
175  if (i+1 == argc)
176  arg_error(argv[0],
177  EST_String(": missing ifile argument for \"")+
178  arg+"\"\n");
179  i++;
180  if (writable_file(argv[i]) == TRUE)
181  al.add_item(arg,argv[i]);
182  else
183  arg_error(argv[0],
184  EST_String(": output file not accessible \"")+
185  argv[i]+"\"\n");
186  }
187  else if (options.val(arg) == "<ifile>")
188  {
189  if (i+1 == argc)
190  arg_error(argv[0],
191  EST_String(": missing ifile argument for \"")+
192  arg+"\"\n");
193  i++;
194  if (readable_file(argv[i]) == TRUE)
195  al.add_item(arg,argv[i]);
196  else
197  arg_error(argv[0],
198  EST_String(": input file not accessible \"")+
199  argv[i]+"\"\n");
200 
201  }
202  else if (options.val(arg) == "<star>")
203  {
204  al.add_item(arg,EST_String(argv[i]).after(arg));
205  }
206  // else string list
207  else
208  {
209  arg_error(argv[0],
210  EST_String(": unknown argument type \"")+
211  options.val(argv[i])+"\" (misparsed usage string)\n");
212  }
213  }
214  }
215 
216  if (files.length() == 0)
217  files.append("-");
218 
219  return 0;
220 }
221 
222 static int valid_option(const EST_Option &options,const char *arg,
223  EST_String &sarg)
224 {
225  // Checks to see arg is declared as an option.
226  // This would be trivial were it not for options containing *
227  // The actual arg name is put in sarg
228  EST_Litem *p;
229 
230  for (p = options.list.head(); p != 0; p = p->next())
231  {
232  if (options.key(p) == arg)
233  {
234  sarg = arg;
235  return TRUE;
236  }
237  else if ((options.val(p) == "<star>") &&
238  (EST_String(arg).contains(options.key(p), 0)))
239  {
240  sarg = options.key(p);
241  return TRUE;
242  }
243  }
244 
245  return FALSE;
246 }
247 
248 static void parse_usage(const EST_String &progname, const EST_String &usage,
249  EST_Option &options, EST_Option &al)
250 {
251  // Extract option definitions from usage and put them in options
252  // If defaults are specified add them al
253  EST_TokenStream ts;
254  EST_Token t;
255 
256  ts.open_string(usage);
257  ts.set_SingleCharSymbols("{}[]|");
258  ts.set_PunctuationSymbols("");
260 
261  while (!ts.eof())
262  {
263  t = ts.get();
264  if ((t.string().contains("-",0)) &&
265  (t.whitespace().contains("\n")))
266  { // An argument
267  if ((ts.peek().string() == "<string>") ||
268  (ts.peek().string() == "<float>") ||
269  (ts.peek().string() == "<double>") ||
270  (ts.peek().string() == "<ifile>") ||
271  (ts.peek().string() == "<ofile>") ||
272  (ts.peek().string() == "<int>"))
273  {
274  options.add_item(t.string(),ts.get().string());
275  if (ts.peek().string() == "{") // a default is given
276  {
277  ts.get();
278  al.add_item(t.string(),ts.get().string());
279  if (ts.get() != "}")
280  arg_error(progname,
281  EST_String(": malformed default value for \"")+
282  t.string()+"\" (missing closing brace)\n");
283  }
284  }
285  else if (t.string().contains("*"))
286  options.add_item(t.string().before("*"),"<star>");
287  // else check for explicit list of names
288  else
289  options.add_item(t.string(),"true"); // simple argument
290  }
291  }
292 }
293 
294 static void arg_error(const EST_String &progname, const EST_String &message)
295 {
296  // Output message and pointer to more help then exit
297  cerr << progname << message;
298  cerr << "Type -h for help on options.\n";
299  exit(-1);
300 }
301 
302 static void standard_options(int argc, char **argv, const EST_String &usage)
303 {
304  // A number of options are always supported
305  int i;
306 
307  for (i=1; i < argc; i++)
308  {
309  if (streq(argv[i],"-man_options"))
310  {
311  output_man_options(usage);
312  exit(0);
313  }
314  if (streq(argv[i],"-sgml_options"))
315  {
316  output_sgml_options(usage);
317  exit(0);
318  }
319  if (streq(argv[i],"-sgml_synopsis"))
320  {
321  output_sgml_synopsis(argv, usage);
322  exit(0);
323  }
324  if ((streq(argv[i],"-h")) ||
325  (streq(argv[i],"-help")) ||
326  (streq(argv[i],"-?")) ||
327  (streq(argv[i],"--help")))
328  {
329  EST_Pathname full(argv[0]);
330  cout << "Usage: " << full.filename() << " " << usage << endl;
331  exit(0);
332  }
333  if (((streq(argv[i],"-version")) ||
334  (streq(argv[i],"--version")))&&
335  (!usage.contains("\n-v")))
336  {
337  cout << argv[0] << ": " << est_name << " v" << est_tools_version << endl;
338  exit(0);
339  }
340  }
341 
342  return;
343 }
344 
345 static void output_man_options(const EST_String &usage)
346 {
347  EST_TokenStream ts;
348  EST_Token t;
349  int in_options = FALSE;
350 
351  ts.open_string(usage);
352  ts.set_SingleCharSymbols("{}[]|");
353  ts.set_PunctuationSymbols("");
355 
356  while (!ts.eof())
357  {
358  t = ts.get();
359  if ((t.string().contains("-",0)) &&
360  (t.whitespace().contains("\n")))
361  { // An argument
362  fprintf(stdout,"\n.TP 8\n.BI \"%s \" ",(const char *)t.string());
363  if ((ts.peek().string() == "<string>") ||
364  (ts.peek().string() == "<float>") ||
365  (ts.peek().string() == "<double>") ||
366  (ts.peek().string() == "<int>"))
367  fprintf(stdout,"%s",(const char *)ts.get().string());
368  if ((ts.peek().string() == "{"))
369  { // a default value
370  ts.get();
371  fprintf(stdout," \" {%s}\"",(const char *)ts.get().string());
372  ts.get();
373  }
374  if (!ts.peek().whitespace().contains("\n"))
375  fprintf(stdout,"\n");
376  in_options = TRUE;
377  }
378  else if (in_options)
379  {
380  if (t.whitespace().contains("\n"))
381  fprintf(stdout,"\n");
382  fprintf(stdout,"%s ",(const char *)t.string());
383  }
384  }
385  if (in_options)
386  fprintf(stdout,"\n");
387 
388 
389 }
390 
391 static void output_sgml_options(const EST_String &usage)
392 {
393  EST_TokenStream ts;
394  EST_Token t;
395  EST_String atype;
396  int in_options = FALSE;
397 
398  ts.open_string(usage);
399  ts.set_SingleCharSymbols("{}[]|");
400  ts.set_PunctuationSymbols("");
402 
403  fprintf(stdout,"<variablelist>\n");
404 
405  while (!ts.eof())
406  {
407  t = ts.get();
408  if ((t.string().contains("-",0)) &&
409  (t.whitespace().contains("\n")))
410  { // An argument
411  if (in_options)
412  fprintf(stdout,"\n</PARA></LISTITEM>\n</varlistentry>\n\n");
413  fprintf(stdout,"<varlistentry><term>%s</term>\n<LISTITEM><PARA>\n", (const char *)t.string());
414  if ((ts.peek().string() == "<string>") ||
415  (ts.peek().string() == "<float>") ||
416  (ts.peek().string() == "<ifile>") ||
417  (ts.peek().string() == "<ofile>") ||
418  (ts.peek().string() == "<double>") ||
419  (ts.peek().string() == "<int>"))
420  { // must strip of the angle brackets to make SGML
421  atype = ts.get().string();
422  atype.gsub("<","");
423  atype.gsub(">","");
424  fprintf(stdout,"<replaceable>%s</replaceable>\n",
425  (const char *) atype);
426  }
427  if ((ts.peek().string() == "{"))
428  { // a default value
429  ts.get();
430  fprintf(stdout," \" {%s}\"",(const char *)ts.get().string());
431  ts.get();
432  }
433  if (!ts.peek().whitespace().contains("\n"))
434  fprintf(stdout,"\n");
435  in_options = TRUE;
436  }
437  else if (in_options)
438  {
439  if (t.whitespace().contains("\n"))
440  fprintf(stdout,"\n");
441  fprintf(stdout,"%s ",(const char *)t.string());
442  }
443  }
444  if (in_options)
445  fprintf(stdout,"</PARA></LISTITEM>\n</varlistentry>\n</variablelist>\n");
446 
447 }
448 
449 static void output_sgml_synopsis(char **argv, const EST_String &usage)
450 {
451  EST_TokenStream ts;
452  EST_Token t;
453  EST_String atype;
454  int in_options = FALSE;
455 
456  ts.open_string(usage);
457  ts.set_SingleCharSymbols("{}[]|");
458  ts.set_PunctuationSymbols("");
460 
461  EST_Pathname full(argv[0]);
462 
463  fprintf(stdout,"<cmdsynopsis><command>%s</command>",
464  (const char *)full.filename());
465 
466  fprintf(stdout,"%s",(const char *)ts.get_upto_eoln().string());
467 
468  while (!ts.eof())
469  {
470  t = ts.get();
471  if ((t.string().contains("-",0)) &&
472  (t.whitespace().contains("\n")))
473  { // An argument
474  if (in_options)
475  fprintf(stdout,"</arg>\n");
476  fprintf(stdout,"<arg>%s ", (const char *)t.string());
477  if ((ts.peek().string() == "<string>") ||
478  (ts.peek().string() == "<float>") ||
479  (ts.peek().string() == "<ifile>") ||
480  (ts.peek().string() == "<ofile>") ||
481  (ts.peek().string() == "<double>") ||
482  (ts.peek().string() == "<int>"))
483  { // must strip of the angle brackets to make SGML
484  atype = ts.get().string();
485  atype.gsub("<","");
486  atype.gsub(">","");
487  fprintf(stdout,"<replaceable>%s</replaceable>",
488  (const char *) atype);
489  }
490  if ((ts.peek().string() == "{"))
491  { // a default value
492  ts.get();
493  fprintf(stdout," \" {%s}\"",(const char *)ts.get().string());
494  ts.get();
495  }
496  in_options = TRUE;
497  }
498  }
499  fprintf(stdout,"</arg>\n</cmdsynopsis>\n");
500 }
501 
503 {
504  // The standard waveform input options
505  return
506  EST_String("")+
507  "-o <ofile> output file" +
508  "-otype <string> output file type\n";
509 }
510 
512  const EST_String &option, const EST_String &arg)
513 {
514  if (al.present(arg))
515  op.set(option, al.val(arg));
516 }
517 
int readable_file(char *filename)
return true if this file is readable
Definition: util_io.cc:65
EST_TokenStream & get(EST_Token &t)
get next token in stream
Definition: EST_Token.cc:499
const K & key(EST_Litem *ptr, int m=1) const
find key, reference by ptr
Definition: EST_TKVL.cc:201
int writable_file(char *filename)
return true if this file is writeable
Definition: util_io.cc:77
int contains(const char *s, ssize_t pos=-1) const
Does it contain this substring?
Definition: EST_String.h:365
Utility IO Function header file.
EST_String options_general(void)
Definition: cmd_line.cc:502
EST_String est_progname
Definition: cmd_line.cc:57
The file was read in successfully.
void set_SingleCharSymbols(const EST_String &sc)
set which characters are to be treated as single character symbols
Definition: EST_Token.h:344
EST_Regex RXdouble("-?\\(\\([0-9]+\\.[0-9]*\\)\\|\\([0-9]+\\)\\|\\(\\.[0-9]+\\)\\)\\([eE][---+]?[0-9]+\\)?")
Floating point number.
const EST_String & whitespace()
Definition: EST_Token.h:112
void set(const EST_String &name, int ival)
Definition: EST_Features.h:186
#define streq(X, Y)
Definition: EST_cutils.h:57
char * getenv()
void set_PrePunctuationSymbols(const EST_String &ps)
set which characters are to be treated as (post) punctuation
Definition: EST_Token.h:350
int contains(EST_TList< int > &l, int n)
Definition: EST_cluster.cc:82
EST_UItem * next()
Definition: EST_UList.h:55
void option_override(EST_Features &op, EST_Option al, const EST_String &option, const EST_String &arg)
Definition: cmd_line.cc:511
int open_string(const EST_String &newbuffer)
open a EST_TokenStream for string rather than a file
Definition: EST_Token.cc:264
EST_Regex RXint("-?[0-9]+")
Integer.
void set_PunctuationSymbols(const EST_String &ps)
set which characters are to be treated as (post) punctuation
Definition: EST_Token.h:347
int eof()
end of file
Definition: EST_Token.h:362
int gsub(const char *os, const EST_String &s)
Substitute one string for another.
Definition: EST_String.h:391
EST_read_status load(const EST_String &filename, const EST_String &comment=";")
Definition: EST_Option.cc:144
EST_TList< EST_TKVI< K, V > > list
Linked list of key-val pairs. Don&#39;t use this as it will be made private in the future.
Definition: EST_TKVL.h:94
void override_lib_ops(EST_Option &a_list, EST_Option &al)
Definition: ch_lab_main.cc:186
int parse_command_line(int argc, char *argv[], const EST_String &usage, EST_StrList &files, EST_Option &al, int make_stdio)
Definition: cmd_line.cc:101
#define FALSE
Definition: EST_bool.h:119
EST_Token & peek(void)
peek at next token
Definition: EST_Token.h:332
const char *const est_tools_version
Definition: EST_cutils.c:49
int init_lib_ops(EST_Option &al, EST_Option &op)
Definition: cmd_line.cc:69
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
EST_Pathname filename(void) const
void append(const T &item)
add item onto end of list
Definition: EST_TList.h:196
int length() const
Definition: EST_UList.cc:57
int add_item(const K &rkey, const V &rval, int no_search=0)
add key-val pair to list
Definition: EST_TKVL.cc:248
const EST_String & string() const
Definition: EST_Token.h:120
const char *const est_name
Definition: EST_cutils.c:52
int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
EST_Token get_upto_eoln(void)
get up to s in end of line as a single token.
Definition: EST_Token.cc:529
EST_UItem * head() const
Definition: EST_UList.h:97
EST_String before(int pos, int len=0) const
Part before position.
Definition: EST_String.h:276
EST_String
#define TRUE
Definition: EST_bool.h:118
Utility EST_String Functions header file.