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(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 140 void deCommandLine_destroy (deCommandLine* cmdLine) 141 { 142 deFree(cmdLine->argBuf); 143 deFree(cmdLine); 144 } 145 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 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