forked from bonsai/harakit
		
	pg(1): start work on a quoted strtok(3) and internal environment
This commit is contained in:
		
							parent
							
								
									eb454a6dad
								
							
						
					
					
						commit
						7142994367
					
				
							
								
								
									
										88
									
								
								src/pg.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/pg.c
									
									
									
									
									
								
							| @ -6,7 +6,7 @@ | ||||
|  * the terms of the GNU Affero General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) any | ||||
|  * later version. | ||||
|  *  | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||
|  * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | ||||
| @ -42,6 +42,70 @@ static FILE *input; | ||||
| static char *prompt = ": "; | ||||
| static char *program_name = "pg"; | ||||
| 
 | ||||
| static char *permute_out(char *str, size_t index){ | ||||
| 	size_t j; | ||||
| 
 | ||||
| 	for(j = index; str[j - 1] != '\0'; ++j) | ||||
| 		str[j - 1] = str[j]; | ||||
| 
 | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| /* strtok(3p), but supports double-quotes and escapes (but only for escaping
 | ||||
|  * quotes). UTF-8 is safe only in str. Unmatched quotes in str are considered | ||||
|  * literal. The behavior of strtok_quoted when '"' or '\\' are in sep is | ||||
|  * undefined. */ | ||||
| /* TODO: Seems to only ever return NULL. */ | ||||
| static char *strtok_quoted(char *str, char *sep){ | ||||
| 	static char *s; | ||||
| 	size_t i; | ||||
| 	size_t j; | ||||
| 
 | ||||
| 	if(str != NULL) | ||||
| 		s = str; | ||||
| 
 | ||||
| 	while(strchr(sep, *s) == NULL) | ||||
| 		if(*++s == '\0') | ||||
| 			return NULL; /* no remaining characters except seperators */ | ||||
| 
 | ||||
| 	{ | ||||
| 		char in_escape; | ||||
| 		int in_quotes; | ||||
| 
 | ||||
| 		in_escape = 0; | ||||
| 		in_quotes = -1; | ||||
| 		for(i = 0; s[i] != '\0'; ++i) | ||||
| 			switch(s[i]){ | ||||
| 			case '\\': | ||||
| 				if(in_escape) | ||||
| 					permute_out(s, i--); | ||||
| 				in_escape = !in_escape; | ||||
| 				break; | ||||
| 			case '"': | ||||
| 				if(in_escape){ | ||||
| 					s[i] = s[i - 1]; | ||||
| 					permute_out(s, i--); | ||||
| 				}else if(in_quotes != -1){ | ||||
| 					permute_out(s, in_quotes); | ||||
| 					--i; | ||||
| 					permute_out(s, i--); | ||||
| 					in_quotes = -1; | ||||
| 				}else | ||||
| 					in_quotes = i; | ||||
| 				break; | ||||
| 			case '\0': | ||||
| 				return s; | ||||
| 			default: | ||||
| 				if(!in_escape && strchr(sep, s[i]) != NULL){ | ||||
| 					s[i] = '\0'; | ||||
| 					return s; | ||||
| 				} | ||||
| 			} | ||||
| 	} | ||||
| 
 | ||||
| 	return s; | ||||
| } | ||||
| 
 | ||||
| /* Page at most l bytes from f without consideration of a buffer (print them to
 | ||||
|  * stdout). */ | ||||
| static int pg_b_u(FILE *f, size_t l){ | ||||
| @ -66,8 +130,8 @@ static int pg_l_u(FILE *f, size_t l, char nl){ | ||||
| 	return c; | ||||
| } | ||||
| 
 | ||||
| static int cmd_quit(int argc, char **argv){ return EX_UNAVAILABLE; } | ||||
| static int cmd_default_page(int argc, char **argv){ | ||||
| static int cmd_quit(int argc, char **argv, char **envp){return EX_UNAVAILABLE;} | ||||
| static int cmd_default_page(int argc, char **argv, char **envp){ | ||||
| 
 | ||||
| 	if(argc > 1) /* This shouldn't be possible. */ | ||||
| 		return EX_USAGE; | ||||
| @ -82,11 +146,11 @@ static int cmd_default_page(int argc, char **argv){ | ||||
| 	else | ||||
| 		return EX_SOFTWARE; | ||||
| } | ||||
| static int cmd_page_down_lines(int argc, char **argv){ | ||||
| static int cmd_page_down_lines(int argc, char **argv, char **envp){ | ||||
| 
 | ||||
| 	switch(argc){ | ||||
| 	case 1: | ||||
| 		return cmd_default_page(argc, argv); | ||||
| 		return cmd_default_page(argc, argv, envp); | ||||
| 	case 2: /* not implemented */ | ||||
| 	default: | ||||
| 		fprintf(stderr, "Usage: %s" /*" (lines)"*/ "\n", argv[0]); | ||||
| @ -95,13 +159,15 @@ static int cmd_page_down_lines(int argc, char **argv){ | ||||
| } | ||||
| 
 | ||||
| /* A CmdMap must be NULL-terminated. */ | ||||
| static struct CmdMap{ char *name; int (*fn)(int, char **); } builtins[] = { | ||||
| static struct CmdMap{ char *name; int (*fn)(int, char **, char **); } | ||||
| builtins[] = { | ||||
| 	{ "", cmd_default_page }, | ||||
| 	{ "+", cmd_page_down_lines }, | ||||
| 
 | ||||
| 	/* don't make the user feel trapped */ | ||||
| 	{ "exit", cmd_quit }, { "q", cmd_quit }, { ":q", cmd_quit }, | ||||
| 	{ ":q!", cmd_quit }, { "quit", cmd_quit }, { "ZZ", cmd_quit }, | ||||
| 	{ ":q", cmd_quit }, { ":q!", cmd_quit }, | ||||
| 	{ "exit", cmd_quit }, { "q", cmd_quit }, { "Q", cmd_quit }, | ||||
| 	{ "quit", cmd_quit }, { "ZZ", cmd_quit }, | ||||
| 	 | ||||
| 	{ NULL, NULL } | ||||
| }; | ||||
| @ -109,7 +175,7 @@ static struct CmdMap{ char *name; int (*fn)(int, char **); } builtins[] = { | ||||
| #define ARGV_MAX 10 | ||||
| /* Find and execute the command in the command map, given a corresponding
 | ||||
|  * command line. */ | ||||
| static int cmdline_exec(struct CmdMap *map, char *cmdline){ | ||||
| static int cmdline_exec(struct CmdMap *map, char *cmdline, char **envp){ | ||||
| 	/* Command line word splitting is naive and based on whitespace ONLY; no
 | ||||
| 	 * fancy quoting or escaping here. Adding that would (ideally) entail | ||||
| 	 * replacing strtok(3) with something specific to this task. */ | ||||
| @ -128,7 +194,7 @@ static int cmdline_exec(struct CmdMap *map, char *cmdline){ | ||||
| 
 | ||||
| 	for(; map->name != NULL; map = &map[1]) | ||||
| 		if(strcmp(map->name, argv[0]) == 0) | ||||
| 			return map->fn(argc, argv); | ||||
| 			return map->fn(argc, argv, envp); | ||||
| 
 | ||||
| 	fprintf(stderr, "%s: %s: not found\n", program_name, argv[0]); | ||||
| 	return EX_USAGE; | ||||
| @ -182,7 +248,7 @@ int main(int argc, char *argv[]){ | ||||
| 			return EX_OK; | ||||
| 
 | ||||
| 		{	int r; | ||||
| 			switch((r = cmdline_exec(builtins, (char *)cmd))){ | ||||
| 			switch((r = cmdline_exec(builtins, (char *)cmd, NULL))){ | ||||
| 			case EX_OK: case EX_USAGE: break; | ||||
| 			case EX_UNAVAILABLE: return EX_OK; | ||||
| 			default: return r; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user