Example #1
0
/*
 * 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;
}
Example #2
0
/*
 * 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;
}
Example #3
0
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;
}