Changeset 96623 in vbox for trunk/src/VBox/Frontends/VBoxManage
- Timestamp:
- Sep 7, 2022 1:25:44 AM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 153503
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp
r96407 r96623 215 215 216 216 /* 217 * Check the syntax. We can deduce the correct syntax from the number of 218 * arguments. 217 * Parse arguments. 218 * 219 * The old syntax was a little boinkers. The --patterns argument just 220 * indicates that the rest of the arguments are options. Sort of like '--'. 221 * This has been normalized a little now, by accepting patterns w/o a 222 * preceding --pattern argument via the VINF_GETOPT_NOT_OPTION. 223 * Though, the first non-option is always the VM name. 219 224 */ 220 if ( a->argc < 1 221 || a->argc == 2 222 || ( a->argc > 3 223 && strcmp(a->argv[1], "--patterns") 224 && strcmp(a->argv[1], "-patterns"))) 225 return errorSyntax(GuestProp::tr("Incorrect parameters")); 226 227 /* 228 * Pack the patterns 229 */ 230 Utf8Str strPatterns(a->argc > 2 ? a->argv[2] : ""); 231 for (int i = 3; i < a->argc; ++i) 232 strPatterns = Utf8StrFmt ("%s,%s", strPatterns.c_str(), a->argv[i]); 225 static const RTGETOPTDEF s_aOptions[] = 226 { 227 { "--old-format", 'o', RTGETOPT_REQ_NOTHING }, 228 { "--sort", 's', RTGETOPT_REQ_NOTHING }, 229 { "--unsort", 'u', RTGETOPT_REQ_NOTHING }, 230 { "--timestamp", 't', RTGETOPT_REQ_NOTHING }, 231 { "--ts", 't', RTGETOPT_REQ_NOTHING }, 232 { "--no-timestamp", 'T', RTGETOPT_REQ_NOTHING }, 233 { "--abs", 'a', RTGETOPT_REQ_NOTHING }, 234 { "--absolute", 'a', RTGETOPT_REQ_NOTHING }, 235 { "--rel", 'r', RTGETOPT_REQ_NOTHING }, 236 { "--relative", 'r', RTGETOPT_REQ_NOTHING }, 237 { "--no-ts", 'T', RTGETOPT_REQ_NOTHING }, 238 { "--flags", 'f', RTGETOPT_REQ_NOTHING }, 239 { "--no-flags", 'F', RTGETOPT_REQ_NOTHING }, 240 /* unnecessary legacy: */ 241 { "--patterns", 'p', RTGETOPT_REQ_STRING }, 242 { "-patterns", 'p', RTGETOPT_REQ_STRING }, 243 }; 244 245 int ch; 246 RTGETOPTUNION ValueUnion; 247 RTGETOPTSTATE GetState; 248 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0); 249 250 const char *pszVmNameOrUuid = NULL; 251 Utf8Str strPatterns; 252 bool fSort = true; 253 bool fNewStyle = true; 254 bool fTimestamp = true; 255 bool fAbsTime = true; 256 bool fFlags = true; 257 258 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) 259 { 260 /* For options that require an argument, ValueUnion has received the value. */ 261 switch (ch) 262 { 263 case VINF_GETOPT_NOT_OPTION: 264 /* The first one is the VM name. */ 265 if (!pszVmNameOrUuid) 266 { 267 pszVmNameOrUuid = ValueUnion.psz; 268 break; 269 } 270 /* Everything else would be patterns by the new syntax. */ 271 RT_FALL_THROUGH(); 272 case 'p': 273 if (strPatterns.isNotEmpty()) 274 if (RT_FAILURE(strPatterns.appendNoThrow(','))) 275 return RTMsgErrorExitFailure("out of memory!"); 276 if (RT_FAILURE(strPatterns.appendNoThrow(ValueUnion.psz))) 277 return RTMsgErrorExitFailure("out of memory!"); 278 break; 279 280 case 'o': 281 fNewStyle = false; 282 break; 283 284 case 's': 285 fSort = true; 286 break; 287 case 'u': 288 fSort = false; 289 break; 290 291 case 't': 292 fTimestamp = true; 293 break; 294 case 'T': 295 fTimestamp = false; 296 break; 297 298 case 'a': 299 fAbsTime = true; 300 break; 301 case 'r': 302 fAbsTime = false; 303 break; 304 305 case 'f': 306 fFlags = true; 307 break; 308 case 'F': 309 fFlags = false; 310 break; 311 312 default: 313 return errorGetOpt(ch, &ValueUnion); 314 } 315 } 316 317 /* Only the VM name is required. */ 318 if (!pszVmNameOrUuid) 319 return errorSyntax(GuestProp::tr("No VM name or UUID was specified")); 233 320 234 321 /* … … 236 323 */ 237 324 ComPtr<IMachine> machine; 238 HRESULT hrc; 239 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(), 240 machine.asOutParam())); 241 if (machine) 242 { 243 /* open a session for the VM - new or existing */ 244 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE); 245 246 /* get the mutable session machine */ 247 a->session->COMGETTER(Machine)(machine.asOutParam()); 248 249 com::SafeArray<BSTR> names; 250 com::SafeArray<BSTR> values; 251 com::SafeArray<LONG64> timestamps; 252 com::SafeArray<BSTR> flags; 253 CHECK_ERROR(machine, EnumerateGuestProperties(Bstr(strPatterns).raw(), 254 ComSafeArrayAsOutParam(names), 255 ComSafeArrayAsOutParam(values), 256 ComSafeArrayAsOutParam(timestamps), 257 ComSafeArrayAsOutParam(flags))); 258 if (SUCCEEDED(hrc)) 325 CHECK_ERROR2I_RET(a->virtualBox, FindMachine(Bstr(pszVmNameOrUuid).raw(), machine.asOutParam()), RTEXITCODE_FAILURE); 326 327 /* open a session for the VM - new or existing */ 328 CHECK_ERROR2I_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE); 329 330 /* get the mutable session machine */ 331 a->session->COMGETTER(Machine)(machine.asOutParam()); 332 333 com::SafeArray<BSTR> names; 334 com::SafeArray<BSTR> values; 335 com::SafeArray<LONG64> timestamps; 336 com::SafeArray<BSTR> flags; 337 CHECK_ERROR2I_RET(machine, EnumerateGuestProperties(Bstr(strPatterns).raw(), 338 ComSafeArrayAsOutParam(names), 339 ComSafeArrayAsOutParam(values), 340 ComSafeArrayAsOutParam(timestamps), 341 ComSafeArrayAsOutParam(flags)), 342 RTEXITCODE_FAILURE); 343 344 size_t const cEntries = names.size(); 345 if (cEntries == 0) 346 RTPrintf(GuestProp::tr("No properties found.\n")); 347 else 348 { 349 /* Whether we sort it or not, we work it via a indirect index: */ 350 size_t *paidxSorted = (size_t *)RTMemAlloc(sizeof(paidxSorted[0]) * cEntries); 351 if (!paidxSorted) 352 return RTMsgErrorExitFailure("out of memory!"); 353 for (size_t i = 0; i < cEntries; i++) 354 paidxSorted[i] = i; 355 356 /* Do the sorting: */ 357 if (fSort && cEntries > 1) 358 for (size_t i = 0; i < cEntries - 1; i++) 359 for (size_t j = 0; j < cEntries - i - 1; j++) 360 if (RTUtf16Cmp(names[paidxSorted[j]], names[paidxSorted[j + 1]]) > 0) 361 { 362 size_t iTmp = paidxSorted[j]; 363 paidxSorted[j] = paidxSorted[j + 1]; 364 paidxSorted[j + 1] = iTmp; 365 } 366 367 if (fNewStyle) 259 368 { 260 if (names.size() == 0) 261 RTPrintf(GuestProp::tr("No properties found.\n")); 262 for (unsigned i = 0; i < names.size(); ++i) 369 /* figure the width of the main columns: */ 370 size_t cwcMaxName = 1; 371 size_t cwcMaxValue = 1; 372 for (size_t i = 0; i < cEntries; ++i) 373 { 374 size_t cwcName = RTUtf16Len(names[i]); 375 cwcMaxName = RT_MAX(cwcMaxName, cwcName); 376 size_t cwcValue = RTUtf16Len(values[i]); 377 cwcMaxValue = RT_MAX(cwcMaxValue, cwcValue); 378 } 379 cwcMaxName = RT_MIN(cwcMaxName, 48); 380 cwcMaxValue = RT_MIN(cwcMaxValue, 28); 381 382 /* Get the current time for relative time formatting: */ 383 RTTIMESPEC Now; 384 RTTimeNow(&Now); 385 386 /* Print the table: */ 387 for (size_t iSorted = 0; iSorted < cEntries; ++iSorted) 388 { 389 size_t const i = paidxSorted[iSorted]; 390 char szTime[80]; 391 if (fTimestamp) 392 { 393 RTTIMESPEC TimestampTS; 394 RTTimeSpecSetNano(&TimestampTS, timestamps[i]); 395 if (fAbsTime) 396 { 397 RTTIME Timestamp; 398 RTTimeToStringEx(RTTimeExplode(&Timestamp, &TimestampTS), &szTime[2], sizeof(szTime) - 2, 3); 399 } 400 else 401 { 402 RTTIMESPEC DurationTS = Now; 403 RTTimeFormatDurationEx(&szTime[2], sizeof(szTime) - 2, RTTimeSpecSub(&DurationTS, &TimestampTS), 3); 404 } 405 szTime[0] = '@'; 406 szTime[1] = ' '; 407 } 408 else 409 szTime[0] = '\0'; 410 411 static RTUTF16 s_wszEmpty[] = { 0 }; 412 PCRTUTF16 const pwszFlags = fFlags ? flags[i] : s_wszEmpty; 413 414 int cchOut = RTPrintf("%-*ls = '%ls'", cwcMaxName, names[i], values[i]); 415 if (fTimestamp || *pwszFlags) 416 { 417 size_t const cwcWidth = cwcMaxName + cwcMaxValue + 6; 418 size_t const cwcValPadding = (unsigned)cchOut < cwcWidth ? cwcWidth - (unsigned)cchOut : 1; 419 RTPrintf("%*s%s%s%ls\n", cwcValPadding, "", szTime, *pwszFlags ? " " : "", pwszFlags); 420 } 421 else 422 RTPrintf("\n"); 423 } 424 } 425 else 426 for (size_t iSorted = 0; iSorted < cEntries; ++iSorted) 427 { 428 size_t const i = paidxSorted[iSorted]; 263 429 RTPrintf(GuestProp::tr("Name: %ls, value: %ls, timestamp: %lld, flags: %ls\n"), 264 430 names[i], values[i], timestamps[i], flags[i]); 265 } 266 } 267 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 431 } 432 RTMemFree(paidxSorted); 433 } 434 435 return RTEXITCODE_SUCCESS; 268 436 } 269 437 … … 405 573 RTEXITCODE handleGuestProperty(HandlerArg *a) 406 574 { 407 HandlerArg arg = *a; 408 arg.argc = a->argc - 1; 409 arg.argv = a->argv + 1; 575 if (a->argc == 0) 576 return errorNoSubcommand(); 410 577 411 578 /** @todo This command does not follow the syntax where the <uuid|vmname> … … 414 581 */ 415 582 416 if (a->argc == 0) 417 return errorSyntax(GuestProp::tr("Incorrect parameters")); 583 const char * const pszSubCmd = a->argv[0]; 584 a->argc -= 1; 585 a->argv += 1; 418 586 419 587 /* switch (cmd) */ 420 if (strcmp( a->argv[0], "get") == 0)421 return handleGetGuestProperty( &arg);422 if (strcmp( a->argv[0], "set") == 0)423 return handleSetGuestProperty( &arg);424 if (strcmp( a->argv[0], "delete") == 0 || strcmp(a->argv[0], "unset") == 0)425 return handleDeleteGuestProperty( &arg);426 if (strcmp( a->argv[0], "enumerate") == 0)427 return handleEnumGuestProperty( &arg);428 if (strcmp( a->argv[0], "wait") == 0)429 return handleWaitGuestProperty( &arg);588 if (strcmp(pszSubCmd, "get") == 0) 589 return handleGetGuestProperty(a); 590 if (strcmp(pszSubCmd, "set") == 0) 591 return handleSetGuestProperty(a); 592 if (strcmp(pszSubCmd, "delete") == 0 || strcmp(pszSubCmd, "unset") == 0) 593 return handleDeleteGuestProperty(a); 594 if (strcmp(pszSubCmd, "enumerate") == 0 || strcmp(pszSubCmd, "enum") == 0) 595 return handleEnumGuestProperty(a); 596 if (strcmp(pszSubCmd, "wait") == 0) 597 return handleWaitGuestProperty(a); 430 598 431 599 /* default: */ 432 return error Syntax(GuestProp::tr("Incorrect parameters"));600 return errorUnknownSubcommand(pszSubCmd); 433 601 }
Note:
See TracChangeset
for help on using the changeset viewer.