Home | History | Annotate | Download | only in deutil
      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 
     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 
    140 void deCommandLine_destroy (deCommandLine* cmdLine)
    141 {
    142 	deFree(cmdLine->argBuf);
    143 	deFree(cmdLine);
    144 }
    145 
    146 #if defined(DE_DEBUG)
    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 
    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