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