mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 20:51:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			121 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //     http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #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;
 | |
| 
 | |
| /* 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)
 | |
| 
 | |
| 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;
 | |
|     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;
 | |
| }
 | 
