Changeset 27384 in vbox for trunk/src/VBox/Runtime/common/misc/getoptargv.cpp
- Timestamp:
- Mar 15, 2010 9:52:18 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/getoptargv.cpp
r26525 r27384 35 35 #include "internal/iprt.h" 36 36 37 #include <iprt/asm.h> 37 38 #include <iprt/assert.h> 38 39 #include <iprt/err.h> 39 40 #include <iprt/mem.h> 40 41 #include <iprt/string.h> 42 43 44 /******************************************************************************* 45 * Header Files * 46 *******************************************************************************/ 47 /** 48 * Array indexed by the quoting type and 7-bit ASCII character. 49 * 50 * We include some extra stuff here that the corresponding shell would normally 51 * require qouting of. 52 */ 53 static uint8_t const g_abmQuoteChars[RTGETOPTARGV_CNV_QUOTE_MASK + 1][128/8] = 54 { 55 { 0xfe, 0xff, 0x0f, 0x00, 0x65, 0x00, 0x00, 0x50 }, 56 { 0xfe, 0xff, 0x0f, 0x00, 0xd7, 0x07, 0x00, 0xd8 }, 57 }; 58 59 60 #if 0 /* To re-generate the bitmaps. */ 61 #include <stdio.h> 62 int main() 63 { 64 RT_ZERO(g_abmQuoteChars); 65 66 # define SET_ALL(ch) \ 67 do { \ 68 for (size_t iType = 0; iType <= RTGETOPTARGV_CNV_QUOTE_MASK; iType++) \ 69 ASMBitSet(&g_abmQuoteChars[iType], (ch)); \ 70 } while (0) 71 # define SET(ConstSuffix, ch) \ 72 ASMBitSet(&g_abmQuoteChars[RTGETOPTARGV_CNV_QUOTE_##ConstSuffix], (ch)); 73 74 /* just flag all the control chars as in need of quoting. */ 75 for (char ch = 1; ch < 20; ch++) 76 SET_ALL(ch); 77 78 /* ... and space of course */ 79 SET_ALL(' '); 80 81 /* MS CRT / CMD.EXE: */ 82 SET(MS_CRT, '"') 83 SET(MS_CRT, '&') 84 SET(MS_CRT, '>') 85 SET(MS_CRT, '<') 86 SET(MS_CRT, '|') 87 SET(MS_CRT, '%') 88 89 /* Bourne shell: */ 90 SET(BOURNE_SH, '!'); 91 SET(BOURNE_SH, '"'); 92 SET(BOURNE_SH, '$'); 93 SET(BOURNE_SH, '&'); 94 SET(BOURNE_SH, '('); 95 SET(BOURNE_SH, ')'); 96 SET(BOURNE_SH, '*'); 97 SET(BOURNE_SH, ';'); 98 SET(BOURNE_SH, '<'); 99 SET(BOURNE_SH, '>'); 100 SET(BOURNE_SH, '?'); 101 SET(BOURNE_SH, '['); 102 SET(BOURNE_SH, '\''); 103 SET(BOURNE_SH, '\\'); 104 SET(BOURNE_SH, '`'); 105 SET(BOURNE_SH, '|'); 106 SET(BOURNE_SH, '~'); 107 108 for (size_t iType = 0; iType <= RTGETOPTARGV_CNV_QUOTE_MASK; iType++) 109 { 110 printf(" {"); 111 for (size_t iByte = 0; iByte < 8; iByte++) 112 printf(iByte == 0 ? " 0x%02x" : ", 0x%02x", g_abmQuoteChars[iType][iByte]); 113 printf(" },\n"); 114 } 115 return 0; 116 } 117 #endif /* To re-generate the bitmaps. */ 41 118 42 119 … … 252 329 253 330 254 /** @todo RTGetOptArgvToString (for windows)? 255 * RTGetOptArgvSort for RTGetOptInit()? */ 256 331 /** 332 * Checks if the argument needs quoting or not. 333 * 334 * @returns true if it needs, false if it don't. 335 * @param pszArg The argument. 336 * @param fFlags Quoting style. 337 * @param pcch Where to store the argument length when quoting 338 * is not required. (optimization) 339 */ 340 DECLINLINE(bool) rtGetOpArgvRequiresQuoting(const char *pszArg, uint32_t fFlags, size_t *pcch) 341 { 342 char const *psz = pszArg; 343 unsigned char ch; 344 while ((ch = (unsigned char)*psz)) 345 { 346 if ( ch < 128 347 && ASMBitTest(&g_abmQuoteChars[fFlags & RTGETOPTARGV_CNV_QUOTE_MASK], ch)) 348 return true; 349 psz++; 350 } 351 352 *pcch = psz - pszArg; 353 return false; 354 } 355 356 357 /** 358 * Grows the command line string buffer. 359 * 360 * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. 361 * @param ppszCmdLine Pointer to the command line string pointer. 362 * @param pcbCmdLineAlloc Pointer to the allocation length variable. 363 * @param cchMin The minimum size to grow with, kind of. 364 */ 365 static int rtGetOptArgvToStringGrow(char **ppszCmdLine, size_t *pcbCmdLineAlloc, size_t cchMin) 366 { 367 size_t cb = *pcbCmdLineAlloc; 368 while (cb < cchMin) 369 cb *= 2; 370 cb *= 2; 371 *pcbCmdLineAlloc = cb; 372 return RTStrRealloc(ppszCmdLine, cb); 373 } 374 375 /** 376 * Checks if we have a sequence of DOS slashes followed by a double quote char. 377 * 378 * @returns true / false accordingly. 379 * @param psz The string. 380 */ 381 DECLINLINE(bool) rtGetOptArgvMsCrtIsSlashQuote(const char *psz) 382 { 383 while (*psz == '\\') 384 psz++; 385 return *psz == '"'; 386 } 387 388 389 RTDECL(int) RTGetOptArgvToString(char **ppszCmdLine, const char * const *papszArgv, uint32_t fFlags) 390 { 391 AssertReturn(!(fFlags & ~RTGETOPTARGV_CNV_QUOTE_MASK), VERR_INVALID_PARAMETER); 392 AssertReturn((fFlags & RTGETOPTARGV_CNV_QUOTE_MASK) == RTGETOPTARGV_CNV_QUOTE_MS_CRT, VERR_NOT_IMPLEMENTED); 393 394 #define PUT_CH(ch) \ 395 if (RT_UNLIKELY(off + 1 >= cbCmdLineAlloc)) { \ 396 rc = rtGetOptArgvToStringGrow(&pszCmdLine, &cbCmdLineAlloc, 1); \ 397 if (RT_FAILURE(rc)) \ 398 break; \ 399 } \ 400 pszCmdLine[off++] = (ch) 401 402 #define PUT_PSZ(psz, cch) \ 403 if (RT_UNLIKELY(off + (cch) >= cbCmdLineAlloc)) { \ 404 rc = rtGetOptArgvToStringGrow(&pszCmdLine, &cbCmdLineAlloc, (cch)); \ 405 if (RT_FAILURE(rc)) \ 406 break; \ 407 } \ 408 memcpy(&pszCmdLine[off], (psz), (cch)); \ 409 off += (cch); 410 #define PUT_SZ(sz) PUT_PSZ(sz, sizeof(sz) - 1) 411 412 /* 413 * Take the realloc approach, it requires less code and is probably more 414 * efficient than figuring out the size first. 415 */ 416 int rc = VINF_SUCCESS; 417 size_t off = 0; 418 size_t cbCmdLineAlloc = 256; 419 char *pszCmdLine = RTStrAlloc(256); 420 if (!pszCmdLine) 421 return VERR_NO_STR_MEMORY; 422 423 for (size_t i = 0; papszArgv[i]; i++) 424 { 425 if (i > 0) 426 { 427 PUT_CH(' '); 428 } 429 430 /* does it need quoting? */ 431 const char *pszArg = papszArgv[i]; 432 size_t cchArg; 433 if (!rtGetOpArgvRequiresQuoting(pszArg, fFlags, &cchArg)) 434 { 435 /* No quoting needed, just append the argument. */ 436 PUT_PSZ(pszArg, cchArg); 437 } 438 else if ((fFlags & RTGETOPTARGV_CNV_QUOTE_MASK) == RTGETOPTARGV_CNV_QUOTE_MS_CRT) 439 { 440 /* 441 * Microsoft CRT quoting. Quote the whole argument in double 442 * quotes to make it easier to read and code. 443 */ 444 PUT_CH('"'); 445 char ch; 446 while ((ch = *pszArg++)) 447 { 448 if ( ch == '\\' 449 && rtGetOptArgvMsCrtIsSlashQuote(pszArg)) 450 { 451 PUT_SZ("\\\\"); 452 } 453 else if (ch == '"') 454 { 455 PUT_SZ("\\\""); 456 } 457 else 458 { 459 PUT_CH(ch); 460 } 461 } 462 PUT_CH('"'); 463 } 464 else /* bourne shell */ 465 { 466 AssertFailed(/*later*/); 467 } 468 } 469 470 /* Set return value / cleanup. */ 471 if (RT_SUCCESS(rc)) 472 { 473 pszCmdLine[off] = '\0'; 474 *ppszCmdLine = pszCmdLine; 475 } 476 else 477 RTStrFree(pszCmdLine); 478 #undef PUT_SZ 479 #undef PUT_PSZ 480 #undef PUT_CH 481 return rc; 482 } 483 484 485 RTDECL(int) RTGetOptArgvToUtf16String(PRTUTF16 *ppwszCmdLine, const char * const *papszArgv, uint32_t fFlags) 486 { 487 char *pszCmdLine; 488 int rc = RTGetOptArgvToString(&pszCmdLine, papszArgv, fFlags); 489 if (RT_SUCCESS(rc)) 490 { 491 rc = RTStrToUtf16(pszCmdLine, ppwszCmdLine); 492 RTStrFree(pszCmdLine); 493 } 494 return rc; 495 } 496
Note:
See TracChangeset
for help on using the changeset viewer.