Re: Patch for psql History Display on MacOSX - Mailing list pgsql-hackers
| From | Tom Lane |
|---|---|
| Subject | Re: Patch for psql History Display on MacOSX |
| Date | |
| Msg-id | 27815.1409626565@sss.pgh.pa.us Whole thread Raw |
| In response to | Re: Patch for psql History Display on MacOSX (Tom Lane <tgl@sss.pgh.pa.us>) |
| List | pgsql-hackers |
I've confirmed that the attached patches work as expected in both the
oldest and newest readline and libedit versions available to me.
Barring further objections, I plan to commit and back-patch these
changes.
regards, tom lane
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 74d4618..6033dfd 100644
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** EOF
*** 277,283 ****
<term><option>--no-readline</></term>
<listitem>
<para>
! Do not use <application>readline</application> for line editing and do not use the history.
This can be useful to turn off tab expansion when cutting and pasting.
</para>
</listitem>
--- 277,284 ----
<term><option>--no-readline</></term>
<listitem>
<para>
! Do not use <application>Readline</application> for line editing and do
! not use the command history.
This can be useful to turn off tab expansion when cutting and pasting.
</para>
</listitem>
*************** lo_import 152801
*** 2357,2368 ****
<term><literal>\s [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
<listitem>
<para>
! Print or save the command line history to <replaceable
! class="parameter">filename</replaceable>. If <replaceable
! class="parameter">filename</replaceable> is omitted, the history
! is written to the standard output. This option is only available
! if <application>psql</application> is configured to use the
! <acronym>GNU</acronym> <application>Readline</application> library.
</para>
</listitem>
</varlistentry>
--- 2358,2370 ----
<term><literal>\s [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
<listitem>
<para>
! Print <application>psql</application>'s command line history
! to <replaceable class="parameter">filename</replaceable>.
! If <replaceable class="parameter">filename</replaceable> is omitted,
! the history is written to the standard output (using the pager if
! appropriate). This command is not available
! if <application>psql</application> was built
! without <application>Readline</application> support.
</para>
</listitem>
</varlistentry>
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..2e01eb1 100644
*** a/src/bin/psql/input.c
--- b/src/bin/psql/input.c
***************
*** 11,16 ****
--- 11,17 ----
#include <unistd.h>
#endif
#include <fcntl.h>
+ #include <limits.h>
#include "input.h"
#include "settings.h"
*************** 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
--- 320,334 ----
/*
! * 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
--- 338,352 ----
* 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;
--- 360,365 ----
*************** saveHistory(char *fname, int max_lines,
*** 387,394 ****
if (errno == 0)
return true;
}
! else
! #endif
{
/* truncate what we have ... */
if (max_lines >= 0)
--- 384,390 ----
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)
{
--- 395,468 ----
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 *cur_hist;
+
+ if (!useHistory)
+ return false;
+
+ if (fname == NULL)
+ {
+ /* use pager, if enabled, when printing to console */
+ output = PageOutput(INT_MAX, 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; (cur_hist = history_get(i)) != NULL; i++)
+ {
+ fprintf(output, "%s\n", cur_hist->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;
}
--- 472,478 ----
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);
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index 2e01eb1..f3193a2 100644
*** a/src/bin/psql/input.c
--- b/src/bin/psql/input.c
*************** gets_fromFile(FILE *source)
*** 229,244 ****
static void
encode_history(void)
{
HIST_ENTRY *cur_hist;
char *cur_ptr;
! history_set_pos(0);
! for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
{
/* some platforms declare HIST_ENTRY.line as const char * */
for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
if (*cur_ptr == '\n')
*cur_ptr = NL_IN_HISTORY;
}
}
--- 229,246 ----
static void
encode_history(void)
{
+ int i;
HIST_ENTRY *cur_hist;
char *cur_ptr;
! for (i = history_base; (cur_hist = history_get(i)) != NULL; i++)
{
/* some platforms declare HIST_ENTRY.line as const char * */
for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
+ {
if (*cur_ptr == '\n')
*cur_ptr = NL_IN_HISTORY;
+ }
}
}
*************** encode_history(void)
*** 248,263 ****
static void
decode_history(void)
{
HIST_ENTRY *cur_hist;
char *cur_ptr;
! history_set_pos(0);
! for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
{
/* some platforms declare HIST_ENTRY.line as const char * */
for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
if (*cur_ptr == NL_IN_HISTORY)
*cur_ptr = '\n';
}
}
#endif /* USE_READLINE */
--- 250,267 ----
static void
decode_history(void)
{
+ int i;
HIST_ENTRY *cur_hist;
char *cur_ptr;
! for (i = history_base; (cur_hist = history_get(i)) != NULL; i++)
{
/* some platforms declare HIST_ENTRY.line as const char * */
for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
+ {
if (*cur_ptr == NL_IN_HISTORY)
*cur_ptr = '\n';
+ }
}
}
#endif /* USE_READLINE */
pgsql-hackers by date: