HaikuDepot: notify work status from main window
[haiku.git] / src / kits / shared / ArgumentVector.cpp
blobc678f5de7cdc76c53f36b59fcc52b2885fd8cd07
1 /*
2 * Copyright 2007-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <ArgumentVector.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <string>
13 #include <vector>
16 struct ArgumentVector::Parser {
17 ParseError Parse(const char* commandLine, const char*& _errorLocation)
19 // init temporary arg/argv storage
20 fCurrentArg.clear();
21 fCurrentArgStarted = false;
22 fArgVector.clear();
23 fTotalStringSize = 0;
25 for (; *commandLine; commandLine++) {
26 char c = *commandLine;
28 // whitespace delimits args and is otherwise ignored
29 if (isspace(c)) {
30 _PushCurrentArg();
31 continue;
34 const char* errorBase = commandLine;
36 switch (c) {
37 case '\'':
38 // quoted string -- no quoting
39 while (*++commandLine != '\'') {
40 c = *commandLine;
41 if (c == '\0') {
42 _errorLocation = errorBase;
43 return UNTERMINATED_QUOTED_STRING;
45 _PushCharacter(c);
47 break;
49 case '"':
50 // quoted string -- some quoting
51 while (*++commandLine != '"') {
52 c = *commandLine;
53 if (c == '\0') {
54 _errorLocation = errorBase;
55 return UNTERMINATED_QUOTED_STRING;
58 if (c == '\\') {
59 c = *++commandLine;
60 if (c == '\0') {
61 _errorLocation = errorBase;
62 return UNTERMINATED_QUOTED_STRING;
65 // only '\' and '"' can be quoted, otherwise the
66 // the '\' is treated as a normal char
67 if (c != '\\' && c != '"')
68 _PushCharacter('\\');
71 _PushCharacter(c);
73 break;
75 case '\\':
76 // quoted char
77 c = *++commandLine;
78 if (c == '\0') {
79 _errorLocation = errorBase;
80 return TRAILING_BACKSPACE;
82 _PushCharacter(c);
83 break;
85 default:
86 // normal char
87 _PushCharacter(c);
88 break;
92 // commit last arg
93 _PushCurrentArg();
95 return NO_ERROR;
98 const std::vector<std::string>& ArgVector() const
100 return fArgVector;
103 size_t TotalStringSize() const
105 return fTotalStringSize;
108 private:
109 void _PushCurrentArg()
111 if (fCurrentArgStarted) {
112 fArgVector.push_back(fCurrentArg);
113 fTotalStringSize += fCurrentArg.length() + 1;
114 fCurrentArgStarted = false;
118 void _PushCharacter(char c)
120 if (!fCurrentArgStarted) {
121 fCurrentArg = "";
122 fCurrentArgStarted = true;
125 fCurrentArg += c;
128 private:
129 // temporaries
130 std::string fCurrentArg;
131 bool fCurrentArgStarted;
132 std::vector<std::string> fArgVector;
133 size_t fTotalStringSize;
137 ArgumentVector::ArgumentVector()
139 fArguments(NULL),
140 fCount(0)
145 ArgumentVector::~ArgumentVector()
147 free(fArguments);
151 char**
152 ArgumentVector::DetachArguments()
154 char** arguments = fArguments;
155 fArguments = NULL;
156 fCount = 0;
157 return arguments;
161 ArgumentVector::ParseError
162 ArgumentVector::Parse(const char* commandLine, const char** _errorLocation)
164 free(DetachArguments());
166 ParseError error;
167 const char* errorLocation = commandLine;
169 try {
170 Parser parser;
171 error = parser.Parse(commandLine, errorLocation);
173 if (error == NO_ERROR) {
174 // Create a char* array and copy everything into a single
175 // allocation.
176 int count = parser.ArgVector().size();
177 size_t arraySize = (count + 1) * sizeof(char*);
178 fArguments = (char**)malloc(
179 arraySize + parser.TotalStringSize());
180 if (fArguments != 0) {
181 char* argument = (char*)(fArguments + count + 1);
182 for (int i = 0; i < count; i++) {
183 fArguments[i] = argument;
184 const std::string& sourceArgument = parser.ArgVector()[i];
185 size_t argumentSize = sourceArgument.length() + 1;
186 memcpy(argument, sourceArgument.c_str(), argumentSize);
187 argument += argumentSize;
190 fArguments[count] = NULL;
191 fCount = count;
192 } else
193 error = NO_MEMORY;
195 } catch (...) {
196 error = NO_MEMORY;
199 if (error != NO_ERROR && _errorLocation != NULL)
200 *_errorLocation = errorLocation;
202 return error;