1 /*-------------------------------------------------------------------------
2 * drawElements Utility Library
3 * ----------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Command line parser.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deCommandLine.h"
25 #include "deMemPool.h"
26 #include "dePoolArray.h"
27 #include "deMemory.h"
28 #include "deString.h"
29
30 #include <string.h>
31
32 DE_DECLARE_POOL_ARRAY(CharPtrArray, char*);
33
34 enum
35 {
36 MAX_ARGS = 64
37 };
38
deCommandLine_parse(const char * commandLine)39 deCommandLine* deCommandLine_parse (const char* commandLine)
40 {
41 deMemPool* tmpPool = deMemPool_createRoot(DE_NULL, 0);
42 CharPtrArray* args = tmpPool ? CharPtrArray_create(tmpPool) : DE_NULL;
43 char* buf = DE_NULL;
44 char* outPtr;
45 int pos;
46 int argNdx;
47 char strChr;
48
49 if (!args)
50 {
51 if (tmpPool)
52 deMemPool_destroy(tmpPool);
53 return DE_NULL;
54 }
55
56 DE_ASSERT(commandLine);
57
58 /* Create buffer for args (no expansion can happen). */
59 buf = (char*)deCalloc(strlen(commandLine)+1);
60 pos = 0;
61 argNdx = 0;
62 outPtr = buf;
63 strChr = 0;
64
65 if (!buf || !CharPtrArray_pushBack(args, buf))
66 {
67 deMemPool_destroy(tmpPool);
68 return DE_NULL;
69 }
70
71 while (commandLine[pos] != 0)
72 {
73 char c = commandLine[pos++];
74
75 if (strChr != 0 && c == '\\')
76 {
77 /* Escape. */
78 c = commandLine[pos++];
79 switch (c)
80 {
81 case 'n': *outPtr++ = '\n'; break;
82 case 't': *outPtr++ = '\t'; break;
83 default: *outPtr++ = c; break;
84 }
85 }
86 else if (strChr != 0 && c == strChr)
87 {
88 /* String end. */
89 strChr = 0;
90 }
91 else if (strChr == 0 && (c == '"' || c == '\''))
92 {
93 /* String start. */
94 strChr = c;
95 }
96 else if (c == ' ' && strChr == 0)
97 {
98 /* Arg end. */
99 *outPtr++ = 0;
100 argNdx += 1;
101 if (!CharPtrArray_pushBack(args, outPtr))
102 {
103 deFree(buf);
104 deMemPool_destroy(tmpPool);
105 return DE_NULL;
106 }
107 }
108 else
109 *outPtr++ = c;
110 }
111
112 DE_ASSERT(commandLine[pos] == 0);
113
114 /* Terminate last arg. */
115 *outPtr = 0;
116
117 /* Create deCommandLine. */
118 {
119 deCommandLine* cmdLine = (deCommandLine*)deCalloc(sizeof(deCommandLine));
120
121 if (!cmdLine || !(cmdLine->args = (char**)deCalloc(sizeof(char*)*(size_t)CharPtrArray_getNumElements(args))))
122 {
123 deFree(cmdLine);
124 deFree(buf);
125 deMemPool_destroy(tmpPool);
126 return DE_NULL;
127 }
128
129 cmdLine->numArgs = CharPtrArray_getNumElements(args);
130 cmdLine->argBuf = buf;
131
132 for (argNdx = 0; argNdx < cmdLine->numArgs; argNdx++)
133 cmdLine->args[argNdx] = CharPtrArray_get(args, argNdx);
134
135 deMemPool_destroy(tmpPool);
136 return cmdLine;
137 }
138 }
139
deCommandLine_destroy(deCommandLine * cmdLine)140 void deCommandLine_destroy (deCommandLine* cmdLine)
141 {
142 deFree(cmdLine->argBuf);
143 deFree(cmdLine);
144 }
145
testParse(const char * cmdLine,const char * const * refArgs,int numArgs)146 static void testParse (const char* cmdLine, const char* const* refArgs, int numArgs)
147 {
148 deCommandLine* parsedCmdLine = deCommandLine_parse(cmdLine);
149 int argNdx;
150
151 DE_TEST_ASSERT(parsedCmdLine);
152 DE_TEST_ASSERT(parsedCmdLine->numArgs == numArgs);
153
154 for (argNdx = 0; argNdx < numArgs; argNdx++)
155 DE_TEST_ASSERT(deStringEqual(parsedCmdLine->args[argNdx], refArgs[argNdx]));
156
157 deCommandLine_destroy(parsedCmdLine);
158 }
159
deCommandLine_selfTest(void)160 void deCommandLine_selfTest (void)
161 {
162 {
163 const char* cmdLine = "hello";
164 const char* ref[] = { "hello" };
165 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
166 }
167 {
168 const char* cmdLine = "hello world";
169 const char* ref[] = { "hello", "world" };
170 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
171 }
172 {
173 const char* cmdLine = "hello/world";
174 const char* ref[] = { "hello/world" };
175 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
176 }
177 {
178 const char* cmdLine = "hello/world --help";
179 const char* ref[] = { "hello/world", "--help" };
180 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
181 }
182 {
183 const char* cmdLine = "hello/world --help foo";
184 const char* ref[] = { "hello/world", "--help", "foo" };
185 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
186 }
187 {
188 const char* cmdLine = "hello\\world --help foo";
189 const char* ref[] = { "hello\\world", "--help", "foo" };
190 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
191 }
192 {
193 const char* cmdLine = "\"hello/worl d\" --help --foo=\"bar\" \"ba z\\\"\"";
194 const char* ref[] = { "hello/worl d", "--help", "--foo=bar", "ba z\"" };
195 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
196 }
197 {
198 const char* cmdLine = "'hello/worl d' --help --foo='bar' 'ba z\\\''";
199 const char* ref[] = { "hello/worl d", "--help", "--foo=bar", "ba z'" };
200 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
201 }
202 {
203 const char* cmdLine = "hello \"'world'\"";
204 const char* ref[] = { "hello", "'world'" };
205 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
206 }
207 {
208 const char* cmdLine = "hello '\"world\"'";
209 const char* ref[] = { "hello", "\"world\"" };
210 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
211 }
212 {
213 const char* cmdLine = "hello \"world\\n\"";
214 const char* ref[] = { "hello", "world\n" };
215 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
216 }
217 }
218