forked from esp8266/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBSArgs.h
177 lines (153 loc) · 4.59 KB
/
BSArgs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* Splitting string into tokens, taking quotes and escape sequences into account.
From https://github.com/espressif/esp-idf/blob/master/components/console/split_argv.c
Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
Licensed under the Apache License 2.0.
*/
#ifndef BS_ARGS_H
#define BS_ARGS_H
#include <stdio.h>
#include <ctype.h>
#include <string.h>
namespace bs
{
namespace protocol
{
#define SS_FLAG_ESCAPE 0x8
typedef enum
{
/* parsing the space between arguments */
SS_SPACE = 0x0,
/* parsing an argument which isn't quoted */
SS_ARG = 0x1,
/* parsing a quoted argument */
SS_QUOTED_ARG = 0x2,
/* parsing an escape sequence within unquoted argument */
SS_ARG_ESCAPED = SS_ARG | SS_FLAG_ESCAPE,
/* parsing an escape sequence within a quoted argument */
SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE,
} split_state_t;
/* helper macro, called when done with an argument */
#define END_ARG() do { \
char_out = 0; \
argv[argc++] = next_arg_start; \
state = SS_SPACE; \
} while(0);
/**
@brief Split command line into arguments in place
- This function finds whitespace-separated arguments in the given input line.
'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ]
- Argument which include spaces may be surrounded with quotes. In this case
spaces are preserved and quotes are stripped.
'abc "123 456" def' -> [ 'abc', '123 456', 'def' ]
- Escape sequences may be used to produce backslash, double quote, and space:
'a\ b\\c\"' -> [ 'a b\c"' ]
Pointers to at most argv_size - 1 arguments are returned in argv array.
The pointer after the last one (i.e. argv[argc]) is set to NULL.
@param line pointer to buffer to parse; it is modified in place
@param argv array where the pointers to arguments are written
@param argv_size number of elements in argv_array (max. number of arguments will be argv_size - 1)
@return number of arguments found (argc)
*/
inline size_t split_args(char *line, char **argv, size_t argv_size)
{
const int QUOTE = '"';
const int ESCAPE = '\\';
const int SPACE = ' ';
split_state_t state = SS_SPACE;
size_t argc = 0;
char *next_arg_start = line;
char *out_ptr = line;
for (char *in_ptr = line; argc < argv_size - 1; ++in_ptr)
{
int char_in = (unsigned char) * in_ptr;
if (char_in == 0)
{
break;
}
int char_out = -1;
switch (state)
{
case SS_SPACE:
if (char_in == SPACE)
{
/* skip space */
}
else if (char_in == QUOTE)
{
next_arg_start = out_ptr;
state = SS_QUOTED_ARG;
}
else if (char_in == ESCAPE)
{
next_arg_start = out_ptr;
state = SS_ARG_ESCAPED;
}
else
{
next_arg_start = out_ptr;
state = SS_ARG;
char_out = char_in;
}
break;
case SS_QUOTED_ARG:
if (char_in == QUOTE)
{
END_ARG();
}
else if (char_in == ESCAPE)
{
state = SS_QUOTED_ARG_ESCAPED;
}
else
{
char_out = char_in;
}
break;
case SS_ARG_ESCAPED:
case SS_QUOTED_ARG_ESCAPED:
if (char_in == ESCAPE || char_in == QUOTE || char_in == SPACE)
{
char_out = char_in;
}
else
{
/* unrecognized escape character, skip */
}
state = (split_state_t)(state & (~SS_FLAG_ESCAPE));
break;
case SS_ARG:
if (char_in == SPACE)
{
END_ARG();
}
else if (char_in == ESCAPE)
{
state = SS_ARG_ESCAPED;
}
else
{
char_out = char_in;
}
break;
}
/* need to output anything? */
if (char_out >= 0)
{
*out_ptr = char_out;
++out_ptr;
}
}
/* make sure the final argument is terminated */
*out_ptr = 0;
/* finalize the last argument */
if (state != SS_SPACE && argc < argv_size - 1)
{
argv[argc++] = next_arg_start;
}
/* add a NULL at the end of argv */
argv[argc] = NULL;
return argc;
}
} // namespace bs
} // namespace protocol
#endif //BS_ARGS_H