Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:59084 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 63781 invoked from network); 20 Mar 2012 19:06:50 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 20 Mar 2012 19:06:50 -0000 Authentication-Results: pb1.pair.com smtp.mail=osama.sorour@eformations.net; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=osama.sorour@eformations.net; sender-id=unknown Received-SPF: error (pb1.pair.com: domain eformations.net from 74.125.82.170 cause and error) X-PHP-List-Original-Sender: osama.sorour@eformations.net X-Host-Fingerprint: 74.125.82.170 mail-we0-f170.google.com Received: from [74.125.82.170] ([74.125.82.170:47793] helo=mail-we0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 16/C0-59347-945D86F4 for ; Tue, 20 Mar 2012 14:06:50 -0500 Received: by mail-we0-f170.google.com with SMTP id h12so394671wer.29 for ; Tue, 20 Mar 2012 12:06:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:content-type:content-transfer-encoding:subject:date:message-id :to:mime-version:x-mailer:x-gm-message-state; bh=jvI/jU7jdgJZVIIyzcNY3R3HioZpvHkhJnbD1CTKgRc=; b=iSM8pq0e4T+9B8G4OzsrYFgcDRqF7CYzyOh5rMD6EUrlfMlGjQrnAIWAOpaa/SbGfa NHoa+rZWPwhWB4t5IblZZnBFdTTQu0fneedavqo1ANbmhbINlJumYlAYaBgIqiC2kXj9 h1QFgpiLebZTB36pcQz2v05fzMyZsTkP8iSODs3r2i4g5IgOrV502ftEq95JsaCt3EQM LFszzo16I1bIEO1pvpmuK1fgkdi+aQbyQezaZ13C/41ISELDbWyiJbEK0AZKMgNZkf/e sG5RSZCO2rQzLGKbRpb0/JGbtqZG0trm/+e2IRLkDJrC4IHu7r2k4rBLSFJpaJYAXveQ nwSQ== Received: by 10.216.139.79 with SMTP id b57mr548929wej.37.1332270409480; Tue, 20 Mar 2012 12:06:49 -0700 (PDT) Received: from [192.168.0.138] ([196.202.61.162]) by mx.google.com with ESMTPS id b3sm36117921wib.4.2012.03.20.12.06.47 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 20 Mar 2012 12:06:48 -0700 (PDT) Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Date: Tue, 20 Mar 2012 21:06:45 +0200 Message-ID: <11302143-55E0-48E9-AC30-943E6075E794@eformations.net> To: internals@lists.php.net Mime-Version: 1.0 (Apple Message framework v1257) X-Mailer: Apple Mail (2.1257) X-Gm-Message-State: ALoCoQmCdkEo6/gcG04tHCtTBvkWdZad0HlUFRylfIebgEvxWNizdS+UQOin0Q6uc8m1zfCzgCs9 Subject: [PATCH] readline extension bug fixes and enhancements From: osama.sorour@eformations.net (Osama Abu Elsorour) All, I was recently involved in a project that relied heavily on readline to = provide console text input capabilities. However I soon noticed that the = current readline extension has a serious bug and is lacking some = important functionality. This patch applies only to PHP compiled with libreadline (and don't have = an effect if compiled with libeditline). It adds/modifies/fixes the = following: - Fixes memory corruption caused by directly setting rl_line_buffer to = new buffer and not using rl_replace_line(). - Fixes a bad combination of preprocessor #if that would cause = readline_on_new_line() implementation not to compile when using = libreadline only. - Adds support for rl_bind_key function by exposing: function readline_bind_key_function($key, $callback_func) where: $key: Key code to bind to. $callback_func: A callback function in the form: function callback($key, $count) where $key and $count are the same = parameters passed from rl_bind_key() Setting $callback_func to null will cause the binding to be removed for = $key. - Modifies the behavior of readline_info() to allow for setting the = readline properties "point" and "end" (it used to only read them but not = set them). Patch below: --- php-5.4.0/ext/readline/readline.c 2012-01-01 15:15:04.000000000 = +0200 +++ php-5.4.0-patched/ext/readline/readline.c 2012-03-19 = 09:09:27.388174973 +0200 @@ -58,9 +58,13 @@ PHP_FUNCTION(readline_callback_read_char PHP_FUNCTION(readline_callback_handler_remove); PHP_FUNCTION(readline_redisplay); PHP_FUNCTION(readline_on_new_line); +PHP_FUNCTION(readline_bind_key_function); =20 static zval *_prepped_callback =3D NULL; +#endif =20 +#if HAVE_LIBREADLINE +static HashTable _bind_key_functions_ht; #endif =20 static zval *_readline_completion =3D NULL; @@ -121,10 +125,19 @@ ZEND_END_ARG_INFO() =20 ZEND_BEGIN_ARG_INFO(arginfo_readline_redisplay, 0) ZEND_END_ARG_INFO() +#endif =20 +#if HAVE_RL_ON_NEW_LINE | HAVE_LIBREADLINE ZEND_BEGIN_ARG_INFO(arginfo_readline_on_new_line, 0) ZEND_END_ARG_INFO() #endif + +#if HAVE_LIBREADLINE +ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_bind_key_function, 0, 0, 2) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, funcname) +ZEND_END_ARG_INFO() +#endif /* }}} */ =20 /* {{{ module stuff */ @@ -145,9 +158,12 @@ static const zend_function_entry php_rea PHP_FE(readline_callback_handler_remove, = arginfo_readline_callback_handler_remove) PHP_FE(readline_redisplay, arginfo_readline_redisplay) #endif -#if HAVE_RL_ON_NEW_LINE +#if HAVE_RL_ON_NEW_LINE | HAVE_LIBREADLINE PHP_FE(readline_on_new_line, arginfo_readline_on_new_line) #endif +#if HAVE_LIBREADLINE + PHP_FE(readline_bind_key_function, = arginfo_readline_bind_key_function) +#endif PHP_FE_END }; =20 @@ -170,6 +186,9 @@ ZEND_GET_MODULE(readline) =20 PHP_MINIT_FUNCTION(readline) { +#if HAVE_LIBREADLINE + zend_hash_init(&_bind_key_functions_ht, 255, NULL, = ZVAL_PTR_DTOR, 1); +#endif using_history(); return PHP_MINIT(cli_readline)(INIT_FUNC_ARGS_PASSTHRU); } @@ -193,6 +212,9 @@ PHP_RSHUTDOWN_FUNCTION(readline) } #endif =20 +#if HAVE_LIBREADLINE + zend_hash_destroy(&_bind_key_functions_ht); +#endif return SUCCESS; } =20 @@ -265,12 +287,20 @@ PHP_FUNCTION(readline_info) if (value) { /* XXX if (rl_line_buffer) = free(rl_line_buffer); */ convert_to_string_ex(value); - rl_line_buffer =3D = strdup(Z_STRVAL_PP(value)); + rl_replace_line(Z_STRVAL_PP(value), 1); } RETVAL_STRING(SAFE_STRING(oldstr),1); } else if (!strcasecmp(what, "point")) { + if (value) { + convert_to_long_ex(value); + rl_point =3D Z_LVAL_PP(value); + } RETVAL_LONG(rl_point); } else if (!strcasecmp(what, "end")) { + if (value) { + convert_to_long_ex(value); + rl_end =3D Z_LVAL_PP(value); + } RETVAL_LONG(rl_end); #ifdef HAVE_LIBREADLINE } else if (!strcasecmp(what, "mark")) { @@ -621,7 +651,7 @@ PHP_FUNCTION(readline_redisplay) =20 #endif =20 -#if HAVE_RL_ON_NEW_LINE +#if HAVE_RL_ON_NEW_LINE | HAVE_LIBREADLINE /* {{{ proto void readline_on_new_line(void) Inform readline that the cursor has moved to a new line */ PHP_FUNCTION(readline_on_new_line) @@ -632,6 +662,72 @@ PHP_FUNCTION(readline_on_new_line) =20 #endif =20 +/* {{{ proto bool readline_bind_key_function(string funcname)=20 + Readline rl_bind_key */ + +static int _readline_bind_key_cb(int count, int key) +{=20 + zval *params[2]; + TSRMLS_FETCH(); +=09 + params[0]=3D_readline_long_zval(key); + params[1]=3D_readline_long_zval(count); +=09 + zval **_callback_func =3D NULL; + long _key =3D key; + int r =3D zend_hash_find(&_bind_key_functions_ht, (char *) = &_key, sizeof(_key), (void **)&_callback_func); + if (r =3D=3D -1) + return -1; +=09 + int _return_int =3D 0; + zval *_callback_return =3D NULL; + MAKE_STD_ZVAL(_callback_return); +=09 + if (call_user_function(CG(function_table), NULL, = *_callback_func, _callback_return, 2, params TSRMLS_CC) =3D=3D SUCCESS) = { + _return_int =3D _callback_return->value.lval; + zval_dtor(_callback_return); + FREE_ZVAL(_callback_return); + } +=09 + return _return_int;=20 +} + +PHP_FUNCTION(readline_bind_key_function) +{ + long key; + zval *arg =3D NULL; + char *name =3D NULL; +=09 + if (FAILURE =3D=3D zend_parse_parameters(ZEND_NUM_ARGS() = TSRMLS_CC, "l!z", &key, &arg)) { + RETURN_FALSE; + } +=09 + if (Z_TYPE_P(arg) =3D=3D IS_NULL) { + zend_hash_del(&_bind_key_functions_ht, (char *)&key, = sizeof(key)); + rl_bind_key(key, rl_insert); + } + else { + if (!zend_is_callable(arg, 0, &name TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s = is not callable", name); + efree(name); + RETURN_FALSE; + } + efree(name); + =09 + zval *_temp_callback =3D NULL; + MAKE_STD_ZVAL(_temp_callback); + *_temp_callback =3D *arg; + zval_copy_ctor(_temp_callback); + =09 + zend_hash_add(&_bind_key_functions_ht, (char *)&key, = sizeof(key), &_temp_callback, sizeof(zval *), NULL); + =09 + rl_bind_key(key, &_readline_bind_key_cb); + } +=09 + RETURN_TRUE; +} + +/* }}} */ =20 #endif /* HAVE_LIBREADLINE */ =20