* Add Simon Ruderich patch adding pager support to r_cons (thanks!)
authorpancake@pair
Sun Feb 05 02:39:04 2012 +0100 (3 months ago)
changeset 20151e3c0a90cb7c
parent 2014 97442099e4a5
child 2016 979f6d33a343
* Add Simon Ruderich patch adding pager support to r_cons (thanks!)
- Add new cfg.pager configuration variable
- by default no pager is used (cfg.pager is empty).
libr/cons/cons.c
libr/core/config.c
libr/include/r_cons.h
libr/include/r_util.h
libr/util/sys.c
     1.1 --- a/libr/cons/cons.c	Sun Feb 05 02:30:08 2012 +0100
     1.2 +++ b/libr/cons/cons.c	Sun Feb 05 02:39:04 2012 +0100
     1.3 @@ -119,6 +119,7 @@
     1.4  	if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE)__w32_control, TRUE))
     1.5  		eprintf ("r_cons: Cannot set control console handler\n");
     1.6  #endif
     1.7 +	I.pager = NULL; /* no pager by default */
     1.8  	//r_cons_palette_init(NULL);
     1.9  	r_cons_reset ();
    1.10  	return &I;
    1.11 @@ -223,7 +224,15 @@
    1.12  		return;
    1.13  	r_cons_filter ();
    1.14  	if (I.is_interactive) {
    1.15 -		if (I.buffer_len > CONS_MAX_USER) {
    1.16 +		/* Use a pager if the output doesn't fit on the terminal window. */
    1.17 +		if (I.pager && *(I.pager)
    1.18 +				&& I.buffer_len > 0
    1.19 +				&& r_str_char_count (I.buffer, '\n') >= I.rows) {
    1.20 +			I.buffer[I.buffer_len-1] = 0;
    1.21 +			r_sys_cmd_str_full(I.pager, I.buffer, NULL, NULL, NULL);
    1.22 +			r_cons_reset ();
    1.23 +
    1.24 +		} else if (I.buffer_len > CONS_MAX_USER) {
    1.25  			if (!r_cons_yesno ('n',"Do you want to print %d bytes? (y/N)",
    1.26  					I.buffer_len)) {
    1.27  				r_cons_reset ();
     2.1 --- a/libr/core/config.c	Sun Feb 05 02:30:08 2012 +0100
     2.2 +++ b/libr/core/config.c	Sun Feb 05 02:39:04 2012 +0100
     2.3 @@ -1,4 +1,4 @@
     2.4 -/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
     2.5 +/* radare - LGPL - Copyright 2009-2012 pancake<nopcode.org> */
     2.6  
     2.7  #include <r_core.h>
     2.8  
     2.9 @@ -393,6 +393,15 @@
    2.10  	return R_TRUE;
    2.11  }
    2.12  
    2.13 +static int config_pager_callback(void *user, void *data) {
    2.14 +	RCore *core = (RCore *) user;
    2.15 +	RConfigNode *node = (RConfigNode *) data;
    2.16 +
    2.17 +	/* Let cons know we have a new pager. */
    2.18 +	core->cons->pager = node->value;
    2.19 +	return R_TRUE;
    2.20 +}
    2.21 +
    2.22  #define SLURP_LIMIT (10*1024*1024)
    2.23  R_API int r_core_config_init(RCore *core) {
    2.24  	RConfig *cfg = cfg = core->config = r_config_new (core);
    2.25 @@ -475,6 +484,7 @@
    2.26  	r_config_desc (cfg, "asm.syntax", "Select assembly syntax");
    2.27  	r_config_set_cb (cfg, "asm.profile", "default", &config_asmprofile_callback);
    2.28  	r_config_desc (cfg, "asm.profile", "configure disassembler (default, simple, gas, smart, debug, full)");
    2.29 +	/* misc */
    2.30  #if LIL_ENDIAN
    2.31  	r_config_set_cb (cfg, "cfg.bigendian", "false", &config_bigendian_callback);
    2.32  #else
    2.33 @@ -493,7 +503,7 @@
    2.34  	r_config_desc (cfg, "cfg.wseek", "Seek after write");
    2.35  	r_config_set_i (cfg, "cfg.hashlimit", SLURP_LIMIT);
    2.36  	r_config_desc (cfg, "cfg.hashlimit", "If the file its bigger than hashlimit don't calculate the hash");
    2.37 -
    2.38 +	/* debug */
    2.39  	r_config_set_i (cfg, "dbg.follow", 32);
    2.40  	r_config_desc (cfg, "dbg.follow", "Follow program counter when pc > core->offset + dbg.follow");
    2.41  	r_config_set_cb (cfg, "dbg.backend", "native", &config_dbgbackend_callback);
    2.42 @@ -541,6 +551,8 @@
    2.43  		(core->print->flags&R_PRINT_FLAGS_COLOR)?"true":"false",
    2.44  		&config_color_callback);
    2.45  	r_config_desc (cfg, "scr.color", "Enable/Disable colors");
    2.46 +	r_config_set_cb (cfg, "scr.pager", "", &config_pager_callback);
    2.47 +	r_config_desc (cfg, "scr.pager", "Select pager program (used if output doesn't fit on window)");
    2.48  	//r_config_set_cb (cfg, "scr.fkey", "function", &config_scrfkey_callback);
    2.49  	r_config_set_cb (cfg, "scr.fkey", "hit", &config_scrfkey_callback);
    2.50  	r_config_desc (cfg, "scr.fkey", "Select the seek mode in visual");
     3.1 --- a/libr/include/r_cons.h	Sun Feb 05 02:30:08 2012 +0100
     3.2 +++ b/libr/include/r_cons.h	Sun Feb 05 02:39:04 2012 +0100
     3.3 @@ -71,6 +71,9 @@
     3.4  	LPDWORD term_raw, term_buf;
     3.5  #endif
     3.6  	RNum *num;
     3.7 +	/* Pager (like more or less) to use if the output doesn't fit on the
     3.8 +	 * current window. If NULL or "" no pager is used. */
     3.9 +	char *pager;
    3.10  } RCons;
    3.11  
    3.12  // XXX THIS MUST BE A SINGLETON AND WRAPPED INTO RCons */
     4.1 --- a/libr/include/r_util.h	Sun Feb 05 02:30:08 2012 +0100
     4.2 +++ b/libr/include/r_util.h	Sun Feb 05 02:39:04 2012 +0100
     4.3 @@ -423,7 +423,7 @@
     4.4  R_API int r_sys_setenv(const char *key, const char *value);
     4.5  R_API char *r_sys_getdir();
     4.6  R_API int r_sys_chdir(const char *s);
     4.7 -R_API char *r_sys_cmd_str_full(const char *cmd, const char *input, int *len, char **sterr);
     4.8 +R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr);
     4.9  #if __WINDOWS__
    4.10  R_API char *r_sys_cmd_str_w32(const char *cmd);
    4.11  #endif
     5.1 --- a/libr/util/sys.c	Sun Feb 05 02:30:08 2012 +0100
     5.2 +++ b/libr/util/sys.c	Sun Feb 05 02:39:04 2012 +0100
     5.3 @@ -209,49 +209,51 @@
     5.4  }
     5.5  
     5.6  #if __UNIX__
     5.7 -R_API char *r_sys_cmd_str_full(const char *cmd, const char *input, int *len, char **sterr) {
     5.8 -	char buffer[1024], *output = NULL;
     5.9 +R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
    5.10 +	char buffer[1024], *outputptr = NULL;
    5.11  	char *inputptr = (char *)input;
    5.12  	int pid, bytes = 0, status;
    5.13  	int sh_in[2], sh_out[2], sh_err[2];
    5.14  
    5.15  	if (len) *len = 0;
    5.16  	if (pipe (sh_in)) 
    5.17 -		return NULL;
    5.18 -	if (pipe (sh_out)) {
    5.19 -		close (sh_in[0]);
    5.20 -		close (sh_in[1]);
    5.21 -		return NULL;
    5.22 +		return R_FALSE;
    5.23 +	if (output) {
    5.24 +		if (pipe (sh_out)) {
    5.25 +			close (sh_in[0]);
    5.26 +			close (sh_in[1]);
    5.27 +			return R_FALSE;
    5.28 +		}
    5.29  	}
    5.30  	if (pipe (sh_err)) {
    5.31  		close (sh_in[0]);
    5.32  		close (sh_in[1]);
    5.33  		close (sh_out[0]);
    5.34  		close (sh_out[1]);
    5.35 -		return NULL;
    5.36 +		return R_FALSE;
    5.37  	}
    5.38  
    5.39  	switch ((pid=fork ())) {
    5.40  	case -1:
    5.41 -		return NULL;
    5.42 +		return R_FALSE;
    5.43  	case 0:
    5.44  		dup2 (sh_in[0], 0); close (sh_in[0]); close (sh_in[1]);
    5.45 -		dup2 (sh_out[1], 1); close (sh_out[0]); close (sh_out[1]);
    5.46 +		if (output) { dup2 (sh_out[1], 1); close (sh_out[0]); close (sh_out[1]); }
    5.47  		if (sterr) dup2 (sh_err[1], 2); else close (2);
    5.48  		close (sh_err[0]); close (sh_err[1]); 
    5.49  		exit (execl ("/bin/sh", "sh", "-c", cmd, (char*)NULL));
    5.50  	default:
    5.51 -		output = strdup ("");
    5.52 -		if (!output)
    5.53 -			return NULL;
    5.54 +		outputptr = strdup ("");
    5.55 +		if (!outputptr)
    5.56 +			return R_FALSE;
    5.57  		if (sterr) {
    5.58  			*sterr = strdup ("");
    5.59  			if (!*sterr) {
    5.60 -				free (output);
    5.61 -				return NULL;
    5.62 +				free (outputptr);
    5.63 +				return R_FALSE;
    5.64  			}
    5.65  		}
    5.66 -		close (sh_out[1]);
    5.67 +		if (output) close (sh_out[1]);
    5.68  		close (sh_err[1]);
    5.69  		close (sh_in[0]);
    5.70  		if (!inputptr || !*inputptr)
    5.71 @@ -263,7 +265,8 @@
    5.72  
    5.73  			FD_ZERO (&rfds);
    5.74  			FD_ZERO (&wfds);
    5.75 -			FD_SET (sh_out[0], &rfds);
    5.76 +			if (output)
    5.77 +				FD_SET (sh_out[0], &rfds);
    5.78  			if (sterr) 
    5.79  				FD_SET (sh_err[0], &rfds);
    5.80  			if (inputptr && *inputptr)
    5.81 @@ -272,46 +275,59 @@
    5.82  			nfd = select (sh_err[0] + 1, &rfds, &wfds, NULL, NULL);
    5.83  			if (nfd < 0)
    5.84  				break;
    5.85 -			if (FD_ISSET (sh_out[0], &rfds)) {
    5.86 +			if (output && FD_ISSET (sh_out[0], &rfds)) {
    5.87  				if ((bytes = read (sh_out[0], buffer, sizeof (buffer)-1)) == 0) break;
    5.88  				if (len) *len += bytes;
    5.89 -				output = r_str_concat (output, buffer);
    5.90 +				outputptr = r_str_concat (outputptr, buffer);
    5.91  			} else if (FD_ISSET (sh_err[0], &rfds) && sterr) {
    5.92  				if (read (sh_err[0], buffer, sizeof (buffer)-1) == 0) break;
    5.93  				*sterr = r_str_concat (*sterr, buffer);
    5.94  			} else if (FD_ISSET (sh_in[1], &wfds) && inputptr && *inputptr) {
    5.95  				bytes = write (sh_in[1], inputptr, strlen (inputptr));
    5.96  				inputptr += bytes;
    5.97 -				if (!*inputptr) close (sh_in[1]);
    5.98 +				if (!*inputptr) {
    5.99 +					close (sh_in[1]);
   5.100 +					/* If neither stdout nor stderr should be captured,
   5.101 +					 * abort now - nothing more to do for select(). */
   5.102 +					if (!output && !sterr) break;
   5.103 +				}
   5.104  			}
   5.105  		}
   5.106 -		close (sh_out[0]);
   5.107 +		if (output)
   5.108 +			close (sh_out[0]);
   5.109  		close (sh_err[0]);
   5.110  		close (sh_in[1]);
   5.111  		waitpid (pid, &status, 0);
   5.112  		if (status != 0) {
   5.113  			eprintf ("%s: command '%s' returned !0\n", __func__, cmd);
   5.114 -			return (NULL);
   5.115 +			return R_FALSE;
   5.116  		}
   5.117  
   5.118  		if (output) {
   5.119 -			if (*output)
   5.120 -				return output;
   5.121 -			free (output);
   5.122 +			*output = outputptr;
   5.123 +		} else if (outputptr) {
   5.124 +			free(outputptr);
   5.125  		}
   5.126 +		return R_TRUE;
   5.127  	}
   5.128 -	return NULL;
   5.129 +	return R_FALSE;
   5.130  }
   5.131  #elif __WINDOWS__
   5.132 -R_API char *r_sys_cmd_str_full(const char *cmd, const char *input, int *len, char **sterr) {
   5.133 +R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
   5.134  	// TODO: fully implement the rest
   5.135 +	char *result;
   5.136  	if (len) *len = 0;
   5.137 -	return r_sys_cmd_str_w32 (cmd);
   5.138 +	result = r_sys_cmd_str_w32 (cmd);
   5.139 +	if (output)
   5.140 +		*output = result;
   5.141 +	if (result)
   5.142 +		return R_TRUE;
   5.143 +	return R_FALSE;
   5.144  }
   5.145  #else
   5.146 -R_API char *r_sys_cmd_str_full(const char *cmd, const char *input, int *len, char **sterr) {
   5.147 +R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
   5.148  	eprintf ("r_sys_cmd_str: not yet implemented for this platform\n");
   5.149 -	return NULL;
   5.150 +	return R_FALSE;
   5.151  }
   5.152  #endif
   5.153  
   5.154 @@ -352,7 +368,10 @@
   5.155  }
   5.156  
   5.157  R_API char *r_sys_cmd_str(const char *cmd, const char *input, int *len) {
   5.158 -	return r_sys_cmd_str_full (cmd, input, len, NULL);
   5.159 +	char *output;
   5.160 +	if (r_sys_cmd_str_full (cmd, input, &output, len, NULL))
   5.161 +		return output;
   5.162 +	return NULL;
   5.163  }
   5.164  
   5.165  R_API int r_sys_rmkdir(const char *dir) {