/* * This function is for saving the readline history when user * runs \s command or when psql finishes. * * We have an argument named encodeFlag to handle the cases differently. * In case of call via \s we don't really need to encode \n as \x01, * but when we save history for Readline we must do that conversion. */ bool saveHistory(char *fname, bool encodeFlag) { #ifdef USE_READLINE /* * Suppressing the write attempt when HISTFILE is set to /dev/null may * look like a negligible optimization, but it's necessary on e.g. Darwin, * where write_history will fail because it tries to chmod the target * file. */ if (useHistory && fname && strcmp(fname, DEVNULL) != 0) { if (encodeFlag) encode_history(); /* * return value of write_history is not standardized across GNU * readline and libedit. Therefore, check for errno becoming set to * see if the write failed. */ errno = 0; (void) write_history(fname); 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; }
/* * 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 /* * Suppressing the write attempt when HISTFILE is set to /dev/null may * look like a negligible optimization, but it's necessary on e.g. Darwin, * 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 * needed and then append what we've added. This avoids overwriting * history from other concurrent sessions (although there are still * race conditions when two sessions exit at about the same time). If * we don't have those functions, fall back to write_history(). * * Note: return value of write_history is not standardized across GNU * readline and libedit. Therefore, check for errno becoming set to * 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; /* truncate previous entries if needed */ if (max_lines >= 0) { nlines = Max(max_lines - history_lines_added, 0); (void) history_truncate_file(fname, nlines); } /* append_history fails if file doesn't already exist :-( */ fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600); if (fd >= 0) close(fd); /* append the appropriate number of lines */ if (max_lines >= 0) nlines = Min(max_lines, history_lines_added); else nlines = history_lines_added; errno = 0; (void) append_history(nlines, fname); if (errno == 0) return true; } else #endif { /* truncate what we have ... */ if (max_lines >= 0) stifle_history(max_lines); /* ... and overwrite file. Tough luck for concurrent sessions. */ errno = 0; (void) write_history(fname); 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 bool saveHistory(char *fname, int max_lines) { int errnum; /* * Suppressing the write attempt when HISTFILE is set to /dev/null may * look like a negligible optimization, but it's necessary on e.g. Darwin, * 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 * needed and then append what we've added. This avoids overwriting * history from other concurrent sessions (although there are still * race conditions when two sessions exit at about the same time). If * we don't have those functions, fall back to write_history(). */ #if defined(HAVE_HISTORY_TRUNCATE_FILE) && defined(HAVE_APPEND_HISTORY) { int nlines; int fd; /* truncate previous entries if needed */ if (max_lines >= 0) { nlines = Max(max_lines - history_lines_added, 0); (void) history_truncate_file(fname, nlines); } /* append_history fails if file doesn't already exist :-( */ fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600); if (fd >= 0) close(fd); /* append the appropriate number of lines */ if (max_lines >= 0) nlines = Min(max_lines, history_lines_added); else nlines = history_lines_added; errnum = append_history(nlines, fname); if (errnum == 0) return true; } #else /* don't have append support */ { /* truncate what we have ... */ if (max_lines >= 0) stifle_history(max_lines); /* ... and overwrite file. Tough luck for concurrent sessions. */ errnum = write_history(fname); if (errnum == 0) return true; } #endif psql_error("could not save history to file \"%s\": %s\n", fname, strerror(errnum)); } return false; }