/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* m_options.c --- process options and set values */

/* $Id: m_options.c,v 1.14 2003/01/06 16:10:39 ri Exp $ */

#include <julius.h>

/* change relative path to absolute path */
static char *
filepath(char *filename, char *dirname)
{
  char *p;
  if (dirname != NULL && filename[0] != '/') {
    p = (char *)mymalloc(strlen(filename) + strlen(dirname) + 1);
    strcpy(p, dirname);
    strcat(p, filename);
  } else {
    p = filename;
  }
  return p;
}

/* error exit when required argument was not specified */
static char *
args_needed_exit(char *opt)
{
  j_printerr("%s: option requires argument -- %s\n", EXECNAME, opt);
  opt_terminate();
  return(NULL);
}

/* parse options and set values */
void
opt_parse(int argc, char *argv[], char *cwd)
{
  char *tmparg;
  int i;

#define NEXTARG (++i >= argc) ? (char *)args_needed_exit(argv[i-1]) : argv[i]

  if (argc == 1) {		/* no argument */
    usage();
  }
  
  for (i=1;i<argc;i++) {
    if (strmatch(argv[i],"-C")) { /* include jconf file  */
      config_file_parse(filepath(NEXTARG, cwd));
      continue;
    } else if (strmatch(argv[i],"-input")) { /* speech input */
      tmparg = NEXTARG;
      if (strmatch(tmparg,"rawfile")) {
	speech_input = SP_RAWFILE;
	realtime_flag = FALSE;
      } else if (strmatch(tmparg,"mfcfile")) {
	speech_input = SP_MFCFILE;
	realtime_flag = FALSE;
      } else if (strmatch(tmparg,"stdin")) {
	speech_input = SP_STDIN;
	realtime_flag = FALSE;
      } else if (strmatch(tmparg,"adinnet")) {
	speech_input = SP_ADINNET;
	realtime_flag = TRUE;
#ifdef USE_NETAUDIO
      } else if (strmatch(tmparg,"netaudio")) {
	speech_input = SP_NETAUDIO;
	realtime_flag = TRUE;
#endif
#ifdef USE_MIC
      } else if (strmatch(tmparg,"mic")) {
	speech_input = SP_MIC;
	realtime_flag = TRUE;
#endif
      } else if (strmatch(tmparg,"file")) { /* for 1.1 compat */
	speech_input = SP_RAWFILE;
	realtime_flag = FALSE;
      } else if (strmatch(tmparg,"mfc")) { /* for 1.1 compat */
	speech_input = SP_MFCFILE;
	realtime_flag = FALSE;
      } else {
	j_printerr("%s: no such speech input source \"%s\" supported\n", argv[0], tmparg);
	opt_terminate();
      }
      continue;
    } else if (strmatch(argv[i],"-filelist")) {	/* input file list */
      inputlist_filename = NEXTARG;
      continue;
    } else if (strmatch(argv[i],"-record")) {	/* record speech data*/
      record_dirname = NEXTARG;
      continue;
    } else if (strmatch(argv[i],"-module")) { /* enable module mode */
      module_mode = TRUE;
      if (i+1 < argc) {
	if (argv[i+1][0] >= '0' && argv[i+1][0] <= '9') {
	  module_port = atoi(NEXTARG);
	}
      }
      /* this option implicitly includes "-result msock" */
      result_output = SP_RESULT_MSOCK;
      continue;
    } else if (strmatch(argv[i],"-result")) { /* result output */
      tmparg = NEXTARG;
      if (strmatch(tmparg,"tty")) {
	result_output = SP_RESULT_TTY;
      } else if (strmatch(tmparg,"msock")) {
	result_output = SP_RESULT_MSOCK;
      } else {
	j_printerr("%s: no such result output \"%s\"\n", argv[0], tmparg);
	opt_terminate();
      }
      continue;
    } else if (strmatch(argv[i],"-outcode")) {
      decode_output_selection(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-force_realtime")) { /* force realtime */
      tmparg = NEXTARG;
      if (strmatch(tmparg, "on")) {
	forced_realtime = TRUE;
      } else if (strmatch(tmparg, "off")) {
	forced_realtime = FALSE;
      } else {
	j_printerr("%s: \"-force_realtime\" allows \"on\" or \"off\" only\n", EXECNAME);
	opt_terminate();
      }
      force_realtime_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-realtime")) {	/* equal to "-force_realtime on" */
      forced_realtime = TRUE;
      force_realtime_flag = TRUE;
      continue;
    } else if (strmatch(argv[i], "-norealtime")) { /* equal to "-force_realtime off" */
      forced_realtime = FALSE;
      force_realtime_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-forcedict")) { /* skip dict error */
      forcedict_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-check")) { /* interactive model check mode */
      tmparg = NEXTARG;
      if (strmatch(tmparg, "wchmm")) {
	wchmm_check_flag = TRUE;
      } else if (strmatch(tmparg, "trellis")) {
	trellis_check_flag = TRUE;
      } else if (strmatch(tmparg, "triphone")) {
	triphone_check_flag = TRUE;
      } else {
	j_printerr("%s: invalid check style: %s\n", argv[0], tmparg);
	opt_terminate();
      }
      continue;
    } else if (strmatch(argv[i],"-notypecheck")) { /* don't check param type */
      paramtype_check_flag = FALSE;
      continue;
    } else if (strmatch(argv[i],"-separatescore")) { /* output LM/AM score */
#ifdef USE_NGRAM
      separate_score_flag = TRUE;
#else  /* USE_DFA */
      j_printerr("Warning: option \"-separatescore\" ignored\n");
#endif
      continue;
    } else if (strmatch(argv[i],"-nlimit")) { /* limit N token in a node */
#ifdef WPAIR_KEEP_NLIMIT
      wpair_keep_nlimit = atoi(NEXTARG);
#else
      j_printerr("Warning: option \"-nlimit\" ignored\n");
#endif
      continue;
    } else if (strmatch(argv[i],"-lookuprange")) { /* trellis neighbor range */
      lookup_range = atoi(NEXTARG);
      continue;
#ifdef USE_DFA
    } else if (strmatch(argv[i],"-looktrellis")) { /* activate loopuprange */
      looktrellis_flag = TRUE;
      continue;
#endif
#ifdef CATEGORY_TREE
    } else if (strmatch(argv[i],"-oldtree")) { /* use old tree function */
      old_tree_function_flag = TRUE;
      continue;
#ifdef PASS1_IWCD
    } else if (strmatch(argv[i],"-oldiwcd")) { /* use full lcd ignoring category constraint */
      old_iwcd_flag = TRUE;
      continue;
#endif
#endif
    } else if (strmatch(argv[i],"-sb")) { /* score envelope width in 2nd pass */
#ifdef SCAN_BEAM
      scan_beam_thres = atof(NEXTARG);
#else
      j_printerr("Warning: option \"-sb\" ignored\n");
#endif
      continue;
    } else if (strmatch(argv[i],"-discount")) {	/* (bogus) */
      j_printerr("Warning: option \"-discount\" ignored\n");
      continue;
    } else if (strmatch(argv[i],"-cutsilence")) { /* force (long) silence detection on */
      silence_cut = 1;
      continue;
    } else if (strmatch(argv[i],"-nocutsilence")) { /* force (long) silence detection off */
      silence_cut = 0;
      continue;
    } else if (strmatch(argv[i],"-pausesegment")) { /* force (long) silence detection on (for backward compatibility) */
      silence_cut = 1;
      continue;
    } else if (strmatch(argv[i],"-nopausesegment")) { /* force (long) silence detection off (for backward comatibility) */
      silence_cut = 0;
      continue;
    } else if (strmatch(argv[i],"-lv")) { /* silence detection threshold level */
      level_thres = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-zc")) { /* silence detection zero cross num */
      zero_cross_num = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-headmargin")) { /* head silence length */
      head_margin_msec = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-tailmargin")) { /* tail silence length */
      tail_margin_msec = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-hipass")) { /* frequency of hi cut-off */
      hipass = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-lopass")) { /* frequency of low cut-off */
      lopass = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-smpPeriod")) { /* sample period (ns) */
      smpPeriod = atoi(NEXTARG);
      smpFreq = period2freq(smpPeriod);
      continue;
    } else if (strmatch(argv[i],"-smpFreq")) { /* sample frequency (Hz) */
      smpFreq = atoi(NEXTARG);
      smpPeriod = freq2period(smpFreq);
      continue;
    } else if (strmatch(argv[i],"-fsize")) { /* Window size */
      fsize = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-fshift")) { /* Frame shiht */
      fshift = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-delwin")) { /* Delta window length */
      delwin = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-ssalpha")) { /* alpha coef. for SS */
      ssalpha = atof(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-ssfloor")) { /* spectral floor for SS */
      ssfloor = atof(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-version")) { /* print version and exit */
      put_header(stderr);
      put_compile_defs(stderr);
      j_exit();
    } else if (strmatch(argv[i],"--version")) {
      put_header(stderr);
      put_compile_defs(stderr);
      j_exit();
    } else if (strmatch(argv[i],"-quiet")) { /* minimum output */
      debug2_flag = verbose_flag = FALSE;
      continue;
    } else if (strmatch(argv[i],"-debug")) { /* debug mode: output huge log */
      debug2_flag = verbose_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-progout")) { /* enable progressive output */
      progout_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-proginterval")) { /* interval for -progout */
      progout_interval = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-demo")) { /* quiet + progout */
      debug2_flag = verbose_flag = FALSE;
      progout_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-walign")) { /* do forced alignment by word */
      align_result_word_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-palign")) { /* do forced alignment by phoneme */
      align_result_phoneme_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-salign")) { /* do forced alignment by state */
      align_result_state_flag = TRUE;
      continue;
    } else if (strmatch(argv[i],"-output")) { /* output up to N candidate */
      output_hypo_maxnum = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-1pass")) { /* do only 1st pass */
      compute_only_1pass = TRUE;
      continue;
    } else if (strmatch(argv[i],"-hlist")) { /* HMM list file */
      mapfilename = filepath(NEXTARG, cwd);
      continue;
#ifdef USE_NGRAM
    } else if (strmatch(argv[i],"-nlr")) { /* word LR 2-gram (ARPA) */
      ngram_filename_lr_arpa = filepath(NEXTARG, cwd);
      ngram_filename = NULL;
      continue;
    } else if (strmatch(argv[i],"-nrl")) { /* word RL 3-gram (ARPA) */
      ngram_filename_rl_arpa = filepath(NEXTARG, cwd);
      ngram_filename = NULL;
      continue;
    } else if (strmatch(argv[i],"-lmp")) { /* LM weight and penalty (pass1) */
      lm_weight = (LOGPROB)atof(NEXTARG);
      lm_penalty = (LOGPROB)atof(NEXTARG);
      lmp_specified = TRUE;
      continue;
    } else if (strmatch(argv[i],"-lmp2")) { /* LM weight and penalty (pass2) */
      lm_weight2 = (LOGPROB)atof(NEXTARG);
      lm_penalty2 = (LOGPROB)atof(NEXTARG);
      lmp2_specified = TRUE;
      continue;
    } else if (strmatch(argv[i],"-transp")) { /* penalty for transparent word */
      lm_penalty_trans = (LOGPROB)atof(NEXTARG);
      continue;
#else  /* USE_DFA */
    } else if (strmatch(argv[i],"-dfa")) { /* DFA filename */
      dfa_filename = filepath(NEXTARG, cwd);
      continue;
    } else if (strmatch(argv[i],"-penalty1")) {	/* word insertion penalty (pass1) */
      penalty1 = (LOGPROB)atof(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-penalty2")) {	/* word insertion penalty (pass2) */
      penalty2 = (LOGPROB)atof(NEXTARG);
      continue;
#endif
    } else if (strmatch(argv[i],"-spmodel") || strmatch(argv[i], "-sp")) { /* name of short pause word */
      spmodel_name = NEXTARG;
      continue;
    } else if (strmatch(argv[i],"-iwsp")) { /* enable inter-word short pause handing */
      enable_iwsp = TRUE;
      continue;
    } else if (strmatch(argv[i],"-iwsppenalty")) { /* set inter-word short pause transition penalty */
      iwsp_penalty = atof(NEXTARG);
      continue;
#ifdef USE_NGRAM
    } else if (strmatch(argv[i],"-silhead")) { /* head silence word name */
      head_silname = NEXTARG;
      continue;
    } else if (strmatch(argv[i],"-siltail")) { /* tail silence word name */
      tail_silname = NEXTARG;
      continue;
    } else if (strmatch(argv[i],"-iwspword")) { /* add short pause word */
      enable_iwspword = TRUE;
      continue;
    } else if (strmatch(argv[i],"-iwspentry")) { /* content of the iwspword */
      iwspentry = NEXTARG;
      continue;
#ifdef CLASS_NGRAM
    } else if (strmatch(argv[i],"-class")) {
      class_bingram_file = filepath(NEXTARG, cwd);
      continue;
    } else if (strmatch(argv[i],"-clw")) {
      class_weight = atof(NEXTARG);
      continue;
#endif
    } else if (strmatch(argv[i],"-iwcache")) { /* control cross-word LM cache */
#ifdef HASH_CACHE_IW
      iw_cache_rate = atof(NEXTARG);
      if (iw_cache_rate > 100) iw_cache_rate = 100;
      if (iw_cache_rate < 1) iw_cache_rate = 1;
#else
      j_printerr("Warning: option \"-iwcache\" ignored\n");
#endif
      continue;
    } else if (strmatch(argv[i],"-sepnum")) { /* N-best frequent word will be separated from tree */
#ifdef SEPARATE_BY_UNIGRAM
      separate_wnum = atoi(NEXTARG);
#else
      j_printerr("Warning: option \"-sepnum\" ignored\n");
#endif
      continue;
#endif /* USE_NGRAM */
#ifdef USE_NETAUDIO
    } else if (strmatch(argv[i],"-NA")) { /* netautio device name */
      netaudio_devname = NEXTARG;
      continue;
#endif
    } else if (strmatch(argv[i],"-adport")) { /* adinnet port num */
      adinnet_port = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-nostrip")) { /* do not strip zero samples */
      strip_zero_sample = FALSE;
      continue;
#ifdef SP_BREAK_CURRENT_FRAME
    } else if (strmatch(argv[i],"-spdur")) { /* short-pause duration threshold */
      sp_frame_duration = atoi(NEXTARG);
      continue;
#endif
    } else if (strmatch(argv[i],"-gprune")) { /* select Gaussian pruning method */
      tmparg = NEXTARG;
      if (strmatch(tmparg,"safe")) { /* safest, slowest */
	gprune_method = GPRUNE_SEL_SAFE;
      } else if (strmatch(tmparg,"heuristic")) {
	gprune_method = GPRUNE_SEL_HEURISTIC;
      } else if (strmatch(tmparg,"beam")) { /* fastest */
	gprune_method = GPRUNE_SEL_BEAM;
      } else if (strmatch(tmparg,"none")) { /* no prune: compute all Gaussian */
	gprune_method = GPRUNE_SEL_NONE;
      } else {
	j_printerr("%s: no such pruning method \"%s\"\n", argv[0], tmparg);
	opt_terminate();
      }
      continue;
/* 
 *     } else if (strmatch(argv[i],"-reorder")) {
 *	 result_reorder_flag = TRUE;
 *	 continue;
 */
    } else if (strmatch(argv[i],"-no_ccd")) { /* force triphone handling = OFF */
      ccd_flag = FALSE;
      ccd_flag_force = TRUE;
      continue;
    } else if (strmatch(argv[i],"-force_ccd")) { /* force triphone handling = ON */
      ccd_flag = TRUE;
      ccd_flag_force = TRUE;
      continue;
    } else if (strmatch(argv[i],"-iwcd1")) { /* select cross-word triphone computation method */
      tmparg = NEXTARG;
      if (strmatch(tmparg, "max")) { /* use maximum score in triphone variants */
	iwcdavg_flag = FALSE;
      } else if (strmatch(tmparg, "avg")) { /* use average in variants */
	iwcdavg_flag = TRUE;
      } else {
	j_printerr("%s: -iwcd1: wrong argument (max|avg): %s\n", argv[0], tmparg);
	opt_terminate();
      }
      continue;
    } else if (strmatch(argv[i],"-tmix")) { /* num of mixture to select */
      if (i + 1 < argc && isdigit(argv[i+1][0])) {
	mixnum_thres = atoi(argv[++i]);
      }
      continue;
    } else if (strmatch(argv[i],"-b2") || strmatch(argv[i],"-bw") || strmatch(argv[i],"-wb")) {	/* word beam width in 2nd pass */
      enveloped_bestfirst_width = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-hgs")) { /* Gaussian selection model file */
      hmm_gs_filename = filepath(NEXTARG, cwd);
      continue;
    } else if (strmatch(argv[i],"-booknum")) { /* num of state to select in GS */
      gs_statenum = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-gshmm")) { /* same as "-hgs" */
      hmm_gs_filename = filepath(NEXTARG, cwd);
      continue;
    } else if (strmatch(argv[i],"-gsnum")) { /* same as "-booknum" */
      gs_statenum = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-cmnload")) { /* load CMN parameter from file */
      cmnload_filename = filepath(NEXTARG, cwd);
      continue;
    } else if (strmatch(argv[i],"-cmnsave")) { /* save CMN parameter to file */
      cmnsave_filename = filepath(NEXTARG, cwd);
      continue;
    } else if (strmatch(argv[i],"-sscalc")) { /* do spectral subtraction (SS) for raw file input */
      sscalc = TRUE;
      ssload_filename = NULL;
      continue;
    } else if (strmatch(argv[i],"-sscalclen")) { /* head silence length used to compute SS (in msec) */
      sscalc_len = atoi(NEXTARG);
      continue;
    } else if (strmatch(argv[i],"-ssload")) { /* load SS parameter from file */
      ssload_filename = filepath(NEXTARG, cwd);
      sscalc = FALSE;
      continue;
    } else if (strmatch(argv[i],"-help")) { /* output version and option */
      detailed_help();
    } else if (strmatch(argv[i],"--help")) {
      detailed_help();
    }
    if (argv[i][0] == '-' && strlen(argv[i]) == 2) {
      /* 1-letter options */
      switch(argv[i][1]) {
      case 'h':			/* hmmdefs */
	hmmfilename = filepath(NEXTARG, cwd);
	break;
      case 'v':			/* dictionary */
	dictfilename = filepath(NEXTARG, cwd);
	break;
#ifdef USE_NGRAM
      case 'd':			/* binary N-gram */
	ngram_filename = filepath(NEXTARG, cwd);
	ngram_filename_lr_arpa = NULL;
	ngram_filename_rl_arpa = NULL;
	break;
#endif
      case 'b':			/* beam width in 1st pass */
	trellis_beam_width = atoi(NEXTARG);
	break;
      case 's':			/* stack size in 2nd pass */
	stack_size = atoi(NEXTARG);
	break;
      case 'n':			/* N-best search */
	nbest = atoi(NEXTARG);
	break;
      case 'm':			/* upper limit of hypothesis generation */
	hypo_overflow = atoi(NEXTARG);
	break;
      default:
	j_printerr("%s: wrong argument: %s\n", argv[0], argv[i]);
	opt_terminate();
      }
    } else {			/* error */
      j_printerr("%s: wrong argument: %s\n", argv[0], argv[i]);
      opt_terminate();
    }
  }
}

