My Project
command_line.cpp
1 /*
2  * uuid-console - Microcontroller console shell
3  * Copyright 2019 Simon Arlott
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <uuid/console.h>
20 
21 #include <string>
22 #include <vector>
23 
24 namespace uuid {
25 
26 namespace console {
27 
28 CommandLine::CommandLine(const std::string &line) {
29  bool string_escape_double = false;
30  bool string_escape_single = false;
31  bool char_escape = false;
32  bool quoted_argument = false;
33 
34  if (!line.empty()) {
35  parameters_.emplace_back(std::string{});
36  }
37 
38  for (char c : line) {
39  switch (c) {
40  case ' ':
41  if (string_escape_double || string_escape_single) {
42  if (char_escape) {
43  parameters_.back().push_back('\\');
44  char_escape = false;
45  }
46  parameters_.back().push_back(' ');
47  } else if (char_escape) {
48  parameters_.back().push_back(' ');
49  char_escape = false;
50  } else {
51  // Begin a new argument if the previous
52  // one is not empty or it was quoted
53  if (quoted_argument || !parameters_.back().empty()) {
54  parameters_.emplace_back(std::string{});
55  }
56  quoted_argument = false;
57  }
58  break;
59 
60  case '"':
61  if (char_escape || string_escape_single) {
62  parameters_.back().push_back('"');
63  char_escape = false;
64  } else {
65  string_escape_double = !string_escape_double;
66  quoted_argument = true;
67  }
68  break;
69 
70  case '\'':
71  if (char_escape || string_escape_double) {
72  parameters_.back().push_back('\'');
73  char_escape = false;
74  } else {
75  string_escape_single = !string_escape_single;
76  quoted_argument = true;
77  }
78  break;
79 
80  case '\\':
81  if (char_escape) {
82  parameters_.back().push_back('\\');
83  char_escape = false;
84  } else {
85  char_escape = true;
86  }
87  break;
88 
89  default:
90  if (char_escape) {
91  parameters_.back().push_back('\\');
92  char_escape = false;
93  }
94  parameters_.back().push_back(c);
95  break;
96  }
97  }
98 
99  if (!parameters_.empty() && parameters_.back().empty() && !quoted_argument) {
100  parameters_.pop_back();
101  if (!parameters_.empty()) {
102  trailing_space = true;
103  }
104  }
105 }
106 
107 CommandLine::CommandLine(std::initializer_list<const std::vector<std::string>> arguments) {
108  for (auto &argument : arguments) {
109  parameters_.insert(parameters_.end(), argument.begin(), argument.end());
110  }
111 }
112 
113 std::string CommandLine::to_string(size_t reserve) const {
114  std::string line;
115  size_t escape = escape_parameters_;
116 
117  line.reserve(reserve);
118 
119  for (auto &item : parameters_) {
120  if (!line.empty()) {
121  line += ' ';
122  }
123 
124  if (item.empty()) {
125  line += '\"';
126  line += '\"';
127  goto next;
128  }
129 
130  for (char c : item) {
131  switch (c) {
132  case ' ':
133  case '\"':
134  case '\'':
135  case '\\':
136  if (escape > 0) {
137  line += '\\';
138  }
139  break;
140  }
141 
142  line += c;
143  }
144 
145 next:
146  if (escape > 0) {
147  escape--;
148  }
149  }
150 
151  if (trailing_space && !line.empty()) {
152  line += ' ';
153  }
154 
155  return line;
156 }
157 
159  parameters_.clear();
161  trailing_space = false;
162 }
163 
164 } // namespace console
165 
166 } // namespace uuid
uuid::console::CommandLine::reset
void reset()
Reset this command line's data.
Definition: command_line.cpp:158
uuid::console::CommandLine::trailing_space
bool trailing_space
Definition: console.h:1794
uuid::console::CommandLine::parameters_
std::vector< std::string > parameters_
Definition: console.h:1797
uuid
Common utilities.
Definition: get_uptime_ms.cpp:28
uuid::console::CommandLine::CommandLine
CommandLine()=default
Create an empty command line.
uuid::console::CommandLine::escape_parameters_
size_t escape_parameters_
Definition: console.h:1798
uuid::console::CommandLine::escape_all_parameters
void escape_all_parameters()
Escape all parameters when formatting the command line for output.
Definition: console.h:1716
uuid::console::CommandLine::to_string
std::string to_string(size_t reserve=Shell::MAX_COMMAND_LINE_LENGTH) const
Format a command line from separate parameters using built-in escaping rules.
Definition: command_line.cpp:113