1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 
17 #include "appspawn_utils.h"
18 #include "command_lexer.h"
19 
20 using namespace OHOS::AppSpawn;
21 
22 enum class ParsingState {
23     INIT,
24     IN_WHITESPACE,
25     IN_ARGUMENT,
26     IN_SINGLE_QUOTE,
27     IN_DOUBLE_QUOTE,
28 };
29 
GetAllArguments(std::vector<std::string> & args)30 bool CommandLexer::GetAllArguments(std::vector<std::string> &args)
31 {
32     constexpr char singleQuote = '\'';
33     constexpr char doubleQuote = '"';
34     ParsingState state = ParsingState::INIT;
35     std::string lastArg;
36 
37     for (size_t i = 0; i < str_.size(); i++) {
38         switch (state) {
39             case ParsingState::INIT:
40                 if (isspace(str_[i])) {
41                     state = ParsingState::IN_WHITESPACE;
42                 } else if (str_[i] == singleQuote) {
43                     state = ParsingState::IN_SINGLE_QUOTE;
44                 } else if (str_[i] == doubleQuote) {
45                     state = ParsingState::IN_DOUBLE_QUOTE;
46                 } else {
47                     state = ParsingState::IN_ARGUMENT;
48                     lastArg += str_[i];
49                 }
50                 break;
51             case ParsingState::IN_WHITESPACE:
52                 if (str_[i] == singleQuote) {
53                     state = ParsingState::IN_SINGLE_QUOTE;
54                 } else if (str_[i] == doubleQuote) {
55                     state = ParsingState::IN_DOUBLE_QUOTE;
56                 } else if (!isspace(str_[i])) {
57                     state = ParsingState::IN_ARGUMENT;
58                     lastArg += str_[i];
59                 }
60                 break;
61             case ParsingState::IN_ARGUMENT:
62                 if (isspace(str_[i])) {
63                     args.push_back(std::move(lastArg));
64                     // Whether a moved string is empty depends on the
65                     // implementation of C++ std library, so clear() is called.
66                     lastArg.clear();
67                     state = ParsingState::IN_WHITESPACE;
68                 } else if (str_[i] == singleQuote) {
69                     state = ParsingState::IN_SINGLE_QUOTE;
70                 } else if (str_[i] == doubleQuote) {
71                     state = ParsingState::IN_DOUBLE_QUOTE;
72                 } else {
73                     lastArg += str_[i];
74                 }
75                 break;
76             case ParsingState::IN_SINGLE_QUOTE:
77                 if (str_[i] == singleQuote) {
78                     state = ParsingState::IN_ARGUMENT;
79                 } else {
80                     lastArg += str_[i];
81                 }
82                 break;
83             case ParsingState::IN_DOUBLE_QUOTE:
84                 if (str_[i] == doubleQuote) {
85                     state = ParsingState::IN_ARGUMENT;
86                 } else {
87                     lastArg += str_[i];
88                 }
89                 break;
90         }
91     }
92 
93     if (state == ParsingState::IN_ARGUMENT) {
94         args.push_back(std::move(lastArg));
95     } else if (state == ParsingState::IN_SINGLE_QUOTE ||
96         state == ParsingState::IN_DOUBLE_QUOTE) {
97         APPSPAWN_LOGE("Parsing arguments failed: missing terminated quote");
98         args.clear();
99         return false;
100     }
101 
102     return true;
103 }
104