• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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