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
20using namespace OHOS::AppSpawn;
21
22enum class ParsingState {
23    INIT,
24    IN_WHITESPACE,
25    IN_ARGUMENT,
26    IN_SINGLE_QUOTE,
27    IN_DOUBLE_QUOTE,
28};
29
30bool 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