mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 22:51:41 +01: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; | ||
|  | 
 | ||
|  | 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; | ||
|  |     int 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; | ||
|  | 
 | ||
|  |         /* helper function, called when done with an argument */ | ||
|  |         void end_arg() { | ||
|  |             char_out = 0; | ||
|  |             argv[argc++] = next_arg_start; | ||
|  |             state = SS_SPACE; | ||
|  |         } | ||
|  | 
 | ||
|  |         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; | ||
|  | } |