Stepan Rutz <stepan.r...@gmx.de> writes:
> Anyway, I am sure the iteration used in encode_history and decode_history in 
> input.c does not work on libedit.

Yeah, I noticed your comment about that.  That seems odd; a look at the
Apple libedit sources suggests it should work.  I was just about to trace
through the logic and try to see what's happening.

The reason nobody noticed is possibly that libedit doesn't actually need
the newline-encoding hack.  However, we should probably fix the loops if
they aren't working as expected on libedit, just in case somebody tries
to copy the logic for some other purpose.

Meanwhile, attached is a draft patch that uses the history_get loop for
all \s operations, and simplifies saveHistory in consequence.

                        regards, tom lane

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index e16b4d5..e1949d8 100644
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** exec_command(const char *cmd,
*** 1088,1107 ****
  		char	   *fname = psql_scan_slash_option(scan_state,
  												   OT_NORMAL, NULL, true);
  
- #if defined(WIN32) && !defined(__CYGWIN__)
- 
- 		/*
- 		 * XXX This does not work for all terminal environments or for output
- 		 * containing non-ASCII characters; see comments in simple_prompt().
- 		 */
- #define DEVTTY	"con"
- #else
- #define DEVTTY	"/dev/tty"
- #endif
- 
  		expand_tilde(&fname);
! 		/* This scrolls off the screen when using /dev/tty */
! 		success = saveHistory(fname ? fname : DEVTTY, -1, false, false);
  		if (success && !pset.quiet && fname)
  			printf(_("Wrote history to file \"%s\".\n"), fname);
  		if (!fname)
--- 1088,1095 ----
  		char	   *fname = psql_scan_slash_option(scan_state,
  												   OT_NORMAL, NULL, true);
  
  		expand_tilde(&fname);
! 		success = printHistory(fname, pset.popt.topt.pager);
  		if (success && !pset.quiet && fname)
  			printf(_("Wrote history to file \"%s\".\n"), fname);
  		if (!fname)
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index aa32a3f..f43e4a2 100644
*** a/src/bin/psql/input.c
--- b/src/bin/psql/input.c
*************** initializeInput(int flags)
*** 319,340 ****
  
  
  /*
!  * This function saves the readline history when user
!  * runs \s command or when psql exits.
   *
   * fname: pathname of history file.  (Should really be "const char *",
   * but some ancient versions of readline omit the const-decoration.)
   *
   * max_lines: if >= 0, limit history file to that many entries.
-  *
-  * appendFlag: if true, try to append just our new lines to the file.
-  * If false, write the whole available history.
-  *
-  * encodeFlag: whether to encode \n as \x01.  For \s calls we don't wish
-  * to do that, but must do so when saving the final history file.
   */
! bool
! saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag)
  {
  #ifdef USE_READLINE
  
--- 319,333 ----
  
  
  /*
!  * This function saves the readline history when psql exits.
   *
   * fname: pathname of history file.  (Should really be "const char *",
   * but some ancient versions of readline omit the const-decoration.)
   *
   * max_lines: if >= 0, limit history file to that many entries.
   */
! static bool
! saveHistory(char *fname, int max_lines)
  {
  #ifdef USE_READLINE
  
*************** saveHistory(char *fname, int max_lines, 
*** 344,354 ****
  	 * where write_history will fail because it tries to chmod the target
  	 * file.
  	 */
! 	if (useHistory && fname &&
! 		strcmp(fname, DEVNULL) != 0)
  	{
! 		if (encodeFlag)
! 			encode_history();
  
  		/*
  		 * On newer versions of libreadline, truncate the history file as
--- 337,351 ----
  	 * where write_history will fail because it tries to chmod the target
  	 * file.
  	 */
! 	if (strcmp(fname, DEVNULL) != 0)
  	{
! 		/*
! 		 * Encode \n, since otherwise readline will reload multiline history
! 		 * entries as separate lines.  (libedit doesn't really need this, but
! 		 * we do it anyway since it's too hard to tell which implementation we
! 		 * are using.)
! 		 */
! 		encode_history();
  
  		/*
  		 * On newer versions of libreadline, truncate the history file as
*************** saveHistory(char *fname, int max_lines, 
*** 362,368 ****
  		 * see if the write failed.  Similarly for append_history.
  		 */
  #if defined(HAVE_HISTORY_TRUNCATE_FILE) && defined(HAVE_APPEND_HISTORY)
- 		if (appendFlag)
  		{
  			int			nlines;
  			int			fd;
--- 359,364 ----
*************** saveHistory(char *fname, int max_lines, 
*** 387,394 ****
  			if (errno == 0)
  				return true;
  		}
! 		else
! #endif
  		{
  			/* truncate what we have ... */
  			if (max_lines >= 0)
--- 383,389 ----
  			if (errno == 0)
  				return true;
  		}
! #else							/* don't have append support */
  		{
  			/* truncate what we have ... */
  			if (max_lines >= 0)
*************** saveHistory(char *fname, int max_lines, 
*** 399,417 ****
  			if (errno == 0)
  				return true;
  		}
  
  		psql_error("could not save history to file \"%s\": %s\n",
  				   fname, strerror(errno));
  	}
- #else
- 	/* only get here in \s case, so complain */
- 	psql_error("history is not supported by this installation\n");
  #endif
  
  	return false;
  }
  
  
  static void
  finishInput(void)
  {
--- 394,467 ----
  			if (errno == 0)
  				return true;
  		}
+ #endif
  
  		psql_error("could not save history to file \"%s\": %s\n",
  				   fname, strerror(errno));
  	}
  #endif
  
  	return false;
  }
  
  
+ /*
+  * Print history to the specified file, or to the console if fname is NULL
+  * (psql \s command)
+  *
+  * We used to use saveHistory() for this purpose, but that doesn't permit
+  * use of a pager; moreover libedit's implementation behaves incompatibly
+  * (preferring to encode its output) and may fail outright when the target
+  * file is specified as /dev/tty.
+  */
+ bool
+ printHistory(const char *fname, unsigned short int pager)
+ {
+ #ifdef USE_READLINE
+ 	FILE	   *output;
+ 	bool		is_pager;
+ 	int			i;
+ 	HIST_ENTRY *curr;
+ 
+ 	if (!useHistory)
+ 		return false;
+ 
+ 	if (fname == NULL)
+ 	{
+ 		/* use pager if appropriate when printing to console */
+ 		output = PageOutput(history_length, pager);
+ 		is_pager = true;
+ 	}
+ 	else
+ 	{
+ 		output = fopen(fname, "w");
+ 		if (output == NULL)
+ 		{
+ 			psql_error("could not save history to file \"%s\": %s\n",
+ 					   fname, strerror(errno));
+ 			return false;
+ 		}
+ 		is_pager = false;
+ 	}
+ 
+ 	for (i = history_base; (curr = history_get(i)) != NULL; i++)
+ 	{
+ 		fprintf(output, "%s\n", curr->line);
+ 	}
+ 
+ 	if (is_pager)
+ 		ClosePager(output);
+ 	else
+ 		fclose(output);
+ 
+ 	return true;
+ #else
+ 	psql_error("history is not supported by this installation\n");
+ 	return false;
+ #endif
+ }
+ 
+ 
  static void
  finishInput(void)
  {
*************** finishInput(void)
*** 421,427 ****
  		int			hist_size;
  
  		hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
! 		saveHistory(psql_history, hist_size, true, true);
  		free(psql_history);
  		psql_history = NULL;
  	}
--- 471,477 ----
  		int			hist_size;
  
  		hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
! 		(void) saveHistory(psql_history, hist_size);
  		free(psql_history);
  		psql_history = NULL;
  	}
diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h
index 1d10a22..1b22399 100644
*** a/src/bin/psql/input.h
--- b/src/bin/psql/input.h
*************** char	   *gets_interactive(const char *pr
*** 42,48 ****
  char	   *gets_fromFile(FILE *source);
  
  void		initializeInput(int flags);
! bool		saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag);
  
  void		pg_append_history(const char *s, PQExpBuffer history_buf);
  void		pg_send_history(PQExpBuffer history_buf);
--- 42,49 ----
  char	   *gets_fromFile(FILE *source);
  
  void		initializeInput(int flags);
! 
! bool		printHistory(const char *fname, unsigned short int pager);
  
  void		pg_append_history(const char *s, PQExpBuffer history_buf);
  void		pg_send_history(PQExpBuffer history_buf);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to