#include #include #include #include "UserInterface.h" #include "StkStream.h" #include "Features.h" namespace TNet { //*************************************************************************** //*************************************************************************** int npercents(const char *str) { int ret = 0; while (*str) if (*str++ == '%') ret++; return ret; } //*************************************************************************** //*************************************************************************** void UserInterface:: ReadConfig(const char *file_name) { std::string line_buf; std::string::iterator chptr; std::string key; std::string value; std::ostringstream ss; int line_no = 0; IStkStream i_stream; i_stream.open(file_name, std::ios::binary); if (!i_stream.good()) { throw std::runtime_error(std::string("Cannot open input config file ") + file_name); } i_stream >> std::ws; while (!i_stream.eof()) { size_t i_pos; // read line std::getline(i_stream, line_buf); i_stream >> std::ws; if (i_stream.fail()) { throw std::runtime_error(std::string("Error reading (") + file_name + ":" + (ss << line_no,ss).str() + ")"); } // increase line counter line_no++; // cut comments if (std::string::npos != (i_pos = line_buf.find('#'))) { line_buf.erase(i_pos); } // cut leading and trailing spaces Trim(line_buf); // if empty line, then skip it if (0 == line_buf.length()) { continue; } // line = line_buf.c_str(); // chptr = parptr; chptr = line_buf.begin(); for (;;) { // Replace speces by '_', which is removed in InsertConfigParam while (isalnum(*chptr) || *chptr == '_' || *chptr == '-') { chptr++; } while (std::isspace(*chptr)) { *chptr = '_'; chptr++; } if (*chptr != ':') { break; } chptr++; while (std::isspace(*chptr)) { *chptr = '_'; chptr++; } } if (*chptr != '=') { throw std::runtime_error(std::string("Character '=' expected (") + file_name + ":" + (ss.str(""),ss<(opt) + "'"); } chptr += 3; while (std::isspace(*chptr)) { chptr++; } if (!chptr || chptr[0] == '-') {// Option without format string will be ignored optfmt = " "; } else { optfmt = chptr; while (*chptr && !std::isspace(*chptr)) { chptr++; } if (!*chptr) { throw std::runtime_error("Fatal: Unexpected end of optionMap string"); } } for (i = 0; !std::isspace(*optfmt); optfmt++) { while (std::isspace(*chptr)) chptr++; value = chptr; while (*chptr && !std::isspace(*chptr)) chptr++; assert(static_cast(chptr-value+1) < sizeof(param)); strncat(strcat(strcpy(param, pToolName), ":"), value, chptr-value); param[chptr-value+strlen(pToolName)+1] = '\0'; switch (*optfmt) { case 'n': value = strchr(param, '='); if (value) *value = '\0'; InsertConfigParam(param, value ? value + 1: "TRUE", opt); break; case 'l': case 'o': case 'r': i++; if (!optarg && (optind+1==argc || IS_OPTION(argv[optind+1]))) { if (*optfmt == 'r' || *optfmt == 'l') { throw std::runtime_error(std::string("Argument ") + (ss<(opt) + "' expected"); } optfmt = " "; // Stop reading option arguments break; } if (!optarg) optarg = argv[++optind]; if (*optfmt == 'o') { option_must_follow = (bool) 1; } bptr = NULL; // For repeated use of option with 'l' (list) format, append // ',' and argument string to existing config parameter value. if (*optfmt == 'l' && OPTION_MARK(opt)) { bptr = strdup(GetStr(param, "")); if (bptr == NULL) throw std::runtime_error("Insufficient memory"); bptr = (char*) realloc(bptr, strlen(bptr) + strlen(optarg) + 2); if (bptr == NULL) throw std::runtime_error("Insufficient memory"); strcat(strcat(bptr, ","), optarg); optarg = bptr; } MARK_OPTION(opt); InsertConfigParam(param, optarg, opt); free(bptr); optarg = NULL; break; default : throw std::runtime_error(std::string("Fatal: Invalid character '") + *optfmt + "' in optionMap after " + tstr); } } if (optarg) { throw std::runtime_error(std::string("Unexpected argument '") + optarg + "' after option '-" + static_cast(opt) + "'"); } } for (i = optind; i < argc && !IS_OPTION(argv[i]); i++) {} if (i < argc) { throw std::runtime_error(std::string("No option expected after first non-option argument '") + argv[optind] + "'"); } if (option_must_follow) { throw std::runtime_error(std::string("Option '-") + static_cast(opt) + "' with optional argument must not be the last option"); } return optind; } //*************************************************************************** //*************************************************************************** int UserInterface:: GetFeatureParams( int * derivOrder, int ** derivWinLens, int * startFrmExt, int * endFrmExt, char ** CMNPath, char ** CMNFile, const char ** CMNMask, char ** CVNPath, char ** CVNFile, const char ** CVNMask, const char ** CVGFile, const char * pToolName, int pseudoModeule) { const char * str; int targetKind; char * chrptr; char paramName[32]; const char * CMNDir; const char * CVNDir; strcpy(paramName, pToolName); strcat(paramName, pseudoModeule == 1 ? "SPARM1:" : pseudoModeule == 2 ? "SPARM2:" : ""); chrptr = paramName + strlen(paramName); strcpy(chrptr, "STARTFRMEXT"); *startFrmExt = GetInt(paramName, 0); strcpy(chrptr, "ENDFRMEXT"); *endFrmExt = GetInt(paramName, 0); *CMNPath = *CVNPath = NULL; strcpy(chrptr, "CMEANDIR"); CMNDir = GetStr(paramName, NULL); strcpy(chrptr, "CMEANMASK"); *CMNMask = GetStr(paramName, NULL); if (*CMNMask != NULL) { *CMNPath = (char*) malloc((CMNDir ? strlen(CMNDir) : 0) + npercents(*CMNMask) + 2); if (*CMNPath == NULL) throw std::runtime_error("Insufficient memory"); if (CMNDir != NULL) strcat(strcpy(*CMNPath, CMNDir), "/"); *CMNFile = *CMNPath + strlen(*CMNPath); } strcpy(chrptr, "VARSCALEDIR"); CVNDir = GetStr(paramName, NULL); strcpy(chrptr, "VARSCALEMASK"); *CVNMask = GetStr(paramName, NULL); if (*CVNMask != NULL) { *CVNPath = (char*) malloc((CVNDir ? strlen(CVNDir) : 0) + npercents(*CVNMask) + 2); if (*CVNPath == NULL) throw std::runtime_error("Insufficient memory"); if (CVNDir != NULL) strcat(strcpy(*CVNPath, CVNDir), "/"); *CVNFile = *CVNPath + strlen(*CVNPath); } strcpy(chrptr, "VARSCALEFN"); *CVGFile = GetStr(paramName, NULL); strcpy(chrptr, "TARGETKIND"); str = GetStr(paramName, "ANON"); targetKind = FeatureRepository::ReadParmKind(str, false); if (targetKind == -1) { throw std::runtime_error(std::string("Invalid TARGETKIND = '") + str + "'"); } strcpy(chrptr, "DERIVWINDOWS"); if ((str = GetStr(paramName, NULL)) != NULL) { long lval; *derivOrder = 0; *derivWinLens = NULL; if (NULL != str) { while ((str = strtok((char *) str, " \t_")) != NULL) { lval = strtol(str, &chrptr, 0); if (!*str || *chrptr) { throw std::runtime_error("Integers separated by '_' expected for parameter DERIVWINDOWS"); } *derivWinLens = (int *)realloc(*derivWinLens, ++*derivOrder*sizeof(int)); if (*derivWinLens == NULL) throw std::runtime_error("Insufficient memory"); (*derivWinLens)[*derivOrder-1] = lval; str = NULL; } } return targetKind; } *derivOrder = targetKind & PARAMKIND_T ? 3 : targetKind & PARAMKIND_A ? 2 : targetKind & PARAMKIND_D ? 1 : 0; if (*derivOrder || targetKind != PARAMKIND_ANON) { *derivWinLens = (int *) malloc(3 * sizeof(int)); if (*derivWinLens == NULL) throw std::runtime_error("Insufficient memory"); strcpy(chrptr, "DELTAWINDOW"); (*derivWinLens)[0] = GetInt(paramName, 2); strcpy(chrptr, "ACCWINDOW"); (*derivWinLens)[1] = GetInt(paramName, 2); strcpy(chrptr, "THIRDWINDOW"); (*derivWinLens)[2] = GetInt(paramName, 2); return targetKind; } *derivWinLens = NULL; *derivOrder = -1; return targetKind; } //*************************************************************************** //*************************************************************************** UserInterface::ValueRecord* UserInterface:: GetParam(const char* pParamName) { MapType::iterator it; // this is done only for convenience. in the loop we will increase the // pointer again pParamName--; // we iteratively try to find the param name in the map. if an attempt // fails, we strip off all characters until the first ':' and we search // again do { pParamName++; it = mMap.find(pParamName); } while ((it == mMap.end()) && (NULL != (pParamName = strchr(pParamName, ':')))); if (it == mMap.end()) { return NULL; } else { it->second.mRead = true; return &(it->second); } } //*************************************************************************** //*************************************************************************** const char * UserInterface:: GetStr( const char * pParamName, const char * default_value) { ValueRecord* p_val = GetParam(pParamName); if (NULL == p_val) { return default_value; } else { return p_val->mValue.c_str(); } } //*************************************************************************** //*************************************************************************** long UserInterface:: GetInt( const char *pParamName, long default_value) { char *chrptr; ValueRecord* p_val = GetParam(pParamName); if (NULL == p_val) { return default_value; } const char *val = p_val->mValue.c_str(); default_value = strtol(val, &chrptr, 0); if (!*val || *chrptr) { throw std::runtime_error(std::string("Integer number expected for ") + pParamName + " but found '" + val + "'"); } return default_value; } //*************************************************************************** //*************************************************************************** float UserInterface:: GetFlt( const char * pParamName, float default_value) { char *chrptr; ValueRecord* p_val = GetParam(pParamName); if (NULL == p_val) { return default_value; } const char *val = p_val->mValue.c_str(); default_value = strtod(val, &chrptr); if (!*val || *chrptr) { throw std::runtime_error(std::string("Decimal number expected for ") + pParamName + " but found '" + val + "'"); } return default_value; } //*************************************************************************** //*************************************************************************** bool UserInterface:: GetBool( const char * pParamName, bool default_value) { ValueRecord* p_val = GetParam(pParamName); if (NULL == p_val) { return default_value; } const char* val = p_val->mValue.c_str(); if (!strcasecmp(val, "TRUE") || !strcmp(val, "T")) return 1; if (strcasecmp(val, "FALSE") && strcmp(val, "F")) { throw std::runtime_error(std::string("TRUE or FALSE expected for ") + pParamName + " but found '" + val + "'"); } return false; } //*************************************************************************** //*************************************************************************** // '...' are pairs: string and corresponding integer value , terminated by NULL int UserInterface:: GetEnum( const char * pParamName, int default_value, ...) { ValueRecord* p_val = GetParam(pParamName); if (NULL == p_val) { return default_value; } const char* val = p_val->mValue.c_str(); char* s; int i = 0, cnt = 0, l = 0; va_list ap; va_start(ap, default_value); while ((s = va_arg(ap, char *)) != NULL) { l += strlen(s) + 2; ++cnt; i = va_arg(ap, int); if (!strcmp(val, s)) break; } va_end(ap); if (s) { return i; } //To report error, create string listing all possible values s = (char*) malloc(l + 1); s[0] = '\0'; va_start(ap, default_value); for (i = 0; i < cnt; i++) { strcat(s, va_arg(ap, char *)); va_arg(ap, int); if (i < cnt - 2) strcat(s, ", "); else if (i == cnt - 2) strcat(s, " or "); } va_end(ap); throw std::runtime_error(std::string(s) + " expected for " + pParamName + " but found '" + val + "'"); return 0; } //*************************************************************************** //*************************************************************************** void UserInterface:: PrintConfig(std::ostream& rStream) { rStream << "Configuration Parameters[" << mMap.size() << "]\n"; for (MapType::iterator it = mMap.begin(); it != mMap.end(); ++it) { rStream << (it->second.mRead ? " " : "# ") << std::setw(35) << std::left << it->first << " = " << std::setw(30) << std::left << it->second.mValue << " # -" << it->second.mOption << std::endl; } } //*************************************************************************** //*************************************************************************** void UserInterface:: CheckCommandLineParamUse() { for (MapType::iterator it = mMap.begin(); it != mMap.end(); ++it) { if (!it->second.mRead && it->second.mOption != 'C') { Error("Unexpected command line parameter " + it->first); } } } }