]> granicus.if.org Git - postgresql/blob - src/bin/psql/input.c
pgindent run for 8.2.
[postgresql] / src / bin / psql / input.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.60 2006/10/04 00:30:06 momjian Exp $
7  */
8 #include "postgres_fe.h"
9
10 #include "input.h"
11 #include "settings.h"
12 #include "tab-complete.h"
13 #include "common.h"
14
15 #ifndef WIN32
16 #define PSQLHISTORY ".psql_history"
17 #else
18 #define PSQLHISTORY "psql_history"
19 #endif
20
21 /* Runtime options for turning off readline and history */
22 /* (of course there is no runtime command for doing that :) */
23 #ifdef USE_READLINE
24 static bool useReadline;
25 static bool useHistory;
26 char       *psql_history;
27
28 /*
29  *      Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
30  *
31  *      It is assumed NL_IN_HISTORY will never be entered by the user
32  *      nor appear inside a multi-byte string.  0x00 is not properly
33  *      handled by the readline routines so it can not be used
34  *      for this purpose.
35  */
36 #define NL_IN_HISTORY   0x01
37 #endif
38
39 #ifdef HAVE_ATEXIT
40 static void finishInput(void);
41 #else
42 /* designed for use with on_exit() */
43 static void finishInput(int, void *);
44 #endif
45
46
47 /*
48  * gets_interactive()
49  *
50  * Gets a line of interactive input, using readline if desired.
51  * The result is a malloc'd string.
52  *
53  * Caller *must* have set up sigint_interrupt_jmp before calling.
54  */
55 char *
56 gets_interactive(const char *prompt)
57 {
58 #ifdef USE_READLINE
59         if (useReadline)
60         {
61                 char       *result;
62
63                 /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
64                 sigint_interrupt_enabled = true;
65
66                 /* On some platforms, readline is declared as readline(char *) */
67                 result = readline((char *) prompt);
68
69                 /* Disable SIGINT again */
70                 sigint_interrupt_enabled = false;
71
72                 return result;
73         }
74 #endif
75
76         fputs(prompt, stdout);
77         fflush(stdout);
78         return gets_fromFile(stdin);
79 }
80
81
82 /*
83  * Append the line to the history buffer, making sure there is a trailing '\n'
84  */
85 void
86 pg_append_history(const char *s, PQExpBuffer history_buf)
87 {
88 #ifdef USE_READLINE
89         if (useHistory && s && s[0])
90         {
91                 appendPQExpBufferStr(history_buf, s);
92                 if (s[strlen(s) - 1] != '\n')
93                         appendPQExpBufferChar(history_buf, '\n');
94         }
95 #endif
96 }
97
98
99 /*
100  * Emit accumulated history entry to readline's history mechanism,
101  * then reset the buffer to empty.
102  *
103  * Note: we write nothing if history_buf is empty, so extra calls to this
104  * function don't hurt.  There must have been at least one line added by
105  * pg_append_history before we'll do anything.
106  */
107 void
108 pg_send_history(PQExpBuffer history_buf)
109 {
110 #ifdef USE_READLINE
111         static char *prev_hist = NULL;
112
113         char       *s = history_buf->data;
114
115         if (useHistory && s[0])
116         {
117                 if (((pset.histcontrol & hctl_ignorespace) &&
118                          s[0] == ' ') ||
119                         ((pset.histcontrol & hctl_ignoredups) &&
120                          prev_hist && strcmp(s, prev_hist) == 0))
121                 {
122                         /* Ignore this line as far as history is concerned */
123                 }
124                 else
125                 {
126                         int                     i;
127
128                         /* Trim any trailing \n's (OK to scribble on history_buf) */
129                         for (i = strlen(s) - 1; i >= 0 && s[i] == '\n'; i--)
130                                 ;
131                         s[i + 1] = '\0';
132                         /* Save each previous line for ignoredups processing */
133                         if (prev_hist)
134                                 free(prev_hist);
135                         prev_hist = pg_strdup(s);
136                         /* And send it to readline */
137                         add_history(s);
138                 }
139         }
140
141         resetPQExpBuffer(history_buf);
142 #endif
143 }
144
145
146 /*
147  * gets_fromFile
148  *
149  * Gets a line of noninteractive input from a file (which could be stdin).
150  * The result is a malloc'd string.
151  *
152  * Caller *must* have set up sigint_interrupt_jmp before calling.
153  *
154  * Note: we re-use a static PQExpBuffer for each call.  This is to avoid
155  * leaking memory if interrupted by SIGINT.
156  */
157 char *
158 gets_fromFile(FILE *source)
159 {
160         static PQExpBuffer buffer = NULL;
161
162         char            line[1024];
163
164         if (buffer == NULL)                     /* first time through? */
165                 buffer = createPQExpBuffer();
166         else
167                 resetPQExpBuffer(buffer);
168
169         for (;;)
170         {
171                 char       *result;
172
173                 /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
174                 sigint_interrupt_enabled = true;
175
176                 /* Get some data */
177                 result = fgets(line, sizeof(line), source);
178
179                 /* Disable SIGINT again */
180                 sigint_interrupt_enabled = false;
181
182                 /* EOF? */
183                 if (result == NULL)
184                         break;
185
186                 appendPQExpBufferStr(buffer, line);
187
188                 /* EOL? */
189                 if (buffer->data[buffer->len - 1] == '\n')
190                 {
191                         buffer->data[buffer->len - 1] = '\0';
192                         return pg_strdup(buffer->data);
193                 }
194         }
195
196         if (buffer->len > 0)            /* EOF after reading some bufferload(s) */
197                 return pg_strdup(buffer->data);
198
199         /* EOF, so return null */
200         return NULL;
201 }
202
203
204 #ifdef USE_READLINE
205 /*
206  * Convert newlines to NL_IN_HISTORY for safe saving in readline history file
207  */
208 static void
209 encode_history(void)
210 {
211         HIST_ENTRY *cur_hist;
212         char       *cur_ptr;
213
214         history_set_pos(0);
215         for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
216         {
217                 /* some platforms declare HIST_ENTRY.line as const char * */
218                 for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
219                         if (*cur_ptr == '\n')
220                                 *cur_ptr = NL_IN_HISTORY;
221         }
222 }
223
224 /*
225  * Reverse the above encoding
226  */
227 static void
228 decode_history(void)
229 {
230         HIST_ENTRY *cur_hist;
231         char       *cur_ptr;
232
233         history_set_pos(0);
234         for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
235         {
236                 /* some platforms declare HIST_ENTRY.line as const char * */
237                 for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
238                         if (*cur_ptr == NL_IN_HISTORY)
239                                 *cur_ptr = '\n';
240         }
241 }
242 #endif   /* USE_READLINE */
243
244
245 /*
246  * Put any startup stuff related to input in here. It's good to maintain
247  * abstraction this way.
248  *
249  * The only "flag" right now is 1 for use readline & history.
250  */
251 void
252 initializeInput(int flags)
253 {
254 #ifdef USE_READLINE
255         if (flags & 1)
256         {
257                 const char *histfile;
258                 char            home[MAXPGPATH];
259
260                 useReadline = true;
261                 initialize_readline();
262
263                 useHistory = true;
264                 using_history();
265
266                 histfile = GetVariable(pset.vars, "HISTFILE");
267                 if (histfile == NULL)
268                 {
269                         if (get_home_path(home))
270                         {
271                                 psql_history = pg_malloc(strlen(home) + 1 +
272                                                                                  strlen(PSQLHISTORY) + 1);
273                                 snprintf(psql_history, MAXPGPATH, "%s/%s", home, PSQLHISTORY);
274                         }
275                 }
276                 else
277                 {
278                         psql_history = pg_strdup(histfile);
279                         expand_tilde(&psql_history);
280                 }
281
282                 if (psql_history)
283                 {
284                         read_history(psql_history);
285                         decode_history();
286                 }
287         }
288 #endif
289
290 #ifdef HAVE_ATEXIT
291         atexit(finishInput);
292 #else
293         on_exit(finishInput, NULL);
294 #endif
295 }
296
297
298 /*
299  * This function is for saving the readline history when user
300  * runs \s command or when psql finishes.
301  *
302  * We have an argument named encodeFlag to handle the cases differently.
303  * In case of call via \s we don't really need to encode \n as \x01,
304  * but when we save history for Readline we must do that conversion.
305  */
306 bool
307 saveHistory(char *fname, bool encodeFlag)
308 {
309 #ifdef USE_READLINE
310
311         /*
312          * Suppressing the write attempt when HISTFILE is set to /dev/null may
313          * look like a negligible optimization, but it's necessary on e.g. Darwin,
314          * where write_history will fail because it tries to chmod the target
315          * file.
316          */
317         if (useHistory && fname &&
318                 strcmp(fname, DEVNULL) != 0)
319         {
320                 if (encodeFlag)
321                         encode_history();
322
323                 /*
324                  * return value of write_history is not standardized across GNU
325                  * readline and libedit.  Therefore, check for errno becoming set to
326                  * see if the write failed.
327                  */
328                 errno = 0;
329                 (void) write_history(fname);
330                 if (errno == 0)
331                         return true;
332
333                 psql_error("could not save history to file \"%s\": %s\n",
334                                    fname, strerror(errno));
335         }
336 #else
337         /* only get here in \s case, so complain */
338         psql_error("history is not supported by this installation\n");
339 #endif
340
341         return false;
342 }
343
344
345 static void
346 #ifdef HAVE_ATEXIT
347 finishInput(void)
348 #else
349 finishInput(int exitstatus, void *arg)
350 #endif
351 {
352 #ifdef USE_READLINE
353         if (useHistory && psql_history)
354         {
355                 int                     hist_size;
356
357                 hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
358                 if (hist_size >= 0)
359                         stifle_history(hist_size);
360
361                 saveHistory(psql_history, true);
362                 free(psql_history);
363                 psql_history = NULL;
364         }
365 #endif
366 }