33 *
44 * Copyright (c) 2000-2006, PostgreSQL Global Development Group
55 *
6- * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.53 2006/03/21 13:38:12 momjian Exp $
6+ * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.54 2006/06/11 23:06:00 tgl Exp $
77 */
88#include "postgres_fe.h"
99
10- #include "pqexpbuffer.h"
1110#include "input.h"
11+ #include "pqexpbuffer.h"
1212#include "settings.h"
1313#include "tab-complete.h"
1414#include "common.h"
@@ -78,110 +78,89 @@ GetHistControlConfig(void)
7878#endif
7979
8080
81- static char *
82- gets_basic (const char prompt [])
83- {
84- fputs (prompt ,stdout );
85- fflush (stdout );
86- return gets_fromFile (stdin );
87- }
88-
89-
9081/*
9182 * gets_interactive()
9283 *
93- * Gets a line of interactive input, using readlineof desired.
84+ * Gets a line of interactive input, using readlineif desired.
9485 * The result is malloc'ed.
9586 */
9687char *
9788gets_interactive (const char * prompt )
9889{
9990#ifdef USE_READLINE
100- char * s ;
101-
10291if (useReadline )
92+ {
10393/* On some platforms, readline is declared as readline(char *) */
104- s = readline ((char * )prompt );
105- else
106- s = gets_basic (prompt );
107-
108- return s ;
109- #else
110- return gets_basic (prompt );
94+ return readline ((char * )prompt );
95+ }
11196#endif
97+
98+ fputs (prompt ,stdout );
99+ fflush (stdout );
100+ return gets_fromFile (stdin );
112101}
113102
114103
115- /* Put the line in the history buffer and also add the trailing \n */
104+ /*
105+ * Append the line to the history buffer, making sure there is a trailing '\n'
106+ */
116107void
117- pg_append_history (char * s ,PQExpBuffer history_buf )
108+ pg_append_history (const char * s ,PQExpBuffer history_buf )
118109{
119110#ifdef USE_READLINE
120-
121- int slen ;
122- if (useReadline && useHistory && s && s [0 ])
111+ if (useHistory && s && s [0 ])
123112{
124- slen = strlen (s );
125- if (s [slen - 1 ]== '\n' )
126- appendPQExpBufferStr (history_buf ,s );
127- else
128- {
129- appendPQExpBufferStr (history_buf ,s );
113+ appendPQExpBufferStr (history_buf ,s );
114+ if (s [strlen (s )- 1 ]!= '\n' )
130115appendPQExpBufferChar (history_buf ,'\n' );
131- }
132116}
133117#endif
134118}
135119
136120
137121/*
138- *Feed the string to readline
122+ * Emit accumulated history entry to readline's history mechanism,
123+ * then reset the buffer to empty.
124+ *
125+ * Note: we write nothing if history_buf is empty, so extra calls to this
126+ * function don't hurt. There must have been at least one line added by
127+ * pg_append_history before we'll do anything.
139128 */
140129void
141- pg_write_history ( char * s )
130+ pg_send_history ( PQExpBuffer history_buf )
142131{
143132#ifdef USE_READLINE
144- static char * prev_hist ;
145- int slen ,i ;
146-
147- if (useReadline && useHistory )
133+ static char * prev_hist = NULL ;
134+
135+ char * s = history_buf -> data ;
136+
137+ if (useHistory && s [0 ])
148138{
149- enum histcontrol HC ;
150-
151- /* Flushing of empty buffer should do nothing */
152- if (* s == 0 )
153- return ;
154-
155- prev_hist = NULL ;
156-
157- HC = GetHistControlConfig ();
139+ enum histcontrol HC = GetHistControlConfig ();
158140
159141if (((HC & hctl_ignorespace )&& s [0 ]== ' ' )||
160- ((HC & hctl_ignoredups )&& prev_hist && strcmp (s ,prev_hist )== 0 ))
142+ ((HC & hctl_ignoredups )&& prev_hist && strcmp (s ,prev_hist )== 0 ))
161143{
162144/* Ignore this line as far as history is concerned */
163145}
164146else
165147{
166- free ( prev_hist ) ;
167- slen = strlen ( s );
168- /* Trimthe trailing \n's */
169- for (i = slen - 1 ;i >=0 && s [i ]== '\n' ;i -- )
148+ int i ;
149+
150+ /* Trimany trailing \n's (OK to scribble on history_buf) */
151+ for (i = strlen ( s ) - 1 ;i >=0 && s [i ]== '\n' ;i -- )
170152;
171153s [i + 1 ]= '\0' ;
154+ /* Save each previous line for ignoredups processing */
155+ if (prev_hist )
156+ free (prev_hist );
172157prev_hist = pg_strdup (s );
158+ /* And send it to readline */
173159add_history (s );
174160}
175161}
176- #endif
177- }
178162
179- void
180- pg_clear_history (PQExpBuffer history_buf )
181- {
182- #ifdef USE_READLINE
183- if (useReadline && useHistory )
184- resetPQExpBuffer (history_buf );
163+ resetPQExpBuffer (history_buf );
185164#endif
186165}
187166
@@ -219,6 +198,9 @@ gets_fromFile(FILE *source)
219198
220199
221200#ifdef USE_READLINE
201+ /*
202+ * Convert newlines to NL_IN_HISTORY for safe saving in readline history file
203+ */
222204static void
223205encode_history (void )
224206{
@@ -232,6 +214,9 @@ encode_history(void)
232214* cur_ptr = NL_IN_HISTORY ;
233215}
234216
217+ /*
218+ * Reverse the above encoding
219+ */
235220static void
236221decode_history (void )
237222{
@@ -285,9 +270,10 @@ initializeInput(int flags)
285270}
286271
287272if (psql_history )
273+ {
288274read_history (psql_history );
289-
290- decode_history ();
275+ decode_history ();
276+ }
291277}
292278#endif
293279
@@ -299,11 +285,13 @@ initializeInput(int flags)
299285}
300286
301287
302- /* This function is designed for saving the readline history when user
303- * run \s command or when psql finishes.
304- * We have an argument named encodeFlag to handle those cases differently
305- * In that case of call via \s we don't really need to encode \n as \x01,
306- * but when we save history for Readline we must do that conversion
288+ /*
289+ * This function is for saving the readline history when user
290+ * runs \s command or when psql finishes.
291+ *
292+ * We have an argument named encodeFlag to handle the cases differently.
293+ * In case of call via \s we don't really need to encode \n as \x01,
294+ * but when we save history for Readline we must do that conversion.
307295 */
308296bool
309297saveHistory (char * fname ,bool encodeFlag )
@@ -316,7 +304,8 @@ saveHistory(char *fname, bool encodeFlag)
316304if (write_history (fname )== 0 )
317305return true;
318306
319- psql_error ("could not save history to file \"%s\": %s\n" ,fname ,strerror (errno ));
307+ psql_error ("could not save history to file \"%s\": %s\n" ,
308+ fname ,strerror (errno ));
320309}
321310#else
322311psql_error ("history is not supported by this installation\n" );