A Simple Win32 Command-Line Parser

Environment: VC6, WIN 9x

A Simple Win32 Command-Line Parser

I was disapointed when I first discovered that (non-console) Win32 apps did not have argc and argv. This class is my solution. CmdLineArgs is a subclass of STL vector. After instantiation, it contains the command line args for your app.

argc - size()
argv - operator[]

Here's an example of it's use...


int main ()
{
    CmdLineArgs args;
   
    for (int i = 0; i < args.size(); i++)
        puts (args[i]);

    return 0;
}

Here's a test run of the example code above...

C:>test.exe This "is" a ""test"" "of the parsing" alg"o"rithm.
C:\Test.exe
This
is
a
"test"
of the parsing
alg"o"rithm.

The class...


class CmdLineArgs : public std::vector
{
public:
    CmdLineArgs ()
    {
        // Save local copy of the command line string, because
        // ParseCmdLine() modifies this string while parsing it.
        PSZ cmdline = GetCommandLine();
        m_cmdline = new char [strlen (cmdline) + 1];
        if (m_cmdline)
        {
            strcpy (m_cmdline, cmdline);
            ParseCmdLine(); 
        }
    }
    ~CmdLineArgs()
    {
        delete m_cmdline;
    }

private:
    PSZ m_cmdline; // the command line string

    ////////////////////////////////////////////////////////////////////////////////
    // Parse m_cmdline into individual tokens, which are delimited by spaces. If a
    // token begins with a quote, then that token is terminated by the next quote
    // followed immediately by a space or terminator.  This allows tokens to contain
    // spaces.
    // This input string:     This "is" a ""test"" "of the parsing" alg"o"rithm.
    // Produces these tokens: This, is, a, "test", of the parsing, alg"o"rithm
    ////////////////////////////////////////////////////////////////////////////////
    void ParseCmdLine ()
    {
        enum { TERM  = '\0',
               QUOTE = '\"' };

        bool bInQuotes = false;
        PSZ pargs = m_cmdline;

        while (*pargs)
        {
            while (isspace (*pargs))        // skip leading whitespace
                pargs++;

            bInQuotes = (*pargs == QUOTE);  // see if this token is quoted

            if (bInQuotes)                  // skip leading quote
                pargs++; 

            push_back (pargs);              // store position of current token

            // Find next token.
            // NOTE: Args are normally terminated by whitespace, unless the
            // arg is quoted.  That's why we handle the two cases separately,
            // even though they are very similar.
            if (bInQuotes)
            {
                // find next quote followed by a space or terminator
                while (*pargs && 
                      !(*pargs == QUOTE && (isspace (pargs[1]) || pargs[1] == TERM)))
                    pargs++;
                if (*pargs)
                {
                    *pargs = TERM;  // terminate token
                    if (pargs[1])   // if quoted token not followed by a terminator
                        pargs += 2; // advance to next token
                }
            }
            else
            {
                // skip to next non-whitespace character
                while (*pargs && !isspace (*pargs)) 
                    pargs++;
                if (*pargs && isspace (*pargs)) // end of token
                {
                   *pargs = TERM;    // terminate token
                    pargs++;         // advance to next token or terminator
                }
            }
        } // while (*pargs)
    } // ParseCmdLine()
}; // class CmdLineArgs

Download demo project - 5 Kb