VirtualBox

Ignore:
Timestamp:
Mar 15, 2010 9:52:18 PM (15 years ago)
Author:
vboxsync
Message:

iprt: Implemented RTGetOptArgvToString with the MS CRT option. (The Bourne shell option is on the todo.)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/getoptargv.cpp

    r26525 r27384  
    3535#include "internal/iprt.h"
    3636
     37#include <iprt/asm.h>
    3738#include <iprt/assert.h>
    3839#include <iprt/err.h>
    3940#include <iprt/mem.h>
    4041#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 */
     53static 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>
     62int 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. */
    41118
    42119
     
    252329
    253330
    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 */
     340DECLINLINE(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 */
     365static 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 */
     381DECLINLINE(bool) rtGetOptArgvMsCrtIsSlashQuote(const char *psz)
     382{
     383    while (*psz == '\\')
     384        psz++;
     385    return *psz == '"';
     386}
     387
     388
     389RTDECL(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
     485RTDECL(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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette