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((int)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*)*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
146 #if defined(DE_DEBUG)
testParse(const char * cmdLine,const char * const * refArgs,int numArgs)147 static void testParse (const char* cmdLine, const char* const* refArgs, int numArgs)
148 {
149 deCommandLine* parsedCmdLine = deCommandLine_parse(cmdLine);
150 int argNdx;
151
152 DE_TEST_ASSERT(parsedCmdLine);
153 DE_TEST_ASSERT(parsedCmdLine->numArgs == numArgs);
154
155 for (argNdx = 0; argNdx < numArgs; argNdx++)
156 DE_TEST_ASSERT(deStringEqual(parsedCmdLine->args[argNdx], refArgs[argNdx]));
157
158 deCommandLine_destroy(parsedCmdLine);
159 }
160
deCommandLine_selfTest(void)161 void deCommandLine_selfTest (void)
162 {
163 {
164 const char* cmdLine = "hello";
165 const char* ref[] = { "hello" };
166 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
167 }
168 {
169 const char* cmdLine = "hello world";
170 const char* ref[] = { "hello", "world" };
171 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
172 }
173 {
174 const char* cmdLine = "hello/world";
175 const char* ref[] = { "hello/world" };
176 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
177 }
178 {
179 const char* cmdLine = "hello/world --help";
180 const char* ref[] = { "hello/world", "--help" };
181 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
182 }
183 {
184 const char* cmdLine = "hello/world --help foo";
185 const char* ref[] = { "hello/world", "--help", "foo" };
186 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
187 }
188 {
189 const char* cmdLine = "hello\\world --help foo";
190 const char* ref[] = { "hello\\world", "--help", "foo" };
191 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
192 }
193 {
194 const char* cmdLine = "\"hello/worl d\" --help --foo=\"bar\" \"ba z\\\"\"";
195 const char* ref[] = { "hello/worl d", "--help", "--foo=bar", "ba z\"" };
196 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
197 }
198 {
199 const char* cmdLine = "'hello/worl d' --help --foo='bar' 'ba z\\\''";
200 const char* ref[] = { "hello/worl d", "--help", "--foo=bar", "ba z'" };
201 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
202 }
203 {
204 const char* cmdLine = "hello \"'world'\"";
205 const char* ref[] = { "hello", "'world'" };
206 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
207 }
208 {
209 const char* cmdLine = "hello '\"world\"'";
210 const char* ref[] = { "hello", "\"world\"" };
211 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
212 }
213 {
214 const char* cmdLine = "hello \"world\\n\"";
215 const char* ref[] = { "hello", "world\n" };
216 testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
217 }
218 }
219 #endif
220