diff options
| author | Bob Weinand <bobwei9@hotmail.com> | 2014-10-24 19:22:45 +0200 | 
|---|---|---|
| committer | Bob Weinand <bobwei9@hotmail.com> | 2014-10-24 19:22:45 +0200 | 
| commit | 9b4d9ac6c7fbc6a53aee6c9b199046556e5fef13 (patch) | |
| tree | d6e968764930a4cc3ac99b39cc235c1fec50f4f5 /sapi/phpdbg/phpdbg_cmd.c | |
| parent | 411984c0e9402a4e7c2d2d0cf23069f9eef60860 (diff) | |
| parent | 36399428919ef518bcd744e120e48c00610a8b86 (diff) | |
| download | php-git-9b4d9ac6c7fbc6a53aee6c9b199046556e5fef13.tar.gz | |
Merge phpdbg into PHP-5.6
Diffstat (limited to 'sapi/phpdbg/phpdbg_cmd.c')
| -rw-r--r-- | sapi/phpdbg/phpdbg_cmd.c | 341 | 
1 files changed, 188 insertions, 153 deletions
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index a45513bee6..30ea48cfbe 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -23,6 +23,7 @@  #include "phpdbg_utils.h"  #include "phpdbg_set.h"  #include "phpdbg_prompt.h" +#include "phpdbg_io.h"  ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -39,7 +40,7 @@ static inline const char *phpdbg_command_name(const phpdbg_command_t *command, c  	memcpy(&buffer[pos], command->name, command->name_len);  	pos += command->name_len;  	buffer[pos] = 0; -	 +  	return buffer;  } @@ -231,12 +232,12 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des  		case STACK_PARAM:  			/* nope */  		break; -		 +  		case STR_PARAM:  			dest->str = estrndup(src->str, src->len);  			dest->len = src->len;  		break; -		 +  		case OP_PARAM:  			dest->str = estrndup(src->str, src->len);  			dest->len = src->len; @@ -276,7 +277,7 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des  		break;  		case EMPTY_PARAM: { /* do nothing */ } break; -		 +  		default: {  			/* not yet */  		} @@ -291,7 +292,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /  		case STACK_PARAM:  			/* nope */  		break; -		 +  		case STR_PARAM:  			hash += zend_inline_hash_func(param->str, param->len);  		break; @@ -329,7 +330,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /  		break;  		case EMPTY_PARAM: { /* do nothing */ } break; -		 +  		default: {  			/* not yet */  		} @@ -347,7 +348,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa  					/* nope, or yep */  					return 1;  				break; -				 +  				case NUMERIC_FUNCTION_PARAM:  					if (l->num != r->num) {  						break; @@ -402,7 +403,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa  				case EMPTY_PARAM:  					return 1; -					 +  				default: {  					/* not yet */  				} @@ -419,43 +420,43 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)  			case STR_PARAM:  				fprintf(stderr, "%s STR_PARAM(%s=%lu)\n", msg, param->str, param->len);  			break; -			 +  			case ADDR_PARAM:  				fprintf(stderr, "%s ADDR_PARAM(%lu)\n", msg, param->addr);  			break; -			 +  			case NUMERIC_FILE_PARAM:  				fprintf(stderr, "%s NUMERIC_FILE_PARAM(%s:#%lu)\n", msg, param->file.name, param->file.line);  			break; -			 +  			case FILE_PARAM:  				fprintf(stderr, "%s FILE_PARAM(%s:%lu)\n", msg, param->file.name, param->file.line);  			break; -			 +  			case METHOD_PARAM:  				fprintf(stderr, "%s METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name);  			break; -			 +  			case NUMERIC_METHOD_PARAM:  				fprintf(stderr, "%s NUMERIC_METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name);  			break; -			 +  			case NUMERIC_FUNCTION_PARAM:  				fprintf(stderr, "%s NUMERIC_FUNCTION_PARAM(%s::%ld)\n", msg, param->str, param->num);  			break; -			 +  			case NUMERIC_PARAM:  				fprintf(stderr, "%s NUMERIC_PARAM(%ld)\n", msg, param->num);  			break; -			 +  			case COND_PARAM:  				fprintf(stderr, "%s COND_PARAM(%s=%lu)\n", msg, param->str, param->len);  			break; -			 +  			case OP_PARAM:  				fprintf(stderr, "%s OP_PARAM(%s=%lu)\n", msg, param->str, param->len);  			break; -			 +  			default: {  				/* not yet */  			} @@ -467,13 +468,13 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)  PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {  	if (stack && stack->next) {  		phpdbg_param_t *remove = stack->next; -		 +  		while (remove) {  			phpdbg_param_t *next = NULL; -			 +  			if (remove->next)  				next = remove->next; -			 +  			switch (remove->type) {  				case NUMERIC_METHOD_PARAM:  				case METHOD_PARAM: @@ -487,29 +488,30 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {  				case STR_PARAM:  				case OP_PARAM:  					if (remove->str) -						free(remove->str);	 +						free(remove->str);  				break; -				 +  				case NUMERIC_FILE_PARAM:  				case FILE_PARAM:  					if (remove->file.name)  						free(remove->file.name);  				break; -				 +  				default: {  					/* nothing */  				}  			} -			 +  			free(remove);  			remove = NULL; -			 +  			if (next) -				remove = next;  +				remove = next;  			else break;  		}  	} -	 + +  	stack->next = NULL;  } /* }}} */ @@ -537,30 +539,29 @@ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param)  	stack->len++;  } /* }}} */ -PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) { +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC) {  	if (command) {  		char buffer[128] = {0,};  		const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL;  		const char *arg = command->args;  		size_t least = 0L, -			   received = 0L, -			   current = 0L; +		       received = 0L, +		       current = 0L;  		zend_bool optional = 0; -		 +  		/* check for arg spec */  		if (!(arg) || !(*arg)) {  			if (!top) {  				return SUCCESS;  			} -			 -			asprintf(why, -				"The command \"%s\" expected no arguments",  + +			phpdbg_error("command", "type=\"toomanyargs\" command=\"%s\" expected=\"0\"", "The command \"%s\" expected no arguments",   				phpdbg_command_name(command, buffer));  			return FAILURE;  		} -		 +  		least = 0L; -		 +  		/* count least amount of arguments */  		while (arg && *arg) {  			if (arg[0] == '|') { @@ -569,21 +570,19 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param  			least++;  			arg++;  		} -		 +  		arg = command->args;  #define verify_arg(e, a, t) if (!(a)) { \  	if (!optional) { \ -		asprintf(why, \ -			"The command \"%s\" expected %s and got nothing at parameter %lu", \ +		phpdbg_error("command", "type=\"noarg\" command=\"%s\" expected=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got nothing at parameter %lu", \  			phpdbg_command_name(command, buffer), \  			(e), \  			current); \  		return FAILURE;\  	} \  } else if ((a)->type != (t)) { \ -	asprintf(why, \ -		"The command \"%s\" expected %s and got %s at parameter %lu", \ +	phpdbg_error("command", "type=\"wrongarg\" command=\"%s\" expected=\"%s\" got=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got %s at parameter %lu", \  		phpdbg_command_name(command, buffer), \  		(e),\  		phpdbg_get_param_type((a) TSRMLS_CC), \ @@ -593,14 +592,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param  		while (arg && *arg) {  			current++; -			 +  			switch (*arg) {  				case '|': {  					current--;  					optional = 1;  					arg++;  				} continue; -				 +  				case 'i': verify_arg("raw input", top, STR_PARAM); break;  				case 's': verify_arg("string", top, STR_PARAM); break;  				case 'n': verify_arg("number", top, NUMERIC_PARAM); break; @@ -610,14 +609,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param  				case 'c': verify_arg("condition", top, COND_PARAM); break;  				case 'o': verify_arg("opcode", top, OP_PARAM); break;  				case 'b': verify_arg("boolean", top, NUMERIC_PARAM); break; -				 +  				case '*': { /* do nothing */ } break;  			} -			 +  			if (top ) {  				top = top->next;  			} else break; -			 +  			received++;  			arg++;  		} @@ -625,28 +624,27 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param  #undef verify_arg  		if ((received < least)) { -			asprintf(why, -				"The command \"%s\" expected at least %lu arguments (%s) and received %lu", +			phpdbg_error("command", "type=\"toofewargs\" command=\"%s\" expected=\"%d\" argtypes=\"%s\" got=\"%d\"", "The command \"%s\" expected at least %lu arguments (%s) and received %lu",  				phpdbg_command_name(command, buffer),  				least, -				command->args,  +				command->args,  				received);  			return FAILURE;  		}  	} -	 +  	return SUCCESS;  }  /* {{{ */ -PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) { +PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC) {  	const phpdbg_command_t *command = commands;  	phpdbg_param_t *name = *top;  	const phpdbg_command_t *matched[3] = {NULL, NULL, NULL};  	ulong matches = 0L; -	 +  	while (command && command->name && command->handler) { -		if ((name->len == 1) || (command->name_len >= name->len)) { +		if (name->len == 1 || command->name_len >= name->len) {  			/* match single letter alias */  			if (command->alias && (name->len == 1)) {  				if (command->alias == (*name->str)) { @@ -654,85 +652,76 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *  					matches++;  				}  			} else { -  				/* match full, case insensitive, command name */  				if (strncasecmp(command->name, name->str, name->len) == SUCCESS) {  					if (matches < 3) { -						  						/* only allow abbreviating commands that can be aliased */ -						if (((name->len != command->name_len) && command->alias) || -							(name->len == command->name_len)) { +						if ((name->len != command->name_len && command->alias) || name->len == command->name_len) {  							matched[matches] = command;  							matches++;  						} -						 -						 +  						/* exact match */ -						if (name->len == command->name_len) +						if (name->len == command->name_len) {  							break; -					} else break; +						} +					} else { +						break; +					}  				}  			}  		} -		 +  		command++;  	} -	 +  	switch (matches) { -		case 0: { +		case 0:  			if (parent) { -				asprintf( -				why, -				"The command \"%s %s\" could not be found",  -				parent->name, name->str); -			} else asprintf( -				why, -				"The command \"%s\" could not be found",  -				name->str); -		} return parent; -		 -		case 1: { +				phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found", parent->name, name->str); +			} else { +				phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str); +			} +			return parent; + +		case 1:  			(*top) = (*top)->next;  			command = matched[0]; -		} break; -		 +			break; +  		default: {  			char *list = NULL;  			zend_uint it = 0;  			size_t pos = 0; -			 +  			while (it < matches) {  				if (!list) { -					list = malloc( -						matched[it]->name_len + 1 +  -						((it+1) < matches ? sizeof(", ")-1 : 0)); +					list = emalloc(matched[it]->name_len + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0));  				} else { -					list = realloc(list,  -						(pos + matched[it]->name_len) + 1  +  -						((it+1) < matches ? sizeof(", ")-1 : 0)); +					list = erealloc(list, (pos + matched[it]->name_len) + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0));  				}  				memcpy(&list[pos], matched[it]->name, matched[it]->name_len);  				pos += matched[it]->name_len; -				if ((it+1) < matches) { -					memcpy(&list[pos], ", ", sizeof(", ")-1); +				if ((it + 1) < matches) { +					memcpy(&list[pos], ", ", sizeof(", ") - 1);  					pos += (sizeof(", ") - 1);  				} -				 +  				list[pos] = 0;  				it++;  			} -			 -			asprintf( -				why, -				"The command \"%s\" is ambigious, matching %lu commands (%s)",  -				name->str, matches, list); -			free(list); -		} return NULL; + +			/* ", " separated matches */ +			phpdbg_error("command", "type=\"ambiguous\" command=\"%s\" matches=\"%lu\" matched=\"%s\"", "The command \"%s\" is ambigious, matching %lu commands (%s)", name->str, matches, list); +			efree(list); + +			return NULL; +		}  	}  	if (command->subs && (*top) && ((*top)->type == STR_PARAM)) { -		return phpdbg_stack_resolve(command->subs, command, top, why); +		return phpdbg_stack_resolve(command->subs, command, top TSRMLS_CC);  	} else {  		return command;  	} @@ -741,103 +730,148 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *  } /* }}} */  /* {{{ */ -PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) { +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC) {  	phpdbg_param_t *top = NULL;  	const phpdbg_command_t *handler = NULL; -	 +  	if (stack->type != STACK_PARAM) { -		asprintf( -			why, "The passed argument was not a stack !!"); +		phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !");  		return FAILURE;  	} -	 +  	if (!stack->len) { -		asprintf( -			why, "The stack contains nothing !!"); +		phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !");  		return FAILURE;  	} -	 -	top = (phpdbg_param_t*) stack->next; -	 + +	top = (phpdbg_param_t *) stack->next; +  	switch (top->type) {  		case EVAL_PARAM: +			phpdbg_activate_err_buf(0 TSRMLS_CC); +			phpdbg_free_err_buf(TSRMLS_C);  			return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC);  		case RUN_PARAM: +			if (!allow_async_unsafe) { +				phpdbg_error("signalsegv", "command=\"run\"", "run command is disallowed during hard interrupt"); +			} +			phpdbg_activate_err_buf(0 TSRMLS_CC); +			phpdbg_free_err_buf(TSRMLS_C);  			return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC); -		 +  		case SHELL_PARAM: +			if (!allow_async_unsafe) { +				phpdbg_error("signalsegv", "command=\"sh\"", "sh command is disallowed during hard interrupt"); +				return FAILURE; +			} +			phpdbg_activate_err_buf(0 TSRMLS_CC); +			phpdbg_free_err_buf(TSRMLS_C);  			return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC); -		 +  		case STR_PARAM: { -			handler = phpdbg_stack_resolve( -				phpdbg_prompt_commands, NULL, &top, why); -			 +			handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top TSRMLS_CC); +  			if (handler) { -				if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) { +				if (!allow_async_unsafe && !(handler->flags & PHPDBG_ASYNC_SAFE)) { +					phpdbg_error("signalsegv", "command=\"%s\"", "%s command is disallowed during hard interrupt", handler->name); +					return FAILURE; +				} + +				if (phpdbg_stack_verify(handler, &top TSRMLS_CC) == SUCCESS) { +					phpdbg_activate_err_buf(0 TSRMLS_CC); +					phpdbg_free_err_buf(TSRMLS_C);  					return handler->handler(top TSRMLS_CC);  				}  			}  		} return FAILURE; -		 +  		default: -			asprintf( -				why, "The first parameter makes no sense !!"); +			phpdbg_error("command", "type=\"invalidcommand\"", "The first parameter makes no sense !");  			return FAILURE;  	} -	 +  	return SUCCESS;  } /* }}} */ -PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ +PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */  {  	char *cmd = NULL; -#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) -	char buf[PHPDBG_MAX_CMD]; -#endif  	char *buffer = NULL;  	if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { -		if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && -			(buffered == NULL)) { -			fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); +		if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) { +			fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);  		}  		if (buffered == NULL) { -disconnect:  			if (0) { +disconnect:  				PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);  				zend_bailout();  				return NULL;  			} -#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) -			if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { -				if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) { +#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)) + +			/* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */ +			/* strongly assuming to be in blocking mode... */ +#if USE_LIB_STAR +readline: +			if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) +#endif +			{ +				char buf[PHPDBG_MAX_CMD]; +				int bytes = PHPDBG_G(input_buflen), len = 0; +				if (PHPDBG_G(input_buflen)) { +					memcpy(buf, PHPDBG_G(input_buffer), bytes); +				} + +				phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C)); +				PHPDBG_G(last_was_newline) = 1; + +				do { +					int i; +					if (bytes <= 0) {  +						continue; +					} + +					for (i = len; i < len + bytes; i++) { +						if (buf[i] == '\x03') { +							if (i != len + bytes - 1) { +								memmove(buf + i, buf + i + 1, len + bytes - i - 1); +							} +							len--; +							i--; +							continue; +						} +						if (buf[i] == '\n') { +							PHPDBG_G(input_buflen) = len + bytes - 1 - i; +							if (PHPDBG_G(input_buflen)) { +								memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); +							} +							if (i != PHPDBG_MAX_CMD - 1) { +								buf[i + 1] = 0; +							} +							cmd = buf; +							goto end; +						} +					} +					len += bytes; +					/* XXX export the timeout through INI??*/ +				} while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); + +				if (bytes <= 0) {  					goto disconnect;  				} + +				cmd = buf;  			} -			 -			/* note: EOF is ignored */ -readline:	 -			if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { -				/* the user has gone away */ -				if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { -					goto disconnect; -				} else goto readline; +#if USE_LIB_STAR +			else { +				cmd = readline(phpdbg_get_prompt(TSRMLS_C));  			} -			cmd = buf; -#else -			/* note: EOF makes readline write prompt again in local console mode */ -readline: -			if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { -				char buf[PHPDBG_MAX_CMD]; -				if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { -					cmd = buf; -				} else goto disconnect; -			} else cmd = readline(phpdbg_get_prompt(TSRMLS_C)); -  			if (!cmd) {  				goto readline;  			} @@ -846,13 +880,15 @@ readline:  				add_history(cmd);  			}  #endif -		} else cmd = buffered; -		 +		} else { +			cmd = buffered; +		} +end: +		PHPDBG_G(last_was_newline) = 1;  		buffer = estrdup(cmd); -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) -		if (!buffered && cmd && -			!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { +#if USE_LIB_STAR +		if (!buffered && cmd &&	!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {  			free(cmd);  		}  #endif @@ -878,7 +914,7 @@ readline:  			buffer = estrdup(PHPDBG_G(buffer));  		}  	} -	 +  	return buffer;  } /* }}} */ @@ -886,4 +922,3 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */  {  	efree(*input);  } /* }}} */ -  | 
