MOS Source Code
Loading...
Searching...
No Matches
cmdline.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include <mos/lib/cmdline.hpp>
4#include <mos/string.hpp>
5#include <mos/vector.hpp>
6#include <mos_stdlib.hpp>
7#include <mos_string.hpp>
8
9// (result array, cmdline, max cmdlines) -> a new result array
10typedef const char **(*cmdline_insert_fn_t)(const char **result, size_t result_capacity, char *cmdline, size_t *result_count);
11
12static const char **cmdline_static_array_insert(const char **result, size_t result_capacity, char *cmdline, size_t *result_count)
13{
14 if (*result_count == result_capacity)
15 return NULL;
16
17 result[*result_count] = cmdline;
18 (*result_count)++;
19 return result;
20}
21
22static const char **cmdline_dynamic_array_insert(const char **argv, size_t result_capacity, char *cmdline, size_t *result_count)
23{
24 MOS_UNUSED(result_capacity); // unused because we always realloc
25 argv = (const char **) krealloc(argv, sizeof(char *) * (*result_count + 1));
26 argv[*result_count] = strdup(cmdline);
27 (*result_count)++;
28 return argv;
29}
30
31static bool cmdline_parse_generic(char *start, size_t length, size_t cmdline_max, size_t *out_count, const char ***argv_ptr, cmdline_insert_fn_t inserter)
32{
33 char *buf_start = start;
34
35 if (length == 0)
36 return true;
37
38 // replace all spaces with null terminators, except for the ones quoted, and also handle escaped quotes
39 bool escaped = false;
40 enum
41 {
42 Q_SINGLE,
43 Q_DOUBLE,
44 Q_NONE,
45 } quote_type = Q_NONE;
46
47 for (char *c = start; c != &buf_start[length + 1]; c++)
48 {
49 if (escaped)
50 {
51 escaped = false;
52 continue;
53 }
54
55 if (*c == '\\')
56 {
57 escaped = true;
58 continue;
59 }
60
61 if (*c == '\'' && quote_type != Q_DOUBLE)
62 {
63 quote_type = quote_type == Q_SINGLE ? Q_NONE : Q_SINGLE;
64 continue;
65 }
66
67 if (*c == '"' && quote_type != Q_SINGLE)
68 {
69 quote_type = quote_type == Q_DOUBLE ? Q_NONE : Q_DOUBLE;
70 continue;
71 }
72
73 if (*c == ' ' && quote_type == Q_NONE)
74 *c = '\0';
75
76 if (*c == '\0' && quote_type != Q_NONE)
77 *c = ' '; // we are in a quoted string, so replace null terminator with space
78
79 if (*c == '\0')
80 {
81 if (strlen(start) > 0)
82 {
83 *argv_ptr = inserter(*argv_ptr, cmdline_max, start, out_count);
84 if (!*argv_ptr)
85 return false;
86 }
87
88 start = c + 1;
89 }
90 }
91
92 return true;
93}
94
95bool cmdline_parse_inplace(char *inbuf, size_t length, size_t cmdline_max, size_t *out_count, const char **out_cmdlines)
96{
97 return cmdline_parse_generic(inbuf, length, cmdline_max, out_count, &out_cmdlines, cmdline_static_array_insert);
98}
99
100const char **cmdline_parse(char *inbuf, size_t length, const char **outargv, size_t *out_count)
101{
102 if (!cmdline_parse_generic(inbuf, length, 0, out_count, &outargv, cmdline_dynamic_array_insert))
103 return NULL;
104 return outargv;
105}
106
108{
110 size_t count = 0;
111 const char **argv = cmdline_parse(inbuf, length, NULL, &count);
112 if (!argv)
113 return result;
114
115 for (size_t i = 0; i < count; i++)
116 result.push_back(argv[i]);
117
118 return result;
119}
120
121void string_unquote(char *str)
122{
123 size_t len = strlen(str);
124 if (len < 2)
125 return;
126
127 char quote = str[0];
128 if (quote != '\'' && quote != '"')
129 return;
130
131 if (str[len - 1] != quote)
132 return; // unbalanced quotes
133
134 for (size_t i = 1; i < len - 1; i++)
135 {
136 if (str[i] == '\\')
137 {
138 if (str[i + 1] == quote)
139 {
140 memmove(&str[i], &str[i + 1], len - i);
141 len--;
142 }
143 else if (str[i + 1] == '\\')
144 {
145 memmove(&str[i], &str[i + 1], len - i);
146 len--;
147 }
148 }
149 }
150
151 str[len - 1] = '\0';
152 memmove(str, &str[1], len - 1);
153}
auto push_back(const TItem &value) noexcept
Definition vector.hpp:143
MOSAPI char * strdup(const char *src)
MOSAPI void * memmove(void *dest, const void *src, size_t n)
const char **(* cmdline_insert_fn_t)(const char **result, size_t result_capacity, char *cmdline, size_t *result_count)
Definition cmdline.cpp:10
const char ** cmdline_parse(char *inbuf, size_t length, const char **outargv, size_t *out_count)
Definition cmdline.cpp:100
static bool cmdline_parse_generic(char *start, size_t length, size_t cmdline_max, size_t *out_count, const char ***argv_ptr, cmdline_insert_fn_t inserter)
Definition cmdline.cpp:31
mos::vector< mos::string > cmdline_parse_vector(char *inbuf, size_t length)
Definition cmdline.cpp:107
static const char ** cmdline_static_array_insert(const char **result, size_t result_capacity, char *cmdline, size_t *result_count)
Definition cmdline.cpp:12
bool cmdline_parse_inplace(char *inbuf, size_t length, size_t cmdline_max, size_t *out_count, const char **out_cmdlines)
Definition cmdline.cpp:95
void string_unquote(char *str)
Definition cmdline.cpp:121
static const char ** cmdline_dynamic_array_insert(const char **argv, size_t result_capacity, char *cmdline, size_t *result_count)
Definition cmdline.cpp:22
#define MOS_UNUSED(x)
Definition mos_global.h:65
#define NULL
Definition pb_syshdr.h:46
static size_t strlen(const char *s)
Definition pb_syshdr.h:80