xref: /aosp_15_r20/external/deqp/framework/delibs/deutil/deCommandLine.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
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(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':
82                 *outPtr++ = '\n';
83                 break;
84             case 't':
85                 *outPtr++ = '\t';
86                 break;
87             default:
88                 *outPtr++ = c;
89                 break;
90             }
91         }
92         else if (strChr != 0 && c == strChr)
93         {
94             /* String end. */
95             strChr = 0;
96         }
97         else if (strChr == 0 && (c == '"' || c == '\''))
98         {
99             /* String start. */
100             strChr = c;
101         }
102         else if (c == ' ' && strChr == 0)
103         {
104             /* Arg end. */
105             *outPtr++ = 0;
106             argNdx += 1;
107             if (!CharPtrArray_pushBack(args, outPtr))
108             {
109                 deFree(buf);
110                 deMemPool_destroy(tmpPool);
111                 return DE_NULL;
112             }
113         }
114         else
115             *outPtr++ = c;
116     }
117 
118     DE_ASSERT(commandLine[pos] == 0);
119 
120     /* Terminate last arg. */
121     *outPtr = 0;
122 
123     /* Create deCommandLine. */
124     {
125         deCommandLine *cmdLine = (deCommandLine *)deCalloc(sizeof(deCommandLine));
126 
127         if (!cmdLine ||
128             !(cmdLine->args = (char **)deCalloc(sizeof(char *) * (size_t)CharPtrArray_getNumElements(args))))
129         {
130             deFree(cmdLine);
131             deFree(buf);
132             deMemPool_destroy(tmpPool);
133             return DE_NULL;
134         }
135 
136         cmdLine->numArgs = CharPtrArray_getNumElements(args);
137         cmdLine->argBuf  = buf;
138 
139         for (argNdx = 0; argNdx < cmdLine->numArgs; argNdx++)
140             cmdLine->args[argNdx] = CharPtrArray_get(args, argNdx);
141 
142         deMemPool_destroy(tmpPool);
143         return cmdLine;
144     }
145 }
146 
deCommandLine_destroy(deCommandLine * cmdLine)147 void deCommandLine_destroy(deCommandLine *cmdLine)
148 {
149     deFree(cmdLine->argBuf);
150     deFree(cmdLine);
151 }
152 
testParse(const char * cmdLine,const char * const * refArgs,int numArgs)153 static void testParse(const char *cmdLine, const char *const *refArgs, int numArgs)
154 {
155     deCommandLine *parsedCmdLine = deCommandLine_parse(cmdLine);
156     int argNdx;
157 
158     DE_TEST_ASSERT(parsedCmdLine);
159     DE_TEST_ASSERT(parsedCmdLine->numArgs == numArgs);
160 
161     for (argNdx = 0; argNdx < numArgs; argNdx++)
162         DE_TEST_ASSERT(deStringEqual(parsedCmdLine->args[argNdx], refArgs[argNdx]));
163 
164     deCommandLine_destroy(parsedCmdLine);
165 }
166 
deCommandLine_selfTest(void)167 void deCommandLine_selfTest(void)
168 {
169     {
170         const char *cmdLine = "hello";
171         const char *ref[]   = {"hello"};
172         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
173     }
174     {
175         const char *cmdLine = "hello world";
176         const char *ref[]   = {"hello", "world"};
177         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
178     }
179     {
180         const char *cmdLine = "hello/world";
181         const char *ref[]   = {"hello/world"};
182         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
183     }
184     {
185         const char *cmdLine = "hello/world --help";
186         const char *ref[]   = {"hello/world", "--help"};
187         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
188     }
189     {
190         const char *cmdLine = "hello/world --help foo";
191         const char *ref[]   = {"hello/world", "--help", "foo"};
192         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
193     }
194     {
195         const char *cmdLine = "hello\\world --help foo";
196         const char *ref[]   = {"hello\\world", "--help", "foo"};
197         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
198     }
199     {
200         const char *cmdLine = "\"hello/worl d\" --help --foo=\"bar\" \"ba z\\\"\"";
201         const char *ref[]   = {"hello/worl d", "--help", "--foo=bar", "ba z\""};
202         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
203     }
204     {
205         const char *cmdLine = "'hello/worl d' --help --foo='bar' 'ba z\\\''";
206         const char *ref[]   = {"hello/worl d", "--help", "--foo=bar", "ba z'"};
207         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
208     }
209     {
210         const char *cmdLine = "hello \"'world'\"";
211         const char *ref[]   = {"hello", "'world'"};
212         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
213     }
214     {
215         const char *cmdLine = "hello '\"world\"'";
216         const char *ref[]   = {"hello", "\"world\""};
217         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
218     }
219     {
220         const char *cmdLine = "hello \"world\\n\"";
221         const char *ref[]   = {"hello", "world\n"};
222         testParse(cmdLine, ref, DE_LENGTH_OF_ARRAY(ref));
223     }
224 }
225