Index: trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- trunk/src/VBox/Runtime/Makefile.kmk	(revision 26455)
+++ trunk/src/VBox/Runtime/Makefile.kmk	(revision 26476)
@@ -252,4 +252,5 @@
 	common/misc/cidr.cpp \
 	common/misc/getopt.cpp \
+	common/misc/getoptargv.cpp \
 	common/misc/handletable.cpp \
 	common/misc/handletablectx.cpp \
@@ -266,4 +267,5 @@
 	common/misc/term.cpp \
 	common/misc/tar.cpp \
+	common/path/rtPathRootSpecLen.cpp \
 	common/path/rtPathVolumeSpecLen.cpp \
 	common/path/RTPathAbsDup.cpp \
@@ -271,4 +273,6 @@
 	common/path/RTPathAbsExDup.cpp \
 	common/path/RTPathAppend.cpp \
+	common/path/RTPathCopyComponents.cpp \
+	common/path/RTPathCountComponents.cpp \
 	common/path/RTPathExt.cpp \
 	common/path/RTPathFilename.cpp \
Index: trunk/src/VBox/Runtime/common/misc/getoptargv.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/getoptargv.cpp	(revision 26476)
+++ trunk/src/VBox/Runtime/common/misc/getoptargv.cpp	(revision 26476)
@@ -0,0 +1,258 @@
+/* $Id$ */
+/** @file
+ * IPRT - Command Line Parsing, Argument Vector.
+ */
+
+/*
+ * Copyright (C) 2010 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/getopt.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+
+/**
+ * Look for an unicode code point in the separator string.
+ *
+ * @returns true if it's a separator, false if it isn't.
+ * @param   Cp              The code point.
+ * @param   pszSeparators   The separators.
+ */
+static bool rtGetOptIsUniCpInString(RTUNICP Cp, const char *pszSeparators)
+{
+    /* This could be done in a more optimal fashion.  Probably worth a
+       separate RTStr function at some point. */
+    for (;;)
+    {
+        RTUNICP CpSep;
+        int rc = RTStrGetCpEx(&pszSeparators, &CpSep);
+        AssertRCReturn(rc, false);
+        if (CpSep == Cp)
+            return true;
+        if (!CpSep)
+            return false;
+    }
+}
+
+
+/**
+ * Look for an 7-bit ASCII character in the separator string.
+ *
+ * @returns true if it's a separator, false if it isn't.
+ * @param   ch              The character.
+ * @param   pszSeparators   The separators.
+ * @param   cchSeparators   The number of separators chars.
+ */
+DECLINLINE(bool) rtGetOptIsAsciiInSet(char ch, const char *pszSeparators, size_t cchSeparators)
+{
+    switch (cchSeparators)
+    {
+        case 8: if (ch == pszSeparators[7]) return true;
+        case 7: if (ch == pszSeparators[6]) return true;
+        case 6: if (ch == pszSeparators[5]) return true;
+        case 5: if (ch == pszSeparators[4]) return true;
+        case 4: if (ch == pszSeparators[3]) return true;
+        case 3: if (ch == pszSeparators[2]) return true;
+        case 2: if (ch == pszSeparators[1]) return true;
+        case 1: if (ch == pszSeparators[0]) return true;
+            return false;
+        default:
+            return memchr(pszSeparators, ch, cchSeparators);
+    }
+}
+
+
+/**
+ * Checks if the character is in the set of separators
+ *
+ * @returns true if it is, false if it isn't.
+ *
+ * @param   Cp              The code point.
+ * @param   pszSeparators   The separators.
+ * @param   cchSeparators   The length of @a pszSeparators.
+ */
+DECL_FORCE_INLINE(bool) rtGetOptIsCpInSet(RTUNICP Cp, const char *pszSeparators, size_t cchSeparators)
+{
+    if (RT_LIKELY(Cp <= 127))
+        return rtGetOptIsAsciiInSet((char)Cp, pszSeparators, cchSeparators);
+    return rtGetOptIsUniCpInString(Cp, pszSeparators);
+}
+
+
+/**
+ * Skips any delimiters at the start of the string that is pointed to.
+ *
+ * @returns VINF_SUCCESS or RTStrGetCpEx status code.
+ * @param   ppszSrc         Where to get and return the string pointer.
+ * @param   pszSeparators   The separators.
+ * @param   cchSeparators   The length of @a pszSeparators.
+ */
+static int rtGetOptSkipDelimiters(const char **ppszSrc, const char *pszSeparators, size_t cchSeparators)
+{
+    const char *pszSrc = *ppszSrc;
+    const char *pszRet;
+    for (;;)
+    {
+        pszRet = pszSrc;
+        RTUNICP Cp;
+        int rc = RTStrGetCpEx(&pszSrc, &Cp);
+        if (RT_FAILURE(rc))
+        {
+            *ppszSrc = pszRet;
+            return rc;
+        }
+        if (   !Cp
+            || !rtGetOptIsCpInSet(Cp, pszSeparators, cchSeparators))
+            break;
+    }
+
+    *ppszSrc = pszRet;
+    return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTGetOptArgvFromString(char ***ppapszArgv, int *pcArgs, const char *pszCmdLine, const char *pszSeparators)
+{
+    /*
+     * Some input validation.
+     */
+    AssertPtr(pszCmdLine);
+    AssertPtr(pcArgs);
+    AssertPtr(ppapszArgv);
+    if (!pszSeparators)
+        pszSeparators = " \t\n\r";
+    else
+        AssertPtr(pszSeparators);
+    size_t const cchSeparators = strlen(pszSeparators);
+    AssertReturn(cchSeparators > 0, VERR_INVALID_PARAMETER);
+
+    /*
+     * Parse the command line and chop off it into argv individual argv strings.
+     */
+    int         rc        = VINF_SUCCESS;
+    const char *pszSrc    = pszCmdLine;
+    char       *pszDup    = (char *)RTMemAlloc(strlen(pszSrc) + 1);
+    char       *pszDst    = pszDup;
+    if (!pszDup)
+        return VERR_NO_STR_MEMORY;
+    char      **papszArgs = NULL;
+    unsigned    iArg      = 0;
+    while (*pszSrc)
+    {
+        /* Skip stuff */
+        rc = rtGetOptSkipDelimiters(&pszSrc, pszSeparators, cchSeparators);
+        if (RT_FAILURE(rc))
+            break;
+        if (!*pszSrc)
+            break;
+
+        /* Start a new entry. */
+        if ((iArg % 32) == 0)
+        {
+            void *pvNew = RTMemRealloc(papszArgs, (iArg + 33) * sizeof(char *));
+            if (!pvNew)
+            {
+                rc = VERR_NO_MEMORY;
+                break;
+            }
+            papszArgs = (char **)pvNew;
+        }
+        papszArgs[iArg++] = pszDst;
+
+        /* Parse and copy the string over. */
+        RTUNICP CpQuote = 0;
+        for (;;)
+        {
+            RTUNICP Cp;
+            rc = RTStrGetCpEx(&pszSrc, &Cp);
+            if (RT_FAILURE(rc))
+                break;
+            if (!Cp)
+                break;
+            if (!CpQuote)
+            {
+                if (Cp == '"' || Cp == '\'')
+                    CpQuote = Cp;
+                else if (rtGetOptIsCpInSet(Cp, pszSeparators, cchSeparators))
+                    break;
+                else
+                    pszDst = RTStrPutCp(pszDst, Cp);
+            }
+            else if (CpQuote != Cp)
+                pszDst = RTStrPutCp(pszDst, Cp);
+            else
+                CpQuote = 0;
+        }
+        *pszDst++ = '\0';
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    if (RT_FAILURE(rc))
+    {
+        RTMemFree(pszDup);
+        RTMemFree(papszArgs);
+        return rc;
+    }
+
+    /*
+     * Terminate the array.
+     * Check for empty string to make sure we've got an array.
+     */
+    if (iArg == 0)
+    {
+        RTMemFree(pszDup);
+        papszArgs = (char **)RTMemAlloc(1 * sizeof(char *));
+        if (!papszArgs)
+            return VERR_NO_MEMORY;
+    }
+    papszArgs[iArg] = NULL;
+
+    *pcArgs     = iArg;
+    *ppapszArgv = papszArgs;
+    return VINF_SUCCESS;
+}
+
+
+RTDECL(void) RTGetOptArgvFree(char **papszArgv)
+{
+    if (papszArgv)
+    {
+        RTMemFree(papszArgv[0]);
+        RTMemFree(papszArgv);
+    }
+}
+
+
+/** @todo RTGetOptArgvToString (for windows)?
+ *  RTGetOptArgvSort for RTGetOptInit()? */
+
Index: trunk/src/VBox/Runtime/common/path/RTPathAppend.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/path/RTPathAppend.cpp	(revision 26455)
+++ trunk/src/VBox/Runtime/common/path/RTPathAppend.cpp	(revision 26476)
@@ -35,4 +35,5 @@
 #include "internal/iprt.h"
 #include <iprt/path.h>
+
 #include <iprt/assert.h>
 #include <iprt/ctype.h>
@@ -50,7 +51,8 @@
  *
  * @remarks Unnecessary root slashes will not be counted. The caller will have
- *          to deal with it where it matters.
+ *          to deal with it where it matters.  (Unlike rtPathRootSpecLen which
+ *          counts them.)
  */
-static size_t rtPathRootSpecLen(const char *pszPath)
+static size_t rtPathRootSpecLen2(const char *pszPath)
 {
     /* fend of wildlife. */
@@ -170,5 +172,5 @@
         /* In the leading path we can skip unnecessary trailing slashes, but
            be sure to leave one. */
-        size_t const cchRoot = rtPathRootSpecLen(pszPath);
+        size_t const cchRoot = rtPathRootSpecLen2(pszPath);
         while (     (size_t)(pszPathEnd - pszPath) > RT_MAX(1, cchRoot)
                &&   RTPATH_IS_SLASH(pszPathEnd[-2]))
Index: trunk/src/VBox/Runtime/common/path/RTPathCopyComponents.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/path/RTPathCopyComponents.cpp	(revision 26476)
+++ trunk/src/VBox/Runtime/common/path/RTPathCopyComponents.cpp	(revision 26476)
@@ -0,0 +1,88 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathCountComponents
+ */
+
+/*
+ * Copyright (C) 2010 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathCopyComponents(char *pszDst, size_t cbDst, const char *pszSrc, size_t cComponents)
+{
+    /*
+     * Quick input validation.
+     */
+    AssertPtr(pszDst);
+    AssertPtr(pszSrc);
+    if (cbDst == 0)
+        return VERR_BUFFER_OVERFLOW;
+
+    /*
+     * Fend of the simple case where nothing is wanted.
+     */
+    if (cComponents == 0)
+    {
+        *pszDst = '\0';
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * Parse into the path until we've counted the desired number of objects
+     * or hit the end.
+     */
+    size_t off = rtPathRootSpecLen(pszSrc);
+    size_t c   = off != 0;
+    while (c < cComponents && pszSrc[off])
+    {
+        c++;
+        while (!RTPATH_IS_SLASH(pszSrc[off]) && pszSrc[off])
+            off++;
+        while (RTPATH_IS_SLASH(pszSrc[off]))
+            off++;
+    }
+
+    /*
+     * Copy up to but not including 'off'.
+     */
+    if (off >= cbDst)
+        return VERR_BUFFER_OVERFLOW;
+
+    memcpy(pszDst, pszSrc, off);
+    pszDst[off] = '\0';
+    return VINF_SUCCESS;
+}
+
Index: trunk/src/VBox/Runtime/common/path/RTPathCountComponents.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/path/RTPathCountComponents.cpp	(revision 26476)
+++ trunk/src/VBox/Runtime/common/path/RTPathCountComponents.cpp	(revision 26476)
@@ -0,0 +1,56 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathCountComponents
+ */
+
+/*
+ * Copyright (C) 2010 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include "internal/path.h"
+
+
+RTDECL(size_t) RTPathCountComponents(const char *pszPath)
+{
+    size_t off = rtPathRootSpecLen(pszPath);
+    size_t c   = off != 0;
+    while (pszPath[off])
+    {
+        c++;
+        while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+            off++;
+        while (RTPATH_IS_SLASH(pszPath[off]))
+            off++;
+    }
+    return c;
+}
+
Index: trunk/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp	(revision 26476)
+++ trunk/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp	(revision 26476)
@@ -0,0 +1,98 @@
+/* $Id$ */
+/** @file
+ * IPRT - rtPathRootSpecLen (internal).
+ */
+
+/*
+ * Copyright (C) 2010 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include "internal/path.h"
+
+/**
+ * Figures out the length of the root (or drive) specifier in @a pszPath.
+ *
+ * For UNC names, we consider the root specifier to include both the server and
+ * share names.
+ *
+ * @returns The length including all slashes.  0 if relative path.
+ *
+ * @param   pszPath         The path to examine.
+ */
+DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
+{
+    /*
+     * If it's an absolute path, threat the root or volume specification as
+     * component 0.  UNC is making this extra fun on OS/2 and Windows as usual.
+     */
+    size_t off = 0;
+    if (RTPATH_IS_SLASH(pszPath[0]))
+    {
+#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+        if (   RTPATH_IS_SLASH(pszPath[1])
+            && !RTPATH_IS_SLASH(pszPath[2])
+            && pszPath[2])
+        {
+            /* UNC server name */
+            off = 2;
+            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                off++;
+            while (RTPATH_IS_SLASH(pszPath[off]))
+                off++;
+
+            /* UNC share */
+            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                off++;
+        }
+        else
+#endif
+        {
+            off = 1;
+        }
+        while (RTPATH_IS_SLASH(pszPath[off]))
+            off++;
+    }
+#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+    else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
+    {
+        off = 2;
+        while (RTPATH_IS_SLASH(pszPath[off]))
+            off++;
+    }
+#endif
+    Assert(!RTPATH_IS_SLASH(pszPath[off]));
+
+    return off;
+}
+
+
Index: trunk/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp	(revision 26455)
+++ trunk/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp	(revision 26476)
@@ -44,5 +44,5 @@
  * If no such specifier zero is returned.
  */
-size_t rtPathVolumeSpecLen(const char *pszPath)
+DECLHIDDEN(size_t) rtPathVolumeSpecLen(const char *pszPath)
 {
 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
Index: trunk/src/VBox/Runtime/include/internal/path.h
===================================================================
--- trunk/src/VBox/Runtime/include/internal/path.h	(revision 26455)
+++ trunk/src/VBox/Runtime/include/internal/path.h	(revision 26476)
@@ -43,7 +43,8 @@
 
 
-size_t  rtPathVolumeSpecLen(const char *pszPath);
-int     rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType);
-int     rtPathWin32MoveRename(const char *pszSrc, const char *pszDst, uint32_t fFlags, RTFMODE fFileType);
+DECLHIDDEN(size_t)  rtPathRootSpecLen(const char *pszPath);
+DECLHIDDEN(size_t)  rtPathVolumeSpecLen(const char *pszPath);
+DECLHIDDEN(int)     rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType);
+DECLHIDDEN(int)     rtPathWin32MoveRename(const char *pszSrc, const char *pszDst, uint32_t fFlags, RTFMODE fFileType);
 
 
Index: trunk/src/VBox/Runtime/r3/posix/path-posix.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/posix/path-posix.cpp	(revision 26455)
+++ trunk/src/VBox/Runtime/r3/posix/path-posix.cpp	(revision 26476)
@@ -662,5 +662,5 @@
  *                      not a directory (we are NOT checking whether it's a file).
  */
-int rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
+DECLHIDDEN(int) rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
 {
     /*
Index: trunk/src/VBox/Runtime/r3/win/path-win.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/win/path-win.cpp	(revision 26455)
+++ trunk/src/VBox/Runtime/r3/win/path-win.cpp	(revision 26476)
@@ -455,5 +455,5 @@
  *                      not a directory (we are NOT checking whether it's a file).
  */
-int rtPathWin32MoveRename(const char *pszSrc, const char *pszDst, uint32_t fFlags, RTFMODE fFileType)
+DECLHIDDEN(int) rtPathWin32MoveRename(const char *pszSrc, const char *pszDst, uint32_t fFlags, RTFMODE fFileType)
 {
     /*
Index: trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 26455)
+++ trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 26476)
@@ -66,4 +66,5 @@
 	tstFork \
 	tstGetOpt \
+	tstRTGetOptArgv \
 	tstHandleTable \
 	tstRTHeapOffset \
@@ -202,4 +203,7 @@
 tstGetOpt_SOURCES = tstGetOpt.cpp
 
+tstRTGetOptArgv_TEMPLATE = VBOXR3TSTEXE
+tstRTGetOptArgv_SOURCES = tstRTGetOptArgv.cpp
+
 tstHandleTable_SOURCES = tstHandleTable.cpp
 
Index: trunk/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp	(revision 26476)
+++ trunk/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp	(revision 26476)
@@ -0,0 +1,129 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - RTGetOptArgv*.
+ */
+
+/*
+ * Copyright (C) 2010 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/path.h>
+
+#include <iprt/err.h>
+#include <iprt/param.h>
+#include <iprt/getopt.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+static void tst1(void)
+{
+    RTTestISub("RTGetOptArgvFromString");
+    char **papszArgs = NULL;
+    int    cArgs = -1;
+    RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "", NULL), VINF_SUCCESS);
+    RTTESTI_CHECK_RETV(cArgs == 0);
+    RTTESTI_CHECK_RETV(papszArgs);
+    RTTESTI_CHECK_RETV(!papszArgs[0]);
+    RTGetOptArgvFree(papszArgs);
+
+    RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "0 1 \"\"2'' '3' 4 5 '''''6' 7 8 9 10 11", NULL), VINF_SUCCESS);
+    RTTESTI_CHECK_RETV(cArgs == 12);
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[6], "6"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[7], "7"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[8], "8"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[9], "9"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[10], "10"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[11], "11"));
+    RTTESTI_CHECK_RETV(!papszArgs[12]);
+    RTGetOptArgvFree(papszArgs);
+
+    RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "\t\" asdf \"  '\"'xyz  \"\t\"  '\n'  '\"'  \"'\"\n\r ", NULL), VINF_SUCCESS);
+    RTTESTI_CHECK_RETV(cArgs == 6);
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], " asdf "));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "\"xyz"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "\t"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "\n"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "\""));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "\'"));
+    RTTESTI_CHECK_RETV(!papszArgs[6]);
+    RTGetOptArgvFree(papszArgs);
+
+    RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, ":0::1::::2:3:4:5:", ":"), VINF_SUCCESS);
+    RTTESTI_CHECK_RETV(cArgs == 6);
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5"));
+    RTTESTI_CHECK_RETV(!papszArgs[6]);
+    RTGetOptArgvFree(papszArgs);
+
+    RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "0:1;2:3;4:5", ";;;;;;;;;;;;;;;;;;;;;;:"), VINF_SUCCESS);
+    RTTESTI_CHECK_RETV(cArgs == 6);
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4"));
+    RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5"));
+    RTTESTI_CHECK_RETV(!papszArgs[6]);
+    RTGetOptArgvFree(papszArgs);
+}
+
+int main()
+{
+    char szPath[RTPATH_MAX];
+
+    /*
+     * Init RT+Test.
+     */
+    RTTEST hTest;
+    int rc = RTTestInitAndCreate("tstRTGetOptArgv", &hTest);
+    if (rc)
+        return rc;
+    RTTestBanner(hTest);
+
+    /*
+     * The test.
+     */
+    tst1();
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
+
+
Index: trunk/src/VBox/Runtime/testcase/tstRTPath.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 26455)
+++ trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 26476)
@@ -414,4 +414,87 @@
 
     /*
+     * RTPathCountComponents
+     */
+    RTTestSub(hTest, "RTPathCountComponents");
+    RTTESTI_CHECK(RTPathCountComponents("") == 0);
+    RTTESTI_CHECK(RTPathCountComponents("/") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//////////////") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//////////////bin") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("//////////////bin/") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("//////////////bin/////") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("..") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("../") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("../..") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("../../") == 2);
+#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+    RTTESTI_CHECK(RTPathCountComponents("d:") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("d:/") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("d:/\\") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("d:\\") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("c:\\config.sys") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("c:\\windows") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("c:\\windows\\") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("c:\\windows\\system32") == 3);
+    RTTESTI_CHECK(RTPathCountComponents("//./C$") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("\\\\.\\C$") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("/\\.\\C$") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/share") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/share/") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\") == 1);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\x") == 2);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\x\\y") == 3);
+    RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\x\\y\\") == 3);
+#endif
+
+    /*
+     * RTPathCopyComponents
+     */
+    struct
+    {
+        const char *pszSrc;
+        size_t      cComponents;
+        const char *pszResult;
+    } s_aCopyComponents[] =
+    {
+        { "",                           0, "" },
+        { "",                           5, "" },
+        { "/",                          0, "" },
+        { "/",                          1, "/" },
+        { "/",                          2, "/" },
+        { "/usr/bin/sed",               0, "" },
+        { "/usr/bin/sed",               1, "/" },
+        { "/usr/bin/sed",               2, "/usr/" },
+        { "/usr/bin/sed",               3, "/usr/bin/" },
+        { "/usr/bin/sed",               4, "/usr/bin/sed" },
+        { "/usr/bin/sed",               5, "/usr/bin/sed" },
+        { "/usr/bin/sed",               6, "/usr/bin/sed" },
+        { "/usr///bin/sed",             2, "/usr///" },
+    };
+    for (unsigned i = 0; i < RT_ELEMENTS(s_aCopyComponents); i++)
+    {
+        const char *pszInput    = s_aCopyComponents[i].pszSrc;
+        size_t      cComponents = s_aCopyComponents[i].cComponents;
+        const char *pszResult   = s_aCopyComponents[i].pszResult;
+
+        memset(szPath, 'a', sizeof(szPath));
+        rc = RTPathCopyComponents(szPath, sizeof(szPath), pszInput, cComponents);
+        RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
+        if (RT_SUCCESS(rc) && strcmp(szPath, pszResult))
+            RTTestIFailed("Unexpected result\n"
+                          "   input: '%s' cComponents=%u\n"
+                          "  output: '%s'\n"
+                          "expected: '%s'",
+                          pszInput, cComponents, szPath, pszResult);
+        else if (RT_SUCCESS(rc))
+        {
+            RTTESTI_CHECK_RC(RTPathCopyComponents(szPath, strlen(pszResult) + 1, pszInput, cComponents), VINF_SUCCESS);
+            RTTESTI_CHECK_RC(RTPathCopyComponents(szPath, strlen(pszResult), pszInput, cComponents), VERR_BUFFER_OVERFLOW);
+        }
+    }
+
+    /*
      * Summary.
      */
