00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "CATCmdLine.h"
00014
00015 CATCmdArg::CATCmdArg(CATWChar cmdSwitch)
00016 {
00017 fSwitch = cmdSwitch;
00018 fArg = 0;
00019 }
00020
00021 CATCmdArg::~CATCmdArg()
00022 {
00023 if (fArg)
00024 {
00025 delete [] fArg;
00026 fArg = 0;
00027 }
00028 }
00029
00030 void CATCmdArg::SetArg( const CATWChar* argument )
00031 {
00032 if (fArg)
00033 {
00034 delete [] fArg;
00035 fArg = 0;
00036 }
00037
00038 if (argument)
00039 {
00040 fArg = new CATWChar[wcslen(argument)+1];
00041 wcscpy(fArg,argument);
00042 }
00043 }
00044
00045 const CATWChar* CATCmdArg::GetArg()
00046 {
00047 return fArg;
00048 }
00049
00050 CATWChar CATCmdArg::GetSwitch()
00051 {
00052 return fSwitch;
00053 }
00054
00055
00056 CATCmdLine::CATCmdLine()
00057 {
00058 fSwitchFlags = 0;
00059 fStringTable = 0;
00060 fLangId = CATLANG_EN;
00061 fPrefaceId = CAT_STR_EMPTY;
00062 fInitialized = false;
00063 }
00064
00065 CATCmdLine::~CATCmdLine()
00066 {
00067 if (fInitialized)
00068 {
00069 Uninitialize();
00070 }
00071 }
00072
00073 CATResult CATCmdLine::Initialize( CATResult prefaceId,
00074 const CATCMDLINEARG* cmdTable,
00075 CATStringTable* stringTable,
00076 CATLangId languageId)
00077 {
00078 if (fInitialized)
00079 {
00080 Uninitialize();
00081 }
00082
00083 fStringTable = stringTable;
00084 fPrefaceId = prefaceId;
00085 fLangId = languageId;
00086
00087
00088 if (cmdTable != 0)
00089 {
00090 CATCMDLINEARG* cmdTablePtr = (CATCMDLINEARG*)&cmdTable[0];
00091 while (cmdTablePtr->CmdSwitch != (CATWChar)-1)
00092 {
00093 fCmdTable.push_back(*cmdTablePtr);
00094
00095 ++cmdTablePtr;
00096 }
00097 }
00098
00099 fInitialized = true;
00100 return CATRESULT(CAT_SUCCESS);
00101 }
00102
00103 void CATCmdLine::Uninitialize()
00104 {
00105 fCmdTable.clear();
00106
00107 fStringTable = 0;
00108 fLangId = CATLANG_EN;
00109 fPrefaceId = CAT_STR_EMPTY;
00110
00111
00112 CATInt32 i;
00113 CATInt32 numEntries = (CATInt32)fOperands.size();
00114 for (i = 0; i < numEntries; i++)
00115 {
00116 delete [] fOperands[i];
00117 }
00118 fOperands.clear();
00119
00120
00121 numEntries = (CATInt32)fArguments.size();
00122 for (i = 0; i < numEntries; i++)
00123 {
00124 delete fArguments[i];
00125 }
00126 fArguments.clear();
00127
00128
00129 fInitialized = false;
00130 }
00131
00132
00133
00134 CATResult CATCmdLine::Parse( CATInt32 argc,
00135 CATWChar** argvw)
00136 {
00137 fSwitchFlags = 0;
00138 CATResult parseValid = CATRESULT(CAT_SUCCESS);
00139 CATCmdArg* curCmd = 0;
00140
00141 for (CATInt32 i = 0; i < argc; i++)
00142 {
00143 if (curCmd)
00144 {
00145
00146 curCmd->SetArg(argvw[i]);
00147 curCmd = 0;
00148 }
00149 else if ((*argvw[i] == '/') || (*argvw[i] == '-'))
00150 {
00151
00152 CATInt32 numSwitches = (CATInt32)wcslen(argvw[i]);
00153 if (numSwitches > 1)
00154 {
00155
00156 for (CATInt32 switchIdx = 1; switchIdx < numSwitches; switchIdx++)
00157 {
00158 CATWChar curSwitch = argvw[i][switchIdx];
00159 curCmd = new CATCmdArg(curSwitch);
00160 fArguments.push_back(curCmd);
00161
00162
00163
00164 for (CATInt32 cmdNum = 0;
00165 cmdNum < (CATInt32)fCmdTable.size(); ++cmdNum)
00166 {
00167 if (fCmdTable[cmdNum].CmdSwitch == curSwitch)
00168 {
00169 fSwitchFlags |= fCmdTable[cmdNum].SwitchFlag;
00170
00171 if (!fCmdTable[cmdNum].TakesArg)
00172 curCmd = 0;
00173 break;
00174 }
00175 }
00176 }
00177 }
00178 else
00179 {
00180
00181 curCmd = 0;
00182 if (CATSUCCEEDED(parseValid))
00183 parseValid = CATRESULT(CAT_ERR_CMD_INVALID_SWITCH);
00184 }
00185 }
00186 else
00187 {
00188
00189 CATWChar* newOperand = new CATWChar[wcslen(argvw[i])+1];
00190 wcscpy(newOperand,argvw[i]);
00191 fOperands.push_back(newOperand);
00192
00193
00194
00195 CATInt32 opNum = (CATInt32)fOperands.size() - 1;
00196
00197 CATInt32 curOpNum = 0;
00198
00199 for (CATInt32 cmdNum = 0;
00200 cmdNum < (CATInt32)fCmdTable.size(); ++cmdNum)
00201 {
00202 if (fCmdTable[cmdNum].CmdSwitch == 0)
00203 {
00204 if (opNum == curOpNum)
00205 {
00206 fSwitchFlags |= fCmdTable[cmdNum].SwitchFlag;
00207 break;
00208 }
00209 else
00210 {
00211 curOpNum++;
00212 }
00213 }
00214 }
00215
00216 }
00217 }
00218
00219 if (curCmd != 0)
00220 {
00221
00222 parseValid = CATRESULT(CAT_ERR_CMD_SWITCH_NO_ARG);
00223 }
00224
00225 if (CATFAILED(parseValid))
00226 return parseValid;
00227
00228
00229
00230
00231
00232
00233
00234
00235 size_t numCmds = fCmdTable.size();
00236 size_t cmdIndex = 0;
00237 CATUInt32 curOperand = 0;
00238 CATUInt32 lastValidCmdGroup = 0;
00239
00240 for (cmdIndex = 0; cmdIndex < numCmds; cmdIndex++)
00241 {
00242 if (fCmdTable[cmdIndex].Required)
00243 {
00244 if (fCmdTable[cmdIndex].CmdGroup != 0)
00245 {
00246 CATInt32 curGroup = fCmdTable[cmdIndex].CmdGroup;
00247
00248 if (curGroup != lastValidCmdGroup)
00249 {
00250
00251
00252 CATUInt32 numFound = 0;
00253 for (size_t i = 0; i < numCmds; i++)
00254 {
00255 if (fCmdTable[i].CmdGroup == curGroup)
00256 {
00257 if (fCmdTable[i].CmdSwitch != 0)
00258 {
00259 if (this->IsSwitchSet(fCmdTable[i].CmdSwitch))
00260 numFound++;
00261 }
00262 else
00263 {
00264
00265
00266
00267 if (this->GetOpByIndex(curOperand))
00268 {
00269 if (numFound == 0)
00270 numFound++;
00271 }
00272 }
00273 }
00274 }
00275
00276 if (numFound == 1)
00277 {
00278 lastValidCmdGroup = curGroup;
00279 }
00280 else if (numFound == 0)
00281 {
00282 parseValid = CATRESULT(CAT_ERR_CMDREQ_GROUP);
00283 }
00284 else
00285 {
00286 parseValid = CATRESULT(CAT_ERR_CMDREQ_EXCLUSIVE_GROUP);
00287 }
00288 }
00289 }
00290 else
00291 {
00292 if (fCmdTable[cmdIndex].CmdSwitch == 0)
00293 {
00294
00295 if (0 == this->GetOpByIndex(curOperand))
00296 {
00297 parseValid = CATRESULT(CAT_ERR_CMDREQ_OP);
00298 break;
00299 }
00300 }
00301 else
00302 {
00303
00304 if (!this->IsSwitchSet(fCmdTable[cmdIndex].CmdSwitch))
00305 {
00306 parseValid = CATRESULT(CAT_ERR_CMDREQ_SWITCH);
00307 break;
00308 }
00309 }
00310 }
00311 }
00312
00313
00314 if (fCmdTable[cmdIndex].CmdSwitch == 0)
00315 curOperand++;
00316 }
00317
00318 return parseValid;
00319 }
00320
00321
00322 CATResult CATCmdLine::PrintUsage(CATInt32 maxColumns)
00323 {
00324 CATResult result = CAT_SUCCESS;
00325
00326 if (!fStringTable)
00327 {
00328 return CATRESULT(CAT_ERR_CMD_NO_STRINGTABLE);
00329 }
00330
00331 const CATWChar* preface = fStringTable->GetString(fPrefaceId,fLangId);
00332
00333 if (preface)
00334 wprintf(L"%s\n",preface);
00335
00336 wprintf(L"\n%s\n\n",fStringTable->GetString(CAT_STR_USAGE,fLangId));
00337
00338 int curColumn = 0;
00339 int startColumn = 4;
00340
00341
00342
00343
00344 size_t numCommands = fCmdTable.size();
00345 CATInt32* cmdLengths = new CATInt32[numCommands+1];
00346 CATUInt32 i = 0;
00347
00348
00349 for (i = 0; i < (CATUInt32)numCommands; ++i)
00350 cmdLengths[i] = GetCmdLength(i);
00351
00352
00353 for (i = 0; i < (CATUInt32)numCommands; ++i)
00354 {
00355
00356 if (curColumn + cmdLengths[i] >= 80)
00357 {
00358 curColumn = startColumn;
00359 wprintf(L"\n");
00360 wprintf(L"%*c",startColumn-1,0x20);
00361 }
00362
00363
00364 CATInt32 cmdLength = PrintCmdEntry(i);
00365 CATASSERT(cmdLength == cmdLengths[i], "ERROR: GetCmdLength() and PrintCmdEntry() don't match!");
00366 curColumn += cmdLength;
00367
00368 if (curColumn < 79)
00369 {
00370 curColumn++;
00371 wprintf(L" ");
00372 }
00373 }
00374
00375 if (cmdLengths)
00376 {
00377 delete [] cmdLengths;
00378 cmdLengths = 0;
00379 }
00380
00381 wprintf(L"\n\n");
00382
00383
00384 CATInt32 maxArgLen = 0;
00385 for (i = 1; i < numCommands; i++)
00386 {
00387 const CATWChar* opDesc = fStringTable->GetString (fCmdTable[i].ArgOptDescId,
00388 fLangId);
00389
00390 const CATWChar* cmdDesc = fStringTable->GetString(fCmdTable[i].DescriptionId,
00391 fLangId);
00392
00393 CATInt32 argLen = 0;
00394 if (fCmdTable[i].CmdSwitch == 0)
00395 {
00396 argLen = startColumn + (CATInt32)(opDesc?wcslen(opDesc):5);
00397 }
00398 else
00399 {
00400 if (!fCmdTable[i].TakesArg)
00401 argLen = startColumn+2;
00402 else
00403 {
00404 argLen = startColumn + 3 + (CATInt32)(opDesc?wcslen(opDesc):5);
00405 }
00406 }
00407
00408 if (argLen > maxArgLen)
00409 maxArgLen = argLen;
00410 }
00411
00412
00413 for (i = 1; i < numCommands; ++i)
00414 {
00415 const CATWChar* cmdDesc = fStringTable->GetString(fCmdTable[i].DescriptionId,
00416 fLangId);
00417
00418 const CATWChar* argDesc = fStringTable->GetString(fCmdTable[i].ArgOptDescId,
00419 fLangId);
00420
00421 if (fCmdTable[i].CmdSwitch != 0)
00422 {
00423 CATASSERT(cmdDesc != 0, "Commands MUST be documented.");
00424 if (fCmdTable[i].TakesArg == 0)
00425 {
00426 curColumn = wprintf(L"%*c-%c",startColumn-1, 0x20,
00427 fCmdTable[i].CmdSwitch);
00428
00429 if (curColumn < maxArgLen)
00430 wprintf(L"%*c",(maxArgLen - curColumn),0x20);
00431
00432 wprintf(L" %s\n", cmdDesc?cmdDesc:L"EMPTY");
00433
00434 }
00435 else
00436 {
00437 CATASSERT(argDesc != 0, "Switch arguments MUST be documented if present.");
00438 curColumn = wprintf(L"%*c-%c %s",startColumn-1, 0x20,
00439 fCmdTable[i].CmdSwitch,
00440 argDesc?argDesc:L"EMPTY");
00441
00442 if (curColumn < maxArgLen)
00443 wprintf(L"%*c",(maxArgLen - curColumn),0x20);
00444
00445 wprintf(L" %s\n", cmdDesc?cmdDesc:L"EMPTY");
00446 }
00447 }
00448 }
00449
00450
00451 for (i = 1; i < numCommands; ++i)
00452 {
00453 const CATWChar* opDesc = fStringTable->GetString (fCmdTable[i].ArgOptDescId,
00454 fLangId);
00455
00456 const CATWChar* cmdDesc = fStringTable->GetString(fCmdTable[i].DescriptionId,
00457 fLangId);
00458
00459 if (fCmdTable[i].CmdSwitch == 0)
00460 {
00461 CATASSERT(opDesc != 0, "Operands MUST have short description name.");
00462 CATASSERT(cmdDesc != 0, "Operands MUST be documented if present.");
00463
00464 curColumn = wprintf(L"%*c%s", startColumn-1, 0x20,
00465 opDesc?opDesc:L"EMPTY");
00466
00467 if (curColumn < maxArgLen)
00468 wprintf(L"%*c",(maxArgLen - curColumn),0x20);
00469
00470 wprintf(L" %s\n", cmdDesc?cmdDesc:L"EMPTY");
00471 }
00472 }
00473
00474 wprintf(L"\n");
00475
00476 return result;
00477 }
00478
00479 CATInt32 CATCmdLine::PrintCmdEntry( CATUInt32 index)
00480 {
00481 CATInt32 length = 0;
00482
00483 bool isFirst = false;
00484 bool isLast = false;
00485 bool inGroup = IsCmdInGroup(index,isFirst,isLast);
00486 bool isRequired = fCmdTable[index].Required;
00487
00488 if (isFirst)
00489 {
00490
00491 length += wprintf(L"%c",isRequired?'(':'[');
00492 }
00493 else if ((!inGroup) && (!isRequired))
00494 {
00495
00496 length += wprintf(L"[");
00497 }
00498
00499 if (fCmdTable[index].CmdSwitch != 0)
00500 {
00501
00502 length += wprintf(L"-%c",fCmdTable[index].CmdSwitch);
00503 if (fCmdTable[index].TakesArg)
00504 {
00505
00506 const CATWChar* argstr = fStringTable->GetString(fCmdTable[index].ArgOptDescId);
00507 CATASSERT(argstr != 0, "If a command takes an argument, you must provide a valid string ID for it.");
00508 length += wprintf(L" %s",(argstr)?argstr:L"EMPTY");
00509 }
00510 }
00511 else
00512 {
00513
00514 const CATWChar* argstr = fStringTable->GetString(fCmdTable[index].ArgOptDescId);
00515 CATASSERT(argstr != 0, "If a command takes an argument, you must provide a valid string ID for it.");
00516 length += wprintf(L"%s",(argstr)?argstr:L"EMPTY");
00517 }
00518
00519 if (isLast)
00520 {
00521
00522 length += wprintf(L"%c",isRequired?')':']');
00523 }
00524 else if (inGroup)
00525 {
00526 length += wprintf(L" |");
00527 }
00528 else if ((!inGroup) && (!isRequired))
00529 {
00530
00531 length += wprintf(L"]");
00532 }
00533
00534 return length;
00535 }
00536 CATInt32 CATCmdLine::GetCmdLength( CATUInt32 index)
00537 {
00538 CATInt32 cmdLength = 0;
00539
00540 bool isFirst = false;
00541 bool isLast = false;
00542 bool inGroup = IsCmdInGroup(index,isFirst,isLast);
00543 bool isRequired = fCmdTable[index].Required;
00544
00545 if (isFirst)
00546 {
00547 cmdLength++;
00548
00549 }
00550 else if ((!inGroup) && (!isRequired))
00551 {
00552 cmdLength++;
00553
00554 }
00555
00556 if (fCmdTable[index].CmdSwitch != 0)
00557 {
00558
00559
00560 cmdLength += 2;
00561
00562
00563 if (fCmdTable[index].TakesArg)
00564 {
00565
00566 const CATWChar* argstr = fStringTable->GetString(fCmdTable[index].ArgOptDescId);
00567 CATASSERT(argstr != 0, "If a command takes an argument, you must provide a valid string ID for it.");
00568
00569 cmdLength += (CATInt32)((argstr)?(wcslen(argstr) + 1):5);
00570
00571 }
00572 }
00573 else
00574 {
00575
00576 const CATWChar* argstr = fStringTable->GetString(fCmdTable[index].ArgOptDescId);
00577 CATASSERT(argstr != 0, "If a command takes an argument, you must provide a valid string ID for it.");
00578
00579 cmdLength += (CATInt32)((argstr)?(wcslen(argstr)):5);
00580
00581 }
00582
00583 if (isLast)
00584 {
00585
00586 cmdLength++;
00587
00588 }
00589 else if (inGroup)
00590 {
00591 cmdLength+=2;
00592
00593 }
00594 else if ((!inGroup) && (!isRequired))
00595 {
00596
00597 cmdLength++;
00598
00599 }
00600
00601
00602 return cmdLength;
00603 }
00604
00605 CATBool CATCmdLine::IsCmdInGroup( CATUInt32 index,
00606 CATBool& isFirst,
00607 CATBool& isLast)
00608 {
00609 isFirst = false;
00610 isLast = false;
00611
00612 CATUInt32 numCmds = (CATUInt32)fCmdTable.size();
00613 if (numCmds == 1)
00614 return false;
00615
00616 CATASSERT(index < numCmds,"Invalid command index.");
00617 if (index >= numCmds)
00618 return false;
00619
00620 CATInt32 cmdGroup = fCmdTable[index].CmdGroup;
00621 if (cmdGroup == 0)
00622 return false;
00623
00624 if (index == 0)
00625 {
00626 if (fCmdTable[index+1].CmdGroup == cmdGroup)
00627 {
00628 isFirst = true;
00629 return true;
00630 }
00631 return false;
00632 }
00633
00634 if (index == numCmds - 1)
00635 {
00636 if (fCmdTable[index-1].CmdGroup == cmdGroup)
00637 {
00638 isLast = true;
00639 return true;
00640 }
00641 return false;
00642 }
00643
00644 if (fCmdTable[index-1].CmdGroup == cmdGroup)
00645 {
00646 isFirst = false;
00647 isLast = (fCmdTable[index+1].CmdGroup != cmdGroup);
00648 return true;
00649 }
00650 else
00651 {
00652 if (fCmdTable[index+1].CmdGroup == cmdGroup)
00653 {
00654 isFirst = true;
00655 isLast = false;
00656 return true;
00657 }
00658 }
00659
00660 return false;
00661 }
00662
00663
00664 CATBool CATCmdLine::IsSwitchSet(CATWChar cmdSwitch)
00665 {
00666 size_t numArgs = fArguments.size();
00667 for (size_t i = 0; i < numArgs; i++)
00668 {
00669 if (fArguments[i]->GetSwitch() == cmdSwitch)
00670 return true;
00671 }
00672 return false;
00673 }
00674
00675 const CATWChar* CATCmdLine::GetArgument(CATWChar cmdSwitch)
00676 {
00677 size_t numArgs = fArguments.size();
00678 for (size_t i = 0; i < numArgs; i++)
00679 {
00680 if (fArguments[i]->GetSwitch() == cmdSwitch)
00681 return fArguments[i]->GetArg();
00682 }
00683 return 0;
00684 }
00685
00686 CATUInt32 CATCmdLine::GetArgUInt(CATWChar cmdSwitch)
00687 {
00688 size_t numArgs = fArguments.size();
00689 for (size_t i = 0; i < numArgs; i++)
00690 {
00691 if (fArguments[i]->GetSwitch() == cmdSwitch)
00692 {
00693 const CATWChar* arg = fArguments[i]->GetArg();
00694 if (!arg)
00695 return 0;
00696
00697 CATWChar* endPtr = 0;
00698 return (CATUInt32)wcstoul(arg,&endPtr,0);
00699 }
00700 }
00701 return 0;
00702 }
00703
00704 CATInt32 CATCmdLine::GetArgInt(CATWChar cmdSwitch)
00705 {
00706 size_t numArgs = fArguments.size();
00707 for (size_t i = 0; i < numArgs; i++)
00708 {
00709 if (fArguments[i]->GetSwitch() == cmdSwitch)
00710 {
00711 const CATWChar* arg = fArguments[i]->GetArg();
00712 if (!arg)
00713 return 0;
00714
00715 CATWChar* endPtr = 0;
00716 return (CATUInt32)wcstol(arg,&endPtr,0);
00717 }
00718 }
00719 return 0;
00720 }
00721
00722 CATUInt32 CATCmdLine::GetNumOps()
00723 {
00724 return (CATUInt32)fOperands.size();
00725 }
00726
00727 const CATWChar* CATCmdLine::GetOpByIndex(CATUInt32 index)
00728 {
00729 if (index >= (CATUInt32)fOperands.size())
00730 return 0;
00731
00732 return fOperands[index];
00733 }
00734
00735 const CATWChar* CATCmdLine::GetOpByDescId(CATResult descId)
00736 {
00737
00738 size_t index = (size_t)-1;
00739 size_t numCmds = fCmdTable.size();
00740 size_t opNum = 0;
00741 for (size_t i = 0; i < numCmds; ++i)
00742 {
00743 if (fCmdTable[i].DescriptionId == descId)
00744 {
00745 index = i;
00746 break;
00747 }
00748
00749 if (fCmdTable[i].CmdSwitch == 0)
00750 opNum++;
00751 }
00752
00753
00754 if (index == (size_t)-1)
00755 return 0;
00756
00757 if (opNum >= (CATUInt32)fOperands.size())
00758 return 0;
00759
00760 return fOperands[opNum];
00761 }
00762
00763 CATUInt32 CATCmdLine::GetSwitchFlags()
00764 {
00765 return fSwitchFlags;
00766 }
00767
00768 CATResult CATCmdLine::RunParsedCallbacks(void* cbParam)
00769 {
00770 CATResult result = CAT_SUCCESS;
00771
00772
00773 size_t cmdIndex = 0;
00774 size_t numCmds = fCmdTable.size();
00775
00776 for (cmdIndex = 0; cmdIndex < numCmds; cmdIndex++)
00777 {
00778 if (fCmdTable[cmdIndex].Callback != 0)
00779 {
00780 CATWChar cmdSwitch = fCmdTable[cmdIndex].CmdSwitch;
00781 if (cmdSwitch != 0)
00782 {
00783 if (IsSwitchSet(cmdSwitch))
00784 {
00785 result = fCmdTable[cmdIndex].Callback(this,cbParam);
00786 if (CATFAILED(result))
00787 return result;
00788 }
00789 }
00790 else
00791 {
00792 const CATWChar* operand = GetOpByDescId(fCmdTable[cmdIndex].DescriptionId);
00793 if (operand)
00794 {
00795 result = fCmdTable[cmdIndex].Callback(this,cbParam);
00796
00797 if (CATFAILED(result))
00798 return result;
00799 }
00800 }
00801 }
00802 }
00803
00804 return result;
00805 }