int main(int argc, char **argv) { int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); /* * Create an empty address space that we can load modules and stuff into * as we parse the parameters. */ RTDBGAS hDbgAs; rc = RTDbgAsCreate(&hDbgAs, 0, RTUINTPTR_MAX, ""); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDBgAsCreate -> %Rrc", rc); /* * Create a debugging configuration instance to work with so that we can * make use of (i.e. test) path searching and such. */ RTDBGCFG hDbgCfg; rc = RTDbgCfgCreate(&hDbgCfg, "IPRT", true /*fNativePaths*/); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgCfgCreate -> %Rrc", rc); /* * Parse arguments. */ static const RTGETOPTDEF s_aOptions[] = { { "--input", 'i', RTGETOPT_REQ_STRING }, { "--local-file", 'l', RTGETOPT_REQ_NOTHING }, { "--cache-file", 'c', RTGETOPT_REQ_NOTHING }, { "--pe-image", 'p', RTGETOPT_REQ_NOTHING }, { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, { "--x86", '8', RTGETOPT_REQ_NOTHING }, { "--amd64", '6', RTGETOPT_REQ_NOTHING }, { "--whatever", '*', RTGETOPT_REQ_NOTHING }, }; PRTSTREAM pInput = g_pStdIn; PRTSTREAM pOutput = g_pStdOut; unsigned cVerbosityLevel = 0; enum { kOpenMethod_FromImage, kOpenMethod_FromPeImage } enmOpenMethod = kOpenMethod_FromImage; bool fCacheFile = false; RTLDRARCH enmArch = RTLDRARCH_WHATEVER; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); while ((rc = RTGetOpt(&GetState, &ValueUnion))) { switch (rc) { case 'i': rc = RTStrmOpen(ValueUnion.psz, "r", &pInput); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open '%s' for reading: %Rrc", ValueUnion.psz, rc); break; case 'c': fCacheFile = true; break; case 'l': fCacheFile = false; break; case 'p': enmOpenMethod = kOpenMethod_FromPeImage; break; case 'v': cVerbosityLevel++; break; case '8': enmArch = RTLDRARCH_X86_32; break; case '6': enmArch = RTLDRARCH_AMD64; break; case '*': enmArch = RTLDRARCH_WHATEVER; break; case 'h': RTPrintf("Usage: %s [options] <module> <address> [<module> <address> [..]]\n" "\n" "Options:\n" " -i,--input=file\n" " Specify a input file instead of standard input.\n" " --pe-image\n" " Use RTDbgModCreateFromPeImage to open the file." " -v, --verbose\n" " Display the address space before doing the filtering.\n" " --amd64,--x86,--whatever\n" " Selects the desired architecture.\n" " -h, -?, --help\n" " Display this help text and exit successfully.\n" " -V, --version\n" " Display the revision and exit successfully.\n" , RTPathFilename(argv[0])); return RTEXITCODE_SUCCESS; case 'V': RTPrintf("$Revision$\n"); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: { /* <module> <address> */ const char *pszModule = ValueUnion.psz; rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX); if (RT_FAILURE(rc)) return RTGetOptPrintError(rc, &ValueUnion); uint64_t u64Address = ValueUnion.u64; uint32_t cbImage = 0; uint32_t uTimestamp = 0; if (fCacheFile) { rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX); if (RT_FAILURE(rc)) return RTGetOptPrintError(rc, &ValueUnion); cbImage = ValueUnion.u32; rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX); if (RT_FAILURE(rc)) return RTGetOptPrintError(rc, &ValueUnion); uTimestamp = ValueUnion.u32; } RTDBGMOD hMod; if (enmOpenMethod == kOpenMethod_FromImage) rc = RTDbgModCreateFromImage(&hMod, pszModule, NULL, enmArch, hDbgCfg); else rc = RTDbgModCreateFromPeImage(&hMod, pszModule, NULL, NIL_RTLDRMOD, cbImage, uTimestamp, hDbgCfg); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgModCreateFromImage(,%s,,) -> %Rrc", pszModule, rc); rc = RTDbgAsModuleLink(hDbgAs, hMod, u64Address, 0 /* fFlags */); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgAsModuleLink(,%s,%llx,) -> %Rrc", pszModule, u64Address, rc); break; } default: return RTGetOptPrintError(rc, &ValueUnion); } } /* * Display the address space. */ if (cVerbosityLevel) { RTPrintf("*** Address Space Dump ***\n"); uint32_t cModules = RTDbgAsModuleCount(hDbgAs); for (uint32_t iModule = 0; iModule < cModules; iModule++) { RTDBGMOD hDbgMod = RTDbgAsModuleByIndex(hDbgAs, iModule); RTPrintf("Module #%u: %s\n", iModule, RTDbgModName(hDbgMod)); RTDBGASMAPINFO aMappings[128]; uint32_t cMappings = RT_ELEMENTS(aMappings); rc = RTDbgAsModuleQueryMapByIndex(hDbgAs, iModule, &aMappings[0], &cMappings, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { for (uint32_t iMapping = 0; iMapping < cMappings; iMapping++) { if (aMappings[iMapping].iSeg == NIL_RTDBGSEGIDX) RTPrintf(" mapping #%u: %RTptr-%RTptr\n", iMapping, aMappings[iMapping].Address, aMappings[iMapping].Address + RTDbgModImageSize(hDbgMod) - 1); else { RTDBGSEGMENT SegInfo; rc = RTDbgModSegmentByIndex(hDbgMod, aMappings[iMapping].iSeg, &SegInfo); if (RT_SUCCESS(rc)) RTPrintf(" mapping #%u: %RTptr-%RTptr (segment #%u - '%s')", iMapping, aMappings[iMapping].Address, aMappings[iMapping].Address + SegInfo.cb, SegInfo.iSeg, SegInfo.szName); else RTPrintf(" mapping #%u: %RTptr-???????? (segment #%u)", iMapping, aMappings[iMapping].Address); } if (cVerbosityLevel > 1) { uint32_t cSymbols = RTDbgModSymbolCount(hDbgMod); RTPrintf(" %u symbols\n", cSymbols); for (uint32_t iSymbol = 0; iSymbol < cSymbols; iSymbol++) { RTDBGSYMBOL SymInfo; rc = RTDbgModSymbolByOrdinal(hDbgMod, iSymbol, &SymInfo); if (RT_SUCCESS(rc)) RTPrintf(" #%04u at %08x:%RTptr %05llx %s\n", SymInfo.iOrdinal, SymInfo.iSeg, SymInfo.offSeg, (uint64_t)SymInfo.cb, SymInfo.szName); } } } } else RTMsgError("RTDbgAsModuleQueryMapByIndex failed: %Rrc", rc); RTDbgModRelease(hDbgMod); } RTPrintf("*** End of Address Space Dump ***\n"); } /* * Read text from standard input and see if there is anything we can translate. */ for (;;) { /* Get a line. */ char szLine[_64K]; rc = RTStrmGetLine(pInput, szLine, sizeof(szLine)); if (rc == VERR_EOF) break; if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmGetLine() -> %Rrc\n", rc); /* * Search the line for potential addresses and replace them with * symbols+offset. */ const char *pszStart = szLine; const char *psz = szLine; char ch; while ((ch = *psz) != '\0') { size_t cchAddress; uint64_t u64Address; if ( ( ch == '0' && (psz[1] == 'x' || psz[1] == 'X') && TryParseAddress(psz, &cchAddress, &u64Address)) || ( RT_C_IS_XDIGIT(ch) && TryParseAddress(psz, &cchAddress, &u64Address)) ) { /* Print. */ psz += cchAddress; if (pszStart != psz) RTStrmWrite(pOutput, pszStart, psz - pszStart); pszStart = psz; /* Try get the module. */ RTUINTPTR uAddr; RTDBGSEGIDX iSeg; RTDBGMOD hDbgMod; rc = RTDbgAsModuleByAddr(hDbgAs, u64Address, &hDbgMod, &uAddr, &iSeg); if (RT_SUCCESS(rc)) { if (iSeg != UINT32_MAX) RTStrmPrintf(pOutput, "=[%s:%u", RTDbgModName(hDbgMod), iSeg); else RTStrmPrintf(pOutput, "=[%s", RTDbgModName(hDbgMod), iSeg); /* * Do we have symbols? */ RTDBGSYMBOL Symbol; RTINTPTR offSym; rc = RTDbgAsSymbolByAddr(hDbgAs, u64Address, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &offSym, &Symbol, NULL); if (RT_SUCCESS(rc)) { if (!offSym) RTStrmPrintf(pOutput, "!%s", Symbol.szName); else if (offSym > 0) RTStrmPrintf(pOutput, "!%s+%#llx", Symbol.szName, offSym); else RTStrmPrintf(pOutput, "!%s-%#llx", Symbol.szName, -offSym); } else RTStrmPrintf(pOutput, "+%#llx", u64Address - uAddr); /* * Do we have line numbers? */ RTDBGLINE Line; RTINTPTR offLine; rc = RTDbgAsLineByAddr(hDbgAs, u64Address, &offLine, &Line, NULL); if (RT_SUCCESS(rc)) RTStrmPrintf(pOutput, " %Rbn(%u)", Line.szFilename, Line.uLineNo); RTStrmPrintf(pOutput, "]"); RTDbgModRelease(hDbgMod); } } else psz++; } if (pszStart != psz) RTStrmWrite(pOutput, pszStart, psz - pszStart); RTStrmPutCh(pOutput, '\n'); } return RTEXITCODE_SUCCESS; }
int main() { RTTEST hTest; int rc = RTTestInitAndCreate("tstRTGetOpt", &hTest); if (rc) return rc; RTGETOPTSTATE GetState; RTGETOPTUNION Val; #define CHECK(expr) do { if (!(expr)) { RTTestIFailed("error line %d (iNext=%d): %s\n", __LINE__, GetState.iNext, #expr); } } while (0) #define CHECK2(expr, fmt) \ do { \ if (!(expr)) { \ RTTestIFailed("error line %d (iNext=%d): %s\n", __LINE__, GetState.iNext, #expr); \ RTTestIFailureDetails fmt; \ } \ } while (0) #define CHECK_pDef(paOpts, i) \ CHECK2(Val.pDef == &(paOpts)[(i)], ("Got #%d (%p) expected #%d\n", (int)(Val.pDef - &(paOpts)[0]), Val.pDef, i)); #define CHECK_GETOPT(expr, chRet, iInc) \ do { \ const int iPrev = GetState.iNext; \ const int rcGetOpt = (expr); \ CHECK2(rcGetOpt == (chRet), ("got %d, expected %d\n", rcGetOpt, (chRet))); \ CHECK2(GetState.iNext == (iInc) + iPrev, ("iNext=%d expected %d\n", GetState.iNext, (iInc) + iPrev)); \ GetState.iNext = (iInc) + iPrev; \ } while (0) #define CHECK_GETOPT_STR(expr, chRet, iInc, str) \ do { \ const int iPrev = GetState.iNext; \ const int rcGetOpt = (expr); \ CHECK2(rcGetOpt == (chRet), ("got %d, expected %d\n", rcGetOpt, (chRet))); \ CHECK2(GetState.iNext == (iInc) + iPrev, ("iNext=%d expected %d\n", GetState.iNext, (iInc) + iPrev)); \ CHECK2(VALID_PTR(Val.psz) && !strcmp(Val.psz, (str)), ("got %s, expected %s\n", Val.psz, (str))); \ GetState.iNext = (iInc) + iPrev; \ } while (0) /* * The basics. */ RTTestSub(hTest, "Basics"); static const RTGETOPTDEF s_aOpts2[] = { { "--optwithstring", 's', RTGETOPT_REQ_STRING }, { "--optwithint", 'i', RTGETOPT_REQ_INT32 }, { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, { NULL, 'q', RTGETOPT_REQ_NOTHING }, { "--quiet", 384, RTGETOPT_REQ_NOTHING }, { "-novalue", 385, RTGETOPT_REQ_NOTHING }, { "-startvm", 386, RTGETOPT_REQ_STRING }, { "nodash", 387, RTGETOPT_REQ_NOTHING }, { "nodashval", 388, RTGETOPT_REQ_STRING }, { "--gateway", 'g', RTGETOPT_REQ_IPV4ADDR }, { "--mac", 'm', RTGETOPT_REQ_MACADDR }, { "--strindex", 400, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX }, { "strindex", 400, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX }, { "--intindex", 401, RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_INDEX }, { "--macindex", 402, RTGETOPT_REQ_MACADDR | RTGETOPT_FLAG_INDEX }, { "--indexnovalue", 403, RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_INDEX }, { "--macindexnegative", 404, RTGETOPT_REQ_NOTHING }, { "--twovalues", 405, RTGETOPT_REQ_STRING }, { "--twovaluesindex", 406, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_INDEX }, { "--threevalues", 407, RTGETOPT_REQ_UINT32 }, { "--boolean", 408, RTGETOPT_REQ_BOOL_ONOFF }, { "--booleanindex", 409, RTGETOPT_REQ_BOOL_ONOFF | RTGETOPT_FLAG_INDEX }, }; const char *argv2[] = { "-s", "string1", "-sstring2", "-s:string3", "-s=string4", "-s:", "-s=", "--optwithstring", "string5", "--optwithstring:string6", "--optwithstring=string7", "--optwithstring:", "--optwithstring=", "-i", "-42", "-i:-42", "-i=-42", "--optwithint", "42", "--optwithint:42", "--optwithint=42", "-v", "--verbose", "-q", "--quiet", "-novalue", "-startvm", "myvm", "nodash", "nodashval", "string9", "filename1", "-q", "filename2", "-vqi999", "-g192.168.1.1", "-m08:0:27:00:ab:f3", "--mac:1:::::c", "--strindex786", "string10", "--strindex786:string11", "--strindex786=string12", "strindex687", "string13", "strindex687:string14", "strindex687=string15", "strindex688:", "strindex689=", "--intindex137", "1000", "--macindex138", "08:0:27:00:ab:f3", "--indexnovalue1", "--macindexnegative", "--twovalues", "firstvalue", "secondvalue", "--twovalues:firstvalue", "secondvalue", "--twovaluesindex4", "1", "0xA", "--twovaluesindex5=2", "0xB", "--threevalues", "1", "0xC", "thirdvalue", /* bool on/off */ "--boolean", "on", "--boolean", "off", "--boolean", "invalid", "--booleanindex2", "on", "--booleanindex7", "off", "--booleanindex9", "invalid", /* standard options */ "--help", "-help", "-?", "-h", "--version", "-version", "-V", /* done */ NULL }; int argc2 = (int)RT_ELEMENTS(argv2) - 1; CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc2, (char **)argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0, 0 /* fFlags */))); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string1")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string2")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string3")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string4")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string5")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string6")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string7")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "")); CHECK(GetState.uIndex == UINT32_MAX); /* -i */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); /* --optwithint */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2); CHECK(Val.i32 == 42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == 42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == 42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 1); CHECK_pDef(s_aOpts2, 2); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 1); CHECK_pDef(s_aOpts2, 2); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 1); CHECK_pDef(s_aOpts2, 3); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 384, 1); CHECK_pDef(s_aOpts2, 4); /* -novalue / -startvm (single dash long options) */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 385, 1); CHECK_pDef(s_aOpts2, 5); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 386, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "myvm")); /* no-dash options */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 387, 1); CHECK_pDef(s_aOpts2, 7); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 388, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string9")); /* non-option, option, non-option */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1); CHECK(Val.psz && !strcmp(Val.psz, "filename1")); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 1); CHECK_pDef(s_aOpts2, 3); CHECK_GETOPT(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1); CHECK(Val.psz && !strcmp(Val.psz, "filename2")); /* compress short options */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 0); CHECK_pDef(s_aOpts2, 2); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 0); CHECK_pDef(s_aOpts2, 3); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == 999); /* IPv4 */ RTTestSub(hTest, "RTGetOpt - IPv4"); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'g', 1); CHECK(Val.IPv4Addr.u == RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8(192,168,1,1)))); /* Ethernet MAC address. */ RTTestSub(hTest, "RTGetOpt - MAC Address"); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'm', 1); CHECK( Val.MacAddr.au8[0] == 0x08 && Val.MacAddr.au8[1] == 0x00 && Val.MacAddr.au8[2] == 0x27 && Val.MacAddr.au8[3] == 0x00 && Val.MacAddr.au8[4] == 0xab && Val.MacAddr.au8[5] == 0xf3); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'm', 1); CHECK( Val.MacAddr.au8[0] == 0x01 && Val.MacAddr.au8[1] == 0x00 && Val.MacAddr.au8[2] == 0x00 && Val.MacAddr.au8[3] == 0x00 && Val.MacAddr.au8[4] == 0x00 && Val.MacAddr.au8[5] == 0x0c); /* string with indexed argument */ RTTestSub(hTest, "RTGetOpt - Option w/ Index"); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string10")); CHECK(GetState.uIndex == 786); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string11")); CHECK(GetState.uIndex == 786); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string12")); CHECK(GetState.uIndex == 786); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string13")); CHECK(GetState.uIndex == 687); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string14")); CHECK(GetState.uIndex == 687); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string15")); CHECK(GetState.uIndex == 687); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "")); CHECK(GetState.uIndex == 688); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "")); CHECK(GetState.uIndex == 689); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 401, 2); CHECK(Val.i32 == 1000); CHECK(GetState.uIndex == 137); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 402, 2); CHECK( Val.MacAddr.au8[0] == 0x08 && Val.MacAddr.au8[1] == 0x00 && Val.MacAddr.au8[2] == 0x27 && Val.MacAddr.au8[3] == 0x00 && Val.MacAddr.au8[4] == 0xab && Val.MacAddr.au8[5] == 0xf3); CHECK(GetState.uIndex == 138); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 403, 1); CHECK(GetState.uIndex == 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 404, 1); CHECK(GetState.uIndex == UINT32_MAX); /* RTGetOptFetchValue tests */ RTTestSub(hTest, "RTGetOptFetchValue"); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 405, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "firstvalue")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "secondvalue")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 405, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "firstvalue")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "secondvalue")); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 406, 2); CHECK(Val.u32 == 1); CHECK(GetState.uIndex == 4); CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_UINT32), VINF_SUCCESS, 1); CHECK(Val.u32 == 10); CHECK(GetState.uIndex == 4); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 406, 1); CHECK(Val.u32 == 2); CHECK(GetState.uIndex == 5); CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_UINT32), VINF_SUCCESS, 1); CHECK(Val.u32 == 11); CHECK(GetState.uIndex == 5); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 407, 2); CHECK(Val.u32 == 1); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_UINT32), VINF_SUCCESS, 1); CHECK(Val.u32 == 12); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "thirdvalue")); CHECK(GetState.uIndex == UINT32_MAX); /* bool on/off tests */ RTTestSub(hTest, "RTGetOpt - bool on/off"); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 408, 2); CHECK(Val.f); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 408, 2); CHECK(!Val.f); CHECK_GETOPT(RTGetOpt(&GetState, &Val), VERR_GETOPT_UNKNOWN_OPTION, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "invalid")); /* bool on/off with indexed argument */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 409, 2); CHECK(Val.f); CHECK(GetState.uIndex == 2); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 409, 2); CHECK(!Val.f); CHECK(GetState.uIndex == 7); CHECK_GETOPT(RTGetOpt(&GetState, &Val), VERR_GETOPT_UNKNOWN_OPTION, 2); CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "invalid")); /* standard options. */ RTTestSub(hTest, "Standard options"); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'V', 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'V', 1); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'V', 1); /* the end */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0); CHECK(Val.pDef == NULL); CHECK(argc2 == GetState.iNext); /* * Options first. */ RTTestSub(hTest, "Options first"); const char *argv3[] = { "foo1", "-s", "string1", "foo2", "--optwithstring", "string2", "foo3", "-i", "-42", "foo4", "-i:-42", "-i=-42", "foo5", "foo6", "foo7", "-i:-42", "-i=-42", "foo8", "--twovalues", "firstvalue", "secondvalue", "foo9", "--twovalues:firstvalue", "secondvalue", "foo10", "--", "--optwithstring", "foo11", "foo12", /* done */ NULL }; int argc3 = (int)RT_ELEMENTS(argv3) - 1; CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc3, (char **)argv3, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST))); /* -s */ CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string1"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string2"); CHECK(GetState.uIndex == UINT32_MAX); /* -i */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); /* --twovalues */ CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 2, "firstvalue"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 1, "firstvalue"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue"); CHECK(GetState.uIndex == UINT32_MAX); /* -- */ CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 2, "foo1"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo2"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo3"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo4"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo5"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo6"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo7"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo8"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo9"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo10"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "--optwithstring"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo11"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo12"); /* the end */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0); CHECK(Val.pDef == NULL); CHECK(argc3 == GetState.iNext); /* * Options first, part 2: No dash-dash. */ const char *argv4[] = { "foo1", "-s", "string1", "foo2", "--optwithstring", "string2", "foo3", "-i", "-42", "foo4", "-i:-42", "-i=-42", "foo5", "foo6", "foo7", "-i:-42", "-i=-42", "foo8", "--twovalues", "firstvalue", "secondvalue", "foo9", "--twovalues:firstvalue", "secondvalue", "foo10", "foo11", "foo12", /* done */ NULL }; int argc4 = (int)RT_ELEMENTS(argv4) - 1; CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc4, (char **)argv4, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST))); /* -s */ CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string1"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string2"); CHECK(GetState.uIndex == UINT32_MAX); /* -i */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1); CHECK(Val.i32 == -42); /* --twovalues */ CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 2, "firstvalue"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 1, "firstvalue"); CHECK(GetState.uIndex == UINT32_MAX); CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue"); CHECK(GetState.uIndex == UINT32_MAX); /* -- */ CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo1"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo2"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo3"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo4"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo5"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo6"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo7"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo8"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo9"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo10"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo11"); CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo12"); /* the end */ CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0); CHECK(Val.pDef == NULL); CHECK(argc4 == GetState.iNext); /* * Summary. */ return RTTestSummaryAndDestroy(hTest); }