1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://kodi.tv
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #pragma once
22 
23 #ifdef TARGET_POSIX
24 char* GetCommandLine();
25 #define _snprintf snprintf
26 #else
27 #include <windows.h>
28 #endif
29 #include <vector>
30 #include <string>
31 
32 class CmdLineArgs : public std::vector<char*>
33 {
34 public:
CmdLineArgs()35     CmdLineArgs ()
36     {
37         // Save local copy of the command line string, because
38         // ParseCmdLine() modifies this string while parsing it.
39         char* cmdline = GetCommandLine();
40         m_cmdline = new char [strlen (cmdline) + 1];
41         if (m_cmdline)
42         {
43             strcpy (m_cmdline, cmdline);
44             ParseCmdLine();
45         } else {
46 #ifdef TARGET_POSIX
47           delete[] cmdline;
48 #endif
49         }
50     }
51 
CmdLineArgs(const int argc,const char ** argv)52     CmdLineArgs (const int argc, const char **argv)
53     {
54       std::string cmdline;
55 #ifdef TARGET_POSIX
56       cmdline = "\"";
57 #endif
58       for (int i = 0 ; i<argc ; i++)
59       {
60         cmdline += std::string(argv[i]);
61         if ( i != (argc-1) )
62         {
63 #ifdef TARGET_POSIX
64           cmdline += "\" \"";
65 #else
66           cmdline += " ";
67 #endif
68         }
69       }
70 #ifdef TARGET_POSIX
71       cmdline += "\"";
72 #endif
73       m_cmdline = new char [cmdline.length() + 1];
74       if (m_cmdline)
75       {
76           strcpy(m_cmdline, cmdline.c_str());
77           ParseCmdLine();
78       }
79     }
80 
~CmdLineArgs()81     ~CmdLineArgs()
82     {
83         delete[] m_cmdline;
84     }
85 
86 private:
87     char* m_cmdline; // the command line string
88 
89     ////////////////////////////////////////////////////////////////////////////////
90     // Parse m_cmdline into individual tokens, which are delimited by spaces. If a
91     // token begins with a quote, then that token is terminated by the next quote
92     // followed immediately by a space or terminator.  This allows tokens to contain
93     // spaces.
94     // This input string:     This "is" a ""test"" "of the parsing" alg"o"rithm.
95     // Produces these tokens: This, is, a, "test", of the parsing, alg"o"rithm
96     ////////////////////////////////////////////////////////////////////////////////
ParseCmdLine()97     void ParseCmdLine ()
98     {
99         enum { TERM  = '\0',
100                QUOTE = '\"' };
101 
102         bool bInQuotes = false;
103         char* pargs = m_cmdline;
104 
105         while (*pargs)
106         {
107             while (isspace (*pargs))        // skip leading whitespace
108                 pargs++;
109 
110             bInQuotes = (*pargs == QUOTE);  // see if this token is quoted
111 
112             if (bInQuotes)                  // skip leading quote
113                 pargs++;
114 
115             push_back (pargs);              // store position of current token
116 
117             // Find next token.
118             // NOTE: Args are normally terminated by whitespace, unless the
119             // arg is quoted.  That's why we handle the two cases separately,
120             // even though they are very similar.
121             if (bInQuotes)
122             {
123                 // find next quote followed by a space or terminator
124                 while (*pargs &&
125                       !(*pargs == QUOTE && (isspace (pargs[1]) || pargs[1] == TERM)))
126                     pargs++;
127                 if (*pargs)
128                 {
129                     *pargs = TERM;  // terminate token
130                     if (pargs[1])   // if quoted token not followed by a terminator
131                         pargs += 2; // advance to next token
132                 }
133             }
134             else
135             {
136                 // skip to next non-whitespace character
137                 while (*pargs && !isspace (*pargs))
138                     pargs++;
139                 if (*pargs && isspace (*pargs)) // end of token
140                 {
141                    *pargs = TERM;    // terminate token
142                     pargs++;         // advance to next token or terminator
143                 }
144             }
145         } // while (*pargs)
146     } // ParseCmdLine()
147 }; // class CmdLineArgs
148 
149