56 #include <sys/types.h> 57 #include <sys/select.h> 71 #include "rnr/rnrconfig.h" 101 #undef CL_ENABLE_DEBUG 103 #ifdef CL_ENABLE_DEBUG 104 static int dbg_calldepth_ = -1;
106 #define CL_CALL_DEPTH dbg_calldepth_ 107 #define CL_SET_CALL_DEPTH(_n) dbg_calldepth_ = _n 108 #define CL_PUSH_CALL_DEPTH() ++dbg_calldepth_ 109 #define CL_POP_CALL_DEPTH() --dbg_calldepth_ 116 #define CL_DBG_CALL_IN(_args, _post) \ 119 CL_PUSH_CALL_DEPTH(); \ 120 cerr << space(dbg_calldepth_*2) << __func__ << "(" << _args << ")" <<_post; \ 131 #define CL_DBG_PARSE_CALL_IN(_cmddef, _formdef, _toks, _pos, _post) \ 132 CL_DBG_CALL_IN("cmddef(uid=" << (_cmddef).getUid() \ 133 << ", name=" << (_cmddef).getName() << ")" \ 134 << ", form(index=" << (_formdef).getIndex() \ 135 << ", argc=" << (_formdef).numOfArgs() << ")" \ 136 << ", tokens=" << (_toks).size() \ 137 << ", pos=" << (_pos), _post) 143 #define CL_DBG_CALL_OUT_NL(_res) \ 146 cerr << space(dbg_calldepth_*2) << "--> (" << _res << ")" << endl; \ 147 CL_POP_CALL_DEPTH(); \ 154 #define CL_DBG_CALL_OUT_IL(_res) \ 157 cerr << "--> (" << _res << ")" << endl; \ 158 CL_POP_CALL_DEPTH(); \ 165 #define CL_DBG(_data) cerr << _data 168 #define CL_CALL_DEPTH 169 #define CL_SET_CALL_DEPTH(_n) 170 #define CL_PUSH_CALL_DEPTH() 171 #define CL_POP_CALL_DEPTH() 172 #define CL_DBG_CALL_IN(_args, _post) 173 #define CL_DBG_PARSE_CALL_IN(_cmddef, _formdef, _toks, _pos, _post) 174 #define CL_DBG_CALL_OUT_NL(_res) 175 #define CL_DBG_CALL_OUT_IL(_res) 177 #endif // CL_ENABLE_DEBUG 192 return( (c ==
'<') || (c ==
':') || (c ==
'>') ||
193 (c ==
'{') || (c ==
'|') || (c ==
'}') ||
194 (c ==
'[') || (c ==
']') ||
195 (c ==
'(') || (c ==
')') );
239 if( (c >=
'0') && (c <=
'9') )
241 return (
char)(c -
'0');
243 else if( (c >=
'a') && (c <=
'f') )
245 return (
char)(c -
'a');
247 else if( (c >=
'A') && (c <=
'F') )
249 return (
char)(c -
'A');
273 return m_exec.fn1 != NULL? m_exec.fn1(argv):
ENoExec;
286 return m_exec.fn2 != NULL? m_exec.fn2(argv):
ENoExec;
288 return m_exec.fn3 != NULL? m_exec.fn3(cli, argv):
ENoExec;
298 <<
"uid = " << obj.
m_uid <<
", " 316 DataSect::DataSect(
const string &ns,
void *pData, DeallocFunc fn)
330 DataSect::~DataSect()
332 if( (m_pData != NULL) && (m_fnDealloc != NULL) )
334 m_fnDealloc(m_pData);
338 void DataSect::set(
const string &ns,
void *pData, DeallocFunc fn)
348 <<
"namespace = " << obj.
m_strNs <<
", " 349 <<
"data = " << obj.
m_pData <<
", " 363 static const string markExec(
"ExecMark");
368 static const string labelExec(
"Execute: ");
369 static const string labelNoExec(
"NoExec: ");
370 static const string labelCompile(
"Compile: ");
371 static const string labelParse(
"Parse: ");
372 static const string labelInput(
"Input: ");
373 static const string labelAt(
"At: ");
374 static const string labelSelect(
"Select: ");
375 static const string labelTry(
"Try: ");
376 static const string labelFit(
"Fitness: ");
377 static const string labelNoMatch(
"NoMatch: ");
378 static const string labelMatch(
"Match: ");
379 static const string labelSyntax(
"Error: ");
380 static const string labelFail(
"Failure: ");
381 static const string labelBlank(
" ");
383 CommandLine::CommandLine(
const string strName,
384 const string strPrompt,
388 m_bIgnoreCase(bIgnoreCase),
389 m_readline(strName, strPrompt, bUseRlLib),
390 m_log(
"Command Line Log", 50)
404 bool CommandLine::isDefined()
const 421 m_log <<
"No syntax forms specified." <<
eoe;
483 split(strSyntax,
'\n', syntaxForms);
488 if( syntaxForms.size() == 0 || syntaxForms[0].empty() )
490 m_log <<
"No syntax forms specified." <<
eoe;
514 for(
size_t i = 0; i < syntaxForms.size(); ++i)
599 m_log <<
"Command " << uid <<
" removed." <<
eoe;
605 m_log <<
"No command with uid " << uid <<
" found." <<
eoe;
623 m_log <<
"All commands removed." <<
eoe;
632 CL_DBG_CALL_IN(
"", endl);
644 m_log << labelFail <<
"No commands added." <<
eoe;
656 CmdDef &cmddef = iter->second;
658 if( !cmddef.isDefined() )
696 CL_DBG_CALL_OUT_NL(
"rc=" << rc);
708 CL_DBG_CALL_IN(
"cmddef.uid=" << cmddef.
getUid(),
" ***" << endl);
712 m_log << labelCompile <<
"cmddef " << cmddef.
getUid()
727 else if( tokcnt == 0 )
730 <<
"cmddef " << cmddef.
m_nUid <<
", " 731 <<
"form " << form.
getIndex() <<
": No syntax specified." <<
eoe;
748 m_log << labelFail <<
"Could not compile." <<
eoe;
751 CL_DBG_CALL_OUT_NL(
"rc=" << rc);
763 CmdDef &cmddef_i = iter->second;
767 for(++jter; jter !=
m_cmdDefs.end(); ++jter)
769 CmdDef &cmddef_j = jter->second;
773 m_log << labelSyntax <<
"Duplicate command names found at uid's " 774 << cmddef_i.
getUid() <<
" and " << cmddef_j.
getUid() <<
"." 804 LOGERROR_STREAM(
"Data section '" << ns <<
"' already exist - cannot add.");
815 LOGERROR_STREAM(
"No data section '" << ns <<
"' exist - cannot remove.");
820 LOGERROR_STREAM(
"Reserved data section '" << ns <<
"' cannot be removed.");
834 return pos !=
m_dataSects.end()? pos->second.data(): NULL;
858 if( ((rc =
readCommand(fp, extargv)) ==
AOk) && (extargv.size() > 0) )
860 uid = extargv[0].uid();
861 iform = extargv[0].formIndex();
863 toVec(extargv, argv);
884 m_log << labelNoExec <<
"No commands added to interface." <<
eoe;
888 else if( !isDefined() )
890 m_log << labelNoExec <<
"Commands not fully compiled." <<
eoe;
898 if( fileno(fp) == fileno(stdin) )
917 if( argv.size() > 0 )
921 <<
"(" << argv[0].uid() <<
"), form " 922 << argv[0].formIndex() <<
" matched.");
927 m_log << labelFail <<
"Input not matched to any command." <<
eoe;
929 LOGDIAG3(
"No command matched to input.");
940 bool CommandLine::kbhit(FILE *fp)
943 struct termios ctio, ntio;
945 struct timeval timeout;
949 if( tcgetattr(fd, &ctio) < 0 )
957 ntio.c_lflag &= ~ICANON;
958 ntio.c_lflag &= ~ECHO;
960 ntio.c_cc[VTIME] = 0;
963 if( tcsetattr(fd, TCSANOW, &ntio) < 0 )
973 timeout.tv_sec = (time_t)0;
974 timeout.tv_usec = (time_t)10;
976 bAvail = select(fd+1, &fdset, NULL, NULL, &timeout) > 0?
true:
false;
979 tcsetattr(fd, TCSANOW, &ctio);
990 if( argv.size() == 0 )
1015 return pos->second.execute(argv);
1023 if( argv.size() == 0 )
1036 return pos->second.execute(*
this, argv);
1094 if( strLine.empty() )
1111 else if( argc == 0 )
1122 rc =
match(tokens, argv);
1136 double fPenultFitness;
1146 if( tokens.size() == 0 )
1148 LOGERROR(
"Bug: No tokens.");
1154 fPenultFitness = fUltFitness = 0.0;
1155 uid2nd = uidUlt =
NoUid;
1156 iform2nd = iformUlt =
NoIndex;
1165 rc =
matchCommand(iter->second, tokens, argvCmd, fFitness);
1180 if( fFitness > fUltFitness )
1182 fPenultFitness = fUltFitness;
1184 iform2nd = iformUlt;
1187 fUltFitness = fFitness;
1188 uidUlt = iter->second.getUid();
1189 iformUlt = argv[0].formIndex();
1193 else if( fFitness > fPenultFitness )
1195 fPenultFitness = fFitness;
1196 uid2nd = iter->second.getUid();
1197 iform2nd = argvCmd[0].formIndex();
1204 if( uidUlt ==
NoUid )
1212 m_log << labelSyntax <<
"Command " << tokens[0] <<
" not found." <<
eoe;
1220 else if( fUltFitness == fPenultFitness )
1222 m_log << labelNoMatch
1223 <<
"Command '" << tokens[0] <<
"' ambiguous. Matches:" 1254 if( tokens.size() == 0 )
1256 LOGERROR(
"Bug: No tokens.");
1272 if( cmddef.
at(0).
at(0).
match(tokens[0].value()) == 0.0 )
1285 if( fFitness > fMaxFitness )
1288 fMaxFitness = fFitness;
1293 m_log << labelFit << fFitness <<
eoe;
1295 if( fMaxFitness >= 1.0 )
1307 <<
"Command '" << cmddef.
getName()
1308 <<
"', form " << iBest <<
": Fitness " << fMaxFitness
1310 fFitness = fMaxFitness;
1319 m_log << labelNoMatch
1320 <<
"Command '" << cmddef.
getName()
1334 int argcToks = (int)tokens.size();
1336 double fWeight, fDecay;
1352 if( argcToks > argcForm )
1354 m_log << labelNoMatch
1355 <<
"Command '" << strCmdName <<
"', " 1356 <<
"form " << form.
getIndex() <<
": " 1357 <<
"Too many arguments: " 1358 << argcToks <<
" specified, " 1359 << argcForm <<
" maximum." 1369 m_log << labelNoMatch
1370 <<
"Command '" << strCmdName <<
"', " 1371 <<
"form " << form.
getIndex() <<
": " 1372 <<
"Missing required arguments: " 1373 << argcToks <<
" specified, " 1382 for(iArg = 0, iTok = 0, rc =
AOk;
1383 (iArg < argcForm) && (iTok < argcToks) && (rc ==
AOk);
1392 if( fWeight == 0.0 )
1397 m_log << labelNoMatch
1398 <<
"Input argument " << tokens[iTok] <<
" doesn't match " 1399 <<
"command '" << strCmdName <<
"', " 1400 <<
"form " << form.
getIndex() <<
", " 1412 m_log << labelBlank <<
" Not one of: " 1422 m_log << labelBlank <<
" Not a " 1424 <<
"' type." <<
eoe;
1429 m_log << labelBlank <<
" Not a " 1440 m_log << labelBlank <<
" Failed to match re: " 1441 <<
"'" << argdef.
getRegEx() <<
"'." 1447 LOGERROR(
"Bug: Unknown type %d.", argdef.
getType());
1459 <<
"Input argument " << tokens[iTok] <<
" matches " 1460 <<
"cmd '" << strCmdName <<
"', " 1461 <<
"form " << form.
getIndex() <<
", " 1462 <<
"arg " << argdef.
getIndex() <<
" " 1469 if( fWeight == 1.0 )
1471 fFitness += fWeight;
1475 fFitness += fWeight * fDecay;
1486 else if( argdef.
isOptional() && (iArg < argcForm-1) )
1501 fFitness /= (double)argcToks;
1531 for(
size_t i = 0; i < v1.size(); ++i)
1533 v2.push_back(v1[i].arg());
1598 const string &strText,
1600 const string &strContext,
1605 if( pAppArg != NULL )
1607 return ((
CommandLine *)pAppArg)->rlGenerator(strText, nIndex, strContext,
1608 nStart, nEnd, uFlags);
1618 const string &strContext,
1623 static vector<CmdArgDef*> argdefs;
1639 rlArgDefs(strContext.substr(0, nStart), argdefs);
1642 rlTabList(strText, argdefs, tabList, uFlags);
1644 if( nIndex < tabList.size() )
1646 return tabList[nIndex];
1655 vector<CmdArgDef*> &argdefs)
1658 vector<CmdArgDef*> v[2];
1675 for(j = 0; j < iter->second.numOfForms(); ++j)
1678 v[tog0].push_back(&form.
argAt(0));
1685 for(argc = 0; argc < tokens.size(); ++argc)
1689 for(i = 0; i < v[tog0].size(); ++i)
1700 v[tog1].push_back(&form.
argAt(argc+1));
1706 tog1 = (tog1 + 1) % 2;
1710 for(i = 0; i < v[tog0].size(); ++i)
1712 argdefs.push_back(v[tog0][i]);
1717 vector<CmdArgDef*> &argdefs,
1723 set<string>::iterator iter, jter;
1734 if( argdefs.size() == 0 )
1740 len = strText.size();
1747 for(i = 0; i < argdefs.size(); ++i)
1749 switch( argdefs[i]->getType() )
1753 for(j = 0; j < argdefs[i]->numOfLiterals(); ++j)
1755 str = argdefs[i]->literalAt(j);
1798 A.insert(argdefs[i]->constructSyntax());
1805 uFlags &= ~
ReadLine::FlagTabNoFilename;
1823 size_t min = iter->size();
1825 for(; (jter != A.end()) && (min > 0); ++iter, ++jter)
1827 j =
gcss(*iter, *jter);
1840 A.insert(str.substr(0, min));
1848 for(iter = A.begin(); iter != A.end(); ++iter)
1850 tabList.push_back(*iter);
1854 if( tabList.size() > 1 )
1861 const string strLiteral,
1870 return strText == strLiteral.substr(0, uLen);
1886 return at(strName).isDefined();
1909 if( iter->second.getName() == strName )
1911 return iter->second;
1938 if( iter->second.getName() == strName )
1940 return iter->second;
1975 CL_DBG_CALL_IN(
"\"" << strInput <<
"\"", endl);
1979 len = strInput.length();
1981 for(cursor = 0; (cursor >= 0) && (cursor < len); )
1984 while( (cursor < len) && isspace((
int)strInput[cursor]) )
2004 cursor =
lexWord(strInput, cursor, tokens);
2008 #ifdef CL_ENABLE_DEBUG 2012 for(
size_t i = 0; i < tokens.size(); ++i)
2014 ss << sep << tokens[i];
2017 CL_DBG_CALL_OUT_NL(ss.str());
2019 #endif // CL_ENABLE_DEBUG 2021 return cursor >= 0? (ssize_t)tokens.size(): cursor;
2034 for(i = 0; i < cnt; ++i)
2036 tokens.push_back(tokenz[i].value());
2048 CL_DBG_CALL_IN(
"\"" << strSyntax <<
"\", tokens", endl);
2052 len = strSyntax.length();
2054 for(cursor = 0; (cursor >= 0) && (cursor < len); )
2057 while( (cursor < len) && isspace((
int)strSyntax[cursor]) )
2078 pushToken(strSyntax, start, cursor, tokens);
2088 #ifdef CL_ENABLE_DEBUG 2092 for(
size_t i = 0; i < tokens.size(); ++i)
2094 ss << sep << tokens[i];
2097 CL_DBG_CALL_OUT_NL(ss.str());
2099 #endif // CL_ENABLE_DEBUG 2101 return cursor >= 0? (ssize_t)tokens.size(): cursor;
2111 len = strSyntax.length();
2115 while( (cursor < len) &&
2116 !isspace((
int)strSyntax[cursor]) &&
2122 if( cursor > start )
2124 pushToken(strSyntax, start, cursor, tokens);
2129 m_log << labelSyntax <<
"No <word> found." <<
eoe;
2149 len = strSyntax.length();
2159 pushToken(strSyntax, start, cursor, tokens);
2167 m_log << labelSyntax <<
"No starting '(' found." <<
eoe;
2172 while( (cursor >= 0) && (cursor < len) && !eop )
2174 switch( strSyntax[cursor] )
2203 value.push_back(strSyntax[cursor++]);
2210 pushToken(strSyntax, start, cursor, tokens);
2214 pushToken(strSyntax, start, cursor, tokens);
2221 m_log << labelSyntax <<
"No ending ')' found." <<
eoe;
2234 len = strInput.length();
2237 while( (cursor < len) && !isspace((
int)strInput[cursor]) )
2242 if( cursor > start )
2244 pushToken(strInput, start, cursor, tokens);
2249 m_log << labelSyntax <<
"No <word> found." <<
eoe;
2267 len = strInput.length();
2277 m_log << labelSyntax <<
"No starting double qoute '\"' found." <<
eoe;
2284 while( (cursor >= 0) && (cursor < len) && !eos )
2289 switch( strInput[cursor] )
2309 if( (i < len) && isxdigit(strInput[i]) )
2311 c =
tohex(strInput[i]);
2314 if( (i < len) && isxdigit(strInput[i]) )
2317 c |=
tohex(strInput[i]);
2328 c = strInput[cursor];
2339 switch( strInput[cursor] )
2348 value.push_back(strInput[cursor++]);
2356 pushToken(strInput, start, cursor, tokens);
2365 m_log << labelSyntax <<
"No ending double qoute '\"' found." <<
eoe;
2372 const ssize_t cursor,
2378 pushToken(strSource, start, cursor, tokens);
2379 tokens.back().printAnnotated(ss, strSource);
2380 m_log << labelAt << ss.str() <<
eoe;
2385 const ssize_t cursor,
2388 Token tok(strSource.substr(start, cursor-start),
2390 tokens.push_back(tok);
2402 size_t tokcnt = tokens.size();
2407 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, 0, endl);
2410 <<
"cmddef " << cmddef.
getUid() <<
", " 2411 <<
"form " << form.
getIndex() <<
": " 2418 m_log << labelFail <<
"Parssing special argv0." <<
eoe;
2425 m_log << labelFail <<
"Parsing required argument list." <<
eoe;
2432 m_log << labelFail <<
"Parsing optional argument list." <<
eoe;
2437 else if( pos < tokcnt )
2440 <<
"Extraneous tokens found after optional arguments." 2448 m_log << labelParse <<
"Ok" <<
eoe;
2450 <<
"uid=" << cmddef.
getUid() <<
", " 2451 <<
"name=" << cmddef.
getName() <<
", " 2452 <<
"form=" << form.
getIndex() <<
", " 2454 <<
"successfully parsed.");
2465 CL_DBG_CALL_OUT_NL(
"rc=" << rc <<
", " <<
okstr(bOk) <<
", pos=" << pos);
2478 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2480 if( pos < tokens.size() )
2482 if(
peekEq(
"<", tokens[pos]) )
2493 m_log << labelSyntax <<
"Command argument not found in form " 2519 if( cmddef.
getName().empty() )
2524 else if( cmddef.
getName() != strName )
2526 m_log << labelSyntax <<
"Expected command name '" << cmddef.
getName()
2527 <<
"', but found '" << strName <<
"' in form " << form.
getIndex()
2535 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2547 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2549 while( bOk && (pos < tokens.size()) )
2552 if(
peekEq(
"[", tokens[pos]) )
2558 else if( (bOk =
parseArg(cmddef, form, tokens, pos)) )
2564 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2576 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2578 while( bOk && (pos < tokens.size()) )
2581 if( !
peekEq(
"[", tokens[pos]) )
2587 if(
tokEq(
"[", tokens, pos) &&
2588 parseArg(cmddef, form, tokens, pos) &&
2589 tokEq(
"]", tokens, pos) )
2600 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2612 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2614 if( pos < tokens.size() )
2616 if(
peekEq(
"{", tokens[pos]) )
2620 else if(
peekEq(
"<", tokens[pos]) )
2631 m_log << labelSyntax <<
"Command argument not found." <<
eoe;
2636 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2650 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2654 bOk =
tokEq(
"{", tokens, pos) &&
2656 tokEq(
"}", tokens, pos);
2669 for(
size_t i = 0; i < literals.size(); ++i)
2675 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2692 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2696 bOk =
tokEq(
"<", tokens, pos) &&
2702 if(
peekEq(
":", tokens[pos]) )
2704 bOk =
tokEq(
":", tokens, pos) &&
2705 parseVarMod(cmddef, form, tokens, pos, eType, ranges, re);
2714 bOk = bOk &&
tokEq(
">", tokens, pos);
2724 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2738 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2756 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2771 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2773 while( more && bOk && (pos < tokens.size()) )
2775 if(
peekEq(
"}", tokens[pos]) )
2777 m_log << labelSyntax <<
"Expected literal value but found '}'." <<
eoe;
2784 literals.push_back(strValue);
2787 if(
peekEq(
"|", tokens[pos]) )
2789 bOk =
tokEq(
"|", tokens, pos);
2800 m_log << labelSyntax <<
"No literal value found." <<
eoe;
2805 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", pos=" << pos);
2818 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2822 if( pos < tokens.size() )
2824 strIdent = tokens[pos].value();
2829 m_log << labelSyntax <<
"No identifier found." <<
eoe;
2834 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", identifier='" << strIdent
2835 <<
"', pos=" << pos);
2850 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos, endl);
2856 if(
peekEq(
"(", tokens[pos]) )
2862 bOk =
tokEq(
"(", tokens, pos) &&
2864 tokEq(
")", tokens, pos);
2867 bOk =
tokEq(
"(", tokens, pos) &&
2869 tokEq(
")", tokens, pos);
2872 m_log << labelSyntax
2873 <<
"Unexpected '(' token found for argument type " 2882 CL_DBG_CALL_OUT_NL(
okstr(bOk) <<
", type=" << eType <<
", pos=" << pos);
2895 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos,
" ");
2899 if( pos < tokens.size() )
2910 m_log << labelSyntax <<
"Unknown variable type '" << tokens[pos].value()
2919 m_log << labelSyntax <<
"No variable type found." <<
eoe;
2924 CL_DBG_CALL_OUT_IL(
okstr(bOk) <<
", type=" << eType <<
", pos=" << pos);
2940 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos,
" ");
2944 if( pos < tokens.size() )
2946 split(tokens[pos].value(),
',', subranges);
2948 for(
size_t i = 0; bOk && (i < subranges.size()); ++i)
2952 split(subranges[i],
':', minmax);
2954 if( minmax.size() == 0 )
2956 m_log << labelSyntax <<
"No 'min[:max]' subrange found in " 2957 <<
"'" << tokens[pos].value() <<
"'.'" 2962 else if( minmax.size() > 2 )
2964 m_log << labelSyntax <<
"Too many 'min:max:?' subrange values found in " 2965 <<
"'" << tokens[pos].value() <<
"'.'" 2973 m_log << labelSyntax <<
"Subrange min '" << minmax[0] <<
"' NaN in " 2974 <<
"'" << tokens[pos].value() <<
"'.'" 2980 if( minmax.size() == 2 )
2984 m_log << labelSyntax <<
"Subrange max '" << minmax[1] <<
"' NaN in " 2985 <<
"'" << tokens[pos].value() <<
"'.'" 3006 ranges.push_back(r);
3011 if( bOk && (ranges.size() == 0) )
3013 m_log << labelSyntax <<
"Range expression not found." <<
eoe;
3026 CL_DBG_CALL_OUT_IL(
okstr(bOk) <<
", numranges=" << ranges.size()
3027 <<
", pos=" << pos);
3040 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos,
" ");
3042 if( pos < tokens.size() )
3049 re = tokens[pos++].value();
3057 m_log << labelSyntax <<
"Regular expression '" 3068 m_log << labelSyntax <<
"Regular expression not found." <<
eoe;
3073 CL_DBG_CALL_OUT_IL(
okstr(bOk) <<
", re='" << re.
getRegEx() <<
"', pos=" 3087 CL_DBG_PARSE_CALL_IN(cmddef, form, tokens, pos,
" ");
3091 if( pos < tokens.size() )
3093 strValue = tokens[pos++].value();
3098 m_log << labelSyntax <<
"Literal value not found." <<
eoe;
3103 CL_DBG_CALL_OUT_IL(
okstr(bOk) <<
", value='" << strValue <<
"', " 3115 CL_DBG_CALL_IN(
"input, strcmp=\"" << strCmp <<
"\", " 3116 <<
"tokens, pos=" << pos,
" ");
3118 if( pos >= tokens.size() )
3120 m_log << labelSyntax <<
"Token " << pos <<
" '" << strCmp
3121 <<
"' does not exist." <<
eoe;
3126 else if( tokens[pos].value() != strCmp )
3128 m_log << labelSyntax <<
"Expected token '" << strCmp <<
"'" 3129 <<
", but found " << tokens[pos]
3141 CL_DBG_CALL_OUT_IL(
okstr(bOk) <<
", pos=" << pos);
3150 CL_DBG_CALL_IN(
"tokens=" << tokens.size() <<
", pos=" << pos,
" ");
3160 m_log << labelSyntax <<
"Invalid identifier " << tokens[pos] <<
eoe;
3164 CL_DBG_CALL_OUT_IL(
okstr(bOk) <<
", pos=" << pos);
3179 for(
size_t i = 0; i < tokens.size(); ++i)
3181 ss << sep <<
prettify(tokens[i].value());
3205 os <<
"CommandLine " << cl.
m_strName << endl;
3223 os <<
indent() <<
"{" << endl;
3229 os << sep << iter->second;
3237 os <<
indent() <<
"}" << endl;
3243 os <<
indent() <<
"{" << endl;
3250 os << sep << iter->second;
3258 os <<
indent() <<
"}" << endl;
3264 os <<
indent() <<
"{" << endl;
3271 os << sep << iter->second;
3279 os <<
indent() <<
"}" << endl;
int matchCommandForm(const CmdFormDef &form, const TokenVec &tokens, CmdExtArgVec &argv, double &fFitness)
Match command form against input line argument list.
CmdFormDef & formAt(const int nIndex)
Get command modifiable form at index.
argument has a mutually exclusive list
void popPrompt()
Pop prompt string from stack of prompts.
static const int ReFlagICase
ignore case when matching
std::ostream & printToMark(std::ostream &os, const std::string strMark, int endpt) const
Print the log book entires between the bookmark and the specified end point to the output stream...
Command line extended argument interface.
void reset()
Reset command definition to pre-compiled state.
const int EUnknownCmd
unknown, unmatched command
int matchCommand(const CmdDef &cmddef, const TokenVec &tokens, CmdExtArgVec &argv, double &fFitness)
Match best command form against input line argument list.
std::ostream & printLog(std::ostream &os) const
Print the entire log book to the output stream.
Command EXTended ARGument class holding parsed command context and the raw and converted argmument va...
no filename TAB completion attempt
int checkReadResult()
Check read input result.
virtual ~CommandLine()
Destructor.
CmdExecMap::iterator CmdExecIter
exec iterator type
std::vector< std::string > StringVec
Useful types.
std::string & rlreadLine()
Interactively read a line of input from standard input (stdin).
std::string m_strName
name of this command line
static std::string c14n(const TokenVec &tokens)
Canonicalization of a string.
#define LOGDIAG2_STREAM(args)
Diagnostic level 2 stream logging.
virtual ssize_t tokenizeInput(const std::string &strInput, TokenVec &tokens)
Lexically analyze input string to generate a series of tokens.
int getUid() const
Get command's unique id.
virtual int execute(const str::StringVec &argv)
Execute a comamnd with the given arguments.
void toVec(const CmdExtArgVec &v1, str::StringVec &v2)
Convert extended argument vector to string argument vector.
floating point number (double)
int removeDataSection(const std::string &ns)
Remove a data section from the command-line interface.
CmdDefMap::const_iterator CmdDefCIter
cmd const iter type
static bool isoparen(int c)
Test if c is a open parenthesis character.
double match(const std::string &strArg, const bool bIgnoreCase=false) const
Match argument string against argument definition pattern.
int m_nUid
command unique id
virtual int rlBuildReadLineGenerator()
Perform any necessary pre-processing to prepare for command line TAB completion.
LogBook m_log
trace and error log
std::string constructLiteralList(const std::string sep=" ") const
Construct literal list string.
void registerAltGenerator(AltAppGenFunc fnAltAppGen, void *pAppArg)
Register alternate application-specific tab-completion generator.
osManipIndent indent()
Left indent at current stream indentation level.
virtual const std::string rlGenerator(const std::string &strText, int nIndex, const std::string &strContext, int nStart, int nEnd, unsigned &uFlags)
TAB completion generator.
std::string synopsis
short command synopsis
ReadLine m_readline
readline interface
Command line interface data section class.
int match(const TokenVec &tokens, CmdExtArgVec &argv)
Match the input tokens to the compiled commands to find the best fit.
void setRanges(const RangeVec &ranges)
Set numeric range values.
const char *const DataSectNsNet
network data section ns
const int EAmbigCmd
ambiguous command
bool parseVarRegExpr(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, RegEx &re)
Parse variable regular expression.
virtual ssize_t tokenizeSyntax(const std::string &strSyntax, TokenVec &tokens)
Lexically analyze extened usage syntax string to generate a series of tokens.
size_t getLineNum() const
Get the line number of the last read line.
std::string longdesc
long command description
bool m_bIsCompiled
has [not] been successfully compiled
bool getBtEnable() const
Test if backtracing is enabled.
std::string lowercase(const std::string &str)
Convert in-place string to lower case.
static char tohex(int c)
Convert ascii character to binary character value.
void clear()
Clear the log book and bookmarks, along with any pending entry.
static bool isdquote(int c)
Test if c is a double quote character.
static bool iscparen(int c)
Test if c is a close parenthesis character.
static void dealloc(void *p)
Deallocate (delete) allocated (new) core data section.
Variant m_variant
function variant enum
virtual int removeCommand(const int uid)
Remove command from command line interface.
bool peekEq(const std::string strCmp, const Token &token) const
Peek if token is equal to string.
const char *const DataSectNsCore
Reserved command line data section namespaces.
const CmdFormDef & at(const int nIndex) const
Get command form at index.
virtual ssize_t lexQuotedString(const std::string &strInput, ssize_t cursor, TokenVec &tokens)
Quoted string lexical analyzer.
osManipIndent setindent(const long nIndent)
Set absolute indentation level.
const char * TruthHood[]
strings that equate to true
Number minimum and maximum (sub)range.
int formIndex() const
Get the argument's associated parsed form definition index.
Command argument compiled definition class.
int(* CmdExec2Func)(const CmdExtArgVec &argv)
Command execution function type, variant 2.
const std::string & getArgName(const CmdExtArg &arg) const
Get the argument name.
void pushPrompt(const std::string &strPrompt)
Push prompt string onto stack of prompts.
virtual int compile()
Compile all added commands.
no space(' ') after TAB completion
const std::string & getRegEx() const
Get the pre-compiled regular expression.
const int NoUid
Special values.
bool haveRlLib() const
Test if have readline library.
int numOfCmds() const
Get the total number of added commands.
const int EError
general, unspecified error
Of string spaces and their strangian operators.
void addLiteralValue(const std::string &strValue)
Add literal value to list of argument values.
void rlArgDefs(const std::string &strSubtext, std::vector< CmdArgDef * > &argdefs)
Build list of all command argument definitions that match completed subtext.
User available command description structure.
int m_uid
command unique id associated with this execution
int numOfArgs(int uid, int iform) const
Get the total number of arguments.
size_t split(const std::string &str, const char delim, StringVec &elems)
Split string.
int uid() const
Get the argument's associated parsed command unique id.
bool parseArgv0(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse argument 0 (command name) syntax.
std::ostream & backtrace(std::ostream &os, const bool bAll=false) const
Insert trace and error log backtrace into output stream.
void orFlags(const unsigned uFlags)
Or flags into argment modifier flags.
virtual void logLexToken(const std::string &strSource, const size_t start, const ssize_t cursor, TokenVec &tokens, const bool bLoc=false)
Log lexigraphical token.
int todouble(const std::string &str, double &val)
Convert string to a double-precision floating-point number.
const std::string & literalAt(const int nIndex) const
Get literal value at index.
static CmdDef nocmddef
"no cmd def" command definition
const CmdDef & at(const int uid) const
Get the command definition with the unique id.
void * m_pData
pointer to section data
void setType(const ArgType eType)
Set argument's type.
int getParentFormIndex() const
Get parent command form's index.
std::string prettify(const std::string &str)
Prettify string.
std::vector< Token > TokenVec
vector of tokens type
Compiled command definition class.
CmdArgDef::ArgType getArgDefType(const CmdExtArg &arg) const
Get the argument type.
virtual int parseSyntax(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens)
Parse command syntax.
int finalize()
Finalize command compilation.
static const std::string lookupArgSymbol(const CmdArgDef::ArgType eType)
Look up argument symbol, given argument type.
Command line interface class interface.
std::vector< CmdExtArg > CmdExtArgVec
vector of ext args type
CmdExecMap m_cmdExecs
map of added command executions
virtual int addCommand(const CmdDesc &desc)
Add a command to the command line interface.
bool parseOptionalArgList(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse optional argument list syntax.
virtual ssize_t lexSyntaxParenExpr(const std::string &strSyntax, ssize_t cursor, TokenVec &tokens)
Syntax parenthetical expression lexical analyzer.
virtual ssize_t lexWord(const std::string &strInput, ssize_t cursor, TokenVec &tokens)
Word lexical analyzer.
static bool isesc(int c)
Testif c is an escape character.
std::string m_strSyntax
parsable command extended usage syntax
CmdExtArg convert(const std::string &strArg, const bool bIgnoreCase=false) const
Convert argument string to type.
bool parseVarRangeExpr(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, CmdArgDef::RangeVec &ranges)
Parse variable range expression.
int numOfRequiredArgs(int uid, int iform) const
Get the total number of required arguments.
CmdDefMap::iterator CmdDefIter
cmd iterator type
bool parseRequiredArgList(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse required argument list syntax.
static const string noprompt
"no prompt" prompt value
DeallocFunc m_fnDealloc
data deallocator function
bool parseVariableArg(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse variable argument syntax.
FnVar m_exec
function execution variant
bool tokIdentifier(const TokenVec &tokens, size_t &pos)
Test if string has valid identifier syntax.
LogBook & eoe(LogBook &log)
LogBook end-of-entry stream manipulator.
Stream I/O manipulators and helpers.
const int ENoExec
cannot execute
int getParentCmdUid() const
Get parent command's unique id.
const int ERead
read error
The thin ReadLine wrapper class interface.
std::string m_strNs
data section namespace
#define LOGDIAG3_STREAM(args)
Diagnostic level 3 stream logging.
const int EBadSyntax
bad syntax
const std::string & getErrorStr() const
Get the last RegExs operation error string.
CmdDef & cmdAt(const int uid)
Get modifiable command definition with the given unique id.
const int NoIndex
no index
const int AOk
(0) A-Ok, no error, success, good
bool isOptional() const
Test if argument is an optional argument.
Command line command definition class interface.
Helper class to hold a command line execution function.
bool parseVarMod(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, CmdArgDef::ArgType &eType, CmdArgDef::RangeVec &ranges, RegEx &re)
Parse variable modifier.
const int EBadVal
bad value
int numOfOptionalArgs(int uid, int iform) const
Get the total number of optional arguments.
ArgType
Argument type enumeration.
#define LOGERROR_STREAM(args)
Error stream logging.
LogBook & bookmark(LogBook &log)
LogBook bookmark stream manipulator.
Command line argument definition class interface.
DataSectMap::iterator DataSectIter
iterator type
static const int NEWEST
newest, most recent entries
void setName(const std::string &strName)
Set command's name.
int(* CmdExec3Func)(CommandLine &cli, const CmdExtArgVec &argv)
Command execution function type, variant 3.
int(* CmdExec1Func)(const str::StringVec &argv)
Command execution function type, variant 1.
virtual int readCommand(int &uid, int &iform, str::StringVec &argv)
Read an input line from stdin and match to the best compiled command.
void setRegEx(const RegEx &re)
Set regular expression value.
PromptStack m_prompts
stack of prompt strings
const std::string & getName() const
Return command's name.
void pushForm(CmdFormDef &formdef)
Push new command form to end of form list.
identifier (C conforming)
ArgType getType() const
Get argument's type.
virtual ssize_t lexSyntaxWord(const std::string &strSyntax, ssize_t cursor, TokenVec &tokens)
Syntax word lexical analyzer.
std::string okstr(bool b)
Convert boolean to "ok" or "not-ok".
bool rlPartialMatch(const std::string &strText, const std::string strLiteral, const size_t uLen)
Match partial text agains literal string.
const char *const DataSectNsOS
OS data section ns.
const std::string & getName() const
Get argument's name.
void setUid(const int uid)
Set command's unique id.
CmdExecMap::const_iterator CmdExecCIter
exec const iter type
bool parseLiteralArg(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse literal, fixed-valued argument syntax.
bool useRlLib() const
Test if the readline library is enabled.
ReadLine class provides a C++ wrapper around the readline C library.
void(* DeallocFunc)(void *)
const int EArgv0
not this command argv0
Logging facitlities built on librnr log.h macros to support C++ output insertion streaming.
bool isFError() const
Test if the last read operation resulted in an I/O error condition.
Command line core data types.
bool parseXorListArg(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse mutually exclusive argument values syntax.
static const char * RlTabEnd
no more matches value (empty string)
int argIndex() const
Get the argument's associated parsed argument definition index.
static bool isspecial(int c)
Command usage syntax special characters.
no default TAB completion match
bool hasCmd(const int uid) const
Test if command exists.
bool parseXorList(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, str::StringVec &literals)
Parse mutually exclusive list.
std::vector< range > RangeVec
vector of subranges
static const std::string rlGeneratorWrapper(void *pAppArg, const std::string &strText, int nIndex, const std::string &strContext, int nStart, int nEnd, unsigned &uFlags)
Static TAB completion generator wrapper.
virtual int removeAllCommands()
Remove all commands from command line interface.
const std::string & getPrompt() const
Get the current prompt string.
void setPrompt(const std::string &strPrompt)
Set the prompt string.
int numOfForms() const
Get the total number command forms.
const std::string & getName() const
Get command line interface's name.
bool isIdentifier(const std::string &str)
Test if string is a valid identifier.
static CmdArgDef::ArgType lookupArgType(const std::string strSymbol)
Look up argument type, given argument type symbol.
osManipIndent deltaindent(const long nDelta)
Set relative delta indentation level.
Parsed token container class.
bool parseVarType(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, CmdArgDef::ArgType &eType)
Parse variable type.
The Regular Expression Class interface.
std::string constructRangeList(const std::string sep=",") const
Construct ranges string.
std::string & ireadLine()
Interactively read a line of input from standard input (stdin).
const RangeVec & getRanges() const
Get numeric range values.
void rlTabList(const std::string &strText, std::vector< CmdArgDef * > &argdefs, str::StringVec &tabList, unsigned &uFlags)
Build TAB completion list and set appropriate readline modifiers.
DataSectMap::const_iterator DataSectCIter
const iter type
const std::string & lastText() const
Get the last (latest) log entry text.
bool isEoF() const
Test if the last read operation resulted in an end-of-file condition.
DataSectMap m_dataSects
data sections
std::string c14n(const std::string &str)
Simple canonicalization of a string.
int addDataSection(const std::string &ns, void *pData, DataSect::DeallocFunc fn=NULL)
Add a data section to the command-line interface.
bool m_bIgnoreCase
do [not] ignore case on commands
int m_nUidCnt
unique id counter
std::string syntax
parsable command extended usage syntax
bool isValid() const
Test if in a valid state (i.e. compiled).
any (quoted) character sequence
const std::string & getErrorStr() const
Get the most recent error.
bool tokEq(const std::string strCmp, const TokenVec &tokens, size_t &pos)
Test if token at position is equal to string.
virtual void addToHistory(const str::StringVec &argv)
Add command to history.
std::ostream & operator<<(std::ostream &os, const timespec &obj)
A timespec insertion operator.
size_t gcss(const std::string &str1, const std::string &str2, const size_t pos=0)
Find the length of the Greatest Common SubString.
bool parseIdentifier(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, std::string &strIdent)
Parse identifier.
int getIndex() const
Get argument's command line index.
const std::string & getRegEx() const
Get regular expression value.
bool parseArg(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos)
Parse argument syntax.
void setFlags(int nFlags)
Set new compile behavior flags.
void setName(const std::string &strName)
Set argument's name.
const std::string emptystring
"" empty string
Simple, token container class interface.
int processInput(const std::string &strLine, CmdExtArgVec &argv)
Process a line of input.
CmdDefMap m_cmdDefs
map of added command definitions
void pushToken(const std::string &strSource, const size_t start, const ssize_t cursor, TokenVec &tokens)
Push token to the end of the generated tokens.
bool isReservedDataSection(const std::string &ns) const
Test if the namespace is a command-line interface reserved name.
const char * FalseHood[]
Falsehood and truthhood strings. Each list termintate with a NULL.
const int EEoF
end of file
bool parseLiteralValue(CmdDef &cmddef, CmdFormDef &form, const TokenVec &tokens, size_t &pos, std::string &strValue)
Parse literal value.
any non-whitespace contiguous char sequence
void * getDataSection(const std::string &ns)
Get the section data under the specified namespace.
const std::string & getErrorStr() const
Get the most recently set error string.