| /*------------------------------------------------------------------------- |
| * drawElements Utility Library |
| * ---------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Command line parser. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "deCommandLine.h" |
| #include "deMemPool.h" |
| #include "dePoolArray.h" |
| #include "deMemory.h" |
| #include "deString.h" |
| |
| #include <string.h> |
| |
| DE_DECLARE_POOL_ARRAY(CharPtrArray, char*); |
| |
| enum |
| { |
| MAX_ARGS = 64 |
| }; |
| |
| deCommandLine* deCommandLine_parse (const char* commandLine) |
| { |
| deMemPool* tmpPool = deMemPool_createRoot(DE_NULL, 0); |
| CharPtrArray* args = tmpPool ? CharPtrArray_create(tmpPool) : DE_NULL; |
| char* buf = DE_NULL; |
| char* outPtr; |
| int pos; |
| int argNdx; |
| char strChr; |
| |
| if (!args) |
| { |
| if (tmpPool) |
| deMemPool_destroy(tmpPool); |
| return DE_NULL; |
| } |
| |
| DE_ASSERT(commandLine); |
| |
| /* Create buffer for args (no expansion can happen). */ |
| buf = (char*)deCalloc(strlen(commandLine)+1); |
| pos = 0; |
| argNdx = 0; |
| outPtr = buf; |
| strChr = 0; |
| |
| if (!buf || !CharPtrArray_pushBack(args, buf)) |
| { |
| deMemPool_destroy(tmpPool); |
| return DE_NULL; |
| } |
| |
| while (commandLine[pos] != 0) |
| { |
| char c = commandLine[pos++]; |
| |
| if (strChr != 0 && c == '\\') |
| { |
| /* Escape. */ |
| c = commandLine[pos++]; |
| switch (c) |
| { |
| case 'n': *outPtr++ = '\n'; break; |
| case 't': *outPtr++ = '\t'; break; |
| default: *outPtr++ = c; break; |
| } |
| } |
| else if (strChr != 0 && c == strChr) |
| { |
| /* String end. */ |
| strChr = 0; |
| } |
| else if (strChr == 0 && (c == '"' || c == '\'')) |
| { |
| /* String start. */ |
| strChr = c; |
| } |
| else if (c == ' ' && strChr == 0) |
| { |
| /* Arg end. */ |
| *outPtr++ = 0; |
| argNdx += 1; |
| if (!CharPtrArray_pushBack(args, outPtr)) |
| { |
| deFree(buf); |
| deMemPool_destroy(tmpPool); |
| return DE_NULL; |
| } |
| } |
| else |
| *outPtr++ = c; |
| } |
| |
| DE_ASSERT(commandLine[pos] == 0); |
| |
| /* Terminate last arg. */ |
| *outPtr = 0; |
| |
| /* Create deCommandLine. */ |
| { |
| deCommandLine* cmdLine = (deCommandLine*)deCalloc(sizeof(deCommandLine)); |
| |
| if (!cmdLine || !(cmdLine->args = (char**)deCalloc(sizeof(char*)*(size_t)CharPtrArray_getNumElements(args)))) |
| { |
| deFree(cmdLine); |
| deFree(buf); |
| deMemPool_destroy(tmpPool); |
| return DE_NULL; |
| } |
| |
| cmdLine->numArgs = CharPtrArray_getNumElements(args); |
| cmdLine->argBuf = buf; |
| |
| for (argNdx = 0; argNdx < cmdLine->numArgs; argNdx++) |
| cmdLine->args[argNdx] = CharPtrArray_get(args, argNdx); |
| |
| deMemPool_destroy(tmpPool); |
| return cmdLine; |
| } |
| } |
| |
| void deCommandLine_destroy (deCommandLine* cmdLine) |
| { |
| deFree(cmdLine->argBuf); |
| deFree(cmdLine); |
| } |
| |
| static void testParse (const char* cmdLine, const char* const* refArgs, int numArgs) |
| { |
| deCommandLine* parsedCmdLine = deCommandLine_parse(cmdLine); |
| int argNdx; |
| |
| DE_TEST_ASSERT(parsedCmdLine); |
| DE_TEST_ASSERT(parsedCmdLine->numArgs == numArgs); |
| |
| for (argNdx = 0; argNdx < numArgs; argNdx++) |
| DE_TEST_ASSERT(deStringEqual(parsedCmdLine->args[argNdx], refArgs[argNdx])); |
| |
| deCommandLine_destroy(parsedCmdLine); |
| } |
| |
| void deCommandLine_selfTest (void) |
| { |
| { |
| const char* cmdLine = "hello"; |
| const char* ref[] = { "hello" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello world"; |
| const char* ref[] = { "hello", "world" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello/world"; |
| const char* ref[] = { "hello/world" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello/world --help"; |
| const char* ref[] = { "hello/world", "--help" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello/world --help foo"; |
| const char* ref[] = { "hello/world", "--help", "foo" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello\\world --help foo"; |
| const char* ref[] = { "hello\\world", "--help", "foo" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "\"hello/worl d\" --help --foo=\"bar\" \"ba z\\\"\""; |
| const char* ref[] = { "hello/worl d", "--help", "--foo=bar", "ba z\"" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "'hello/worl d' --help --foo='bar' 'ba z\\\''"; |
| const char* ref[] = { "hello/worl d", "--help", "--foo=bar", "ba z'" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello \"'world'\""; |
| const char* ref[] = { "hello", "'world'" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello '\"world\"'"; |
| const char* ref[] = { "hello", "\"world\"" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| { |
| const char* cmdLine = "hello \"world\\n\""; |
| const char* ref[] = { "hello", "world\n" }; |
| testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref)); |
| } |
| } |