| 
									
										
										
										
											2021-05-17 03:41:32 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-06 15:08:05 +08:00
										 |  |  | /* 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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | size_t esp_console_split_argv(char *line, char **argv, size_t argv_size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int QUOTE = '"'; | 
					
						
							|  |  |  |     const int ESCAPE = '\\'; | 
					
						
							|  |  |  |     const int SPACE = ' '; | 
					
						
							|  |  |  |     split_state_t state = SS_SPACE; | 
					
						
							| 
									
										
										
										
											2020-11-17 12:48:35 +08:00
										 |  |  |     size_t argc = 0; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2018-12-06 15:08:05 +08:00
										 |  |  |                 END_ARG(); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |             } 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) { | 
					
						
							| 
									
										
										
										
											2018-12-06 15:08:05 +08:00
										 |  |  |                 END_ARG(); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |             } 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; | 
					
						
							|  |  |  | } |