Fix obsolete comment regarding FSM truncation.
[PostgreSQL.git] / src / bin / psql / input.c
blobf854d7c10900d20f8929e059c9bfe96dea3bfd57
1 /*
2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
6 * $PostgreSQL$
7 */
8 #include "postgres_fe.h"
10 #include "input.h"
11 #include "settings.h"
12 #include "tab-complete.h"
13 #include "common.h"
15 #ifndef WIN32
16 #define PSQLHISTORY ".psql_history"
17 #else
18 #define PSQLHISTORY "psql_history"
19 #endif
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;
29 * Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
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.
36 #define NL_IN_HISTORY 0x01
37 #endif
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
48 * gets_interactive()
50 * Gets a line of interactive input, using readline if desired.
51 * The result is a malloc'd string.
53 * Caller *must* have set up sigint_interrupt_jmp before calling.
55 char *
56 gets_interactive(const char *prompt)
58 #ifdef USE_READLINE
59 if (useReadline)
61 char *result;
63 /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
64 sigint_interrupt_enabled = true;
66 /* On some platforms, readline is declared as readline(char *) */
67 result = readline((char *) prompt);
69 /* Disable SIGINT again */
70 sigint_interrupt_enabled = false;
72 return result;
74 #endif
76 fputs(prompt, stdout);
77 fflush(stdout);
78 return gets_fromFile(stdin);
83 * Append the line to the history buffer, making sure there is a trailing '\n'
85 void
86 pg_append_history(const char *s, PQExpBuffer history_buf)
88 #ifdef USE_READLINE
89 if (useHistory && s && s[0])
91 appendPQExpBufferStr(history_buf, s);
92 if (s[strlen(s) - 1] != '\n')
93 appendPQExpBufferChar(history_buf, '\n');
95 #endif
100 * Emit accumulated history entry to readline's history mechanism,
101 * then reset the buffer to empty.
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.
107 void
108 pg_send_history(PQExpBuffer history_buf)
110 #ifdef USE_READLINE
111 static char *prev_hist = NULL;
113 char *s = history_buf->data;
114 int i;
116 /* Trim any trailing \n's (OK to scribble on history_buf) */
117 for (i = strlen(s) - 1; i >= 0 && s[i] == '\n'; i--)
119 s[i + 1] = '\0';
121 if (useHistory && s[0])
123 if (((pset.histcontrol & hctl_ignorespace) &&
124 s[0] == ' ') ||
125 ((pset.histcontrol & hctl_ignoredups) &&
126 prev_hist && strcmp(s, prev_hist) == 0))
128 /* Ignore this line as far as history is concerned */
130 else
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);
141 resetPQExpBuffer(history_buf);
142 #endif
147 * gets_fromFile
149 * Gets a line of noninteractive input from a file (which could be stdin).
150 * The result is a malloc'd string, or NULL on EOF or input error.
152 * Caller *must* have set up sigint_interrupt_jmp before calling.
154 * Note: we re-use a static PQExpBuffer for each call. This is to avoid
155 * leaking memory if interrupted by SIGINT.
157 char *
158 gets_fromFile(FILE *source)
160 static PQExpBuffer buffer = NULL;
162 char line[1024];
164 if (buffer == NULL) /* first time through? */
165 buffer = createPQExpBuffer();
166 else
167 resetPQExpBuffer(buffer);
169 for (;;)
171 char *result;
173 /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
174 sigint_interrupt_enabled = true;
176 /* Get some data */
177 result = fgets(line, sizeof(line), source);
179 /* Disable SIGINT again */
180 sigint_interrupt_enabled = false;
182 /* EOF or error? */
183 if (result == NULL)
185 if (ferror(source))
187 psql_error("could not read from input file: %s\n",
188 strerror(errno));
189 return NULL;
191 break;
194 appendPQExpBufferStr(buffer, line);
196 if (PQExpBufferBroken(buffer))
198 psql_error("out of memory\n");
199 return NULL;
202 /* EOL? */
203 if (buffer->data[buffer->len - 1] == '\n')
205 buffer->data[buffer->len - 1] = '\0';
206 return pg_strdup(buffer->data);
210 if (buffer->len > 0) /* EOF after reading some bufferload(s) */
211 return pg_strdup(buffer->data);
213 /* EOF, so return null */
214 return NULL;
218 #ifdef USE_READLINE
220 * Convert newlines to NL_IN_HISTORY for safe saving in readline history file
222 static void
223 encode_history(void)
225 HIST_ENTRY *cur_hist;
226 char *cur_ptr;
228 history_set_pos(0);
229 for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
231 /* some platforms declare HIST_ENTRY.line as const char * */
232 for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
233 if (*cur_ptr == '\n')
234 *cur_ptr = NL_IN_HISTORY;
239 * Reverse the above encoding
241 static void
242 decode_history(void)
244 HIST_ENTRY *cur_hist;
245 char *cur_ptr;
247 history_set_pos(0);
248 for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
250 /* some platforms declare HIST_ENTRY.line as const char * */
251 for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
252 if (*cur_ptr == NL_IN_HISTORY)
253 *cur_ptr = '\n';
256 #endif /* USE_READLINE */
260 * Put any startup stuff related to input in here. It's good to maintain
261 * abstraction this way.
263 * The only "flag" right now is 1 for use readline & history.
265 void
266 initializeInput(int flags)
268 #ifdef USE_READLINE
269 if (flags & 1)
271 const char *histfile;
272 char home[MAXPGPATH];
274 useReadline = true;
275 initialize_readline();
277 useHistory = true;
278 using_history();
280 histfile = GetVariable(pset.vars, "HISTFILE");
281 if (histfile == NULL)
283 if (get_home_path(home))
285 psql_history = pg_malloc(strlen(home) + 1 +
286 strlen(PSQLHISTORY) + 1);
287 snprintf(psql_history, MAXPGPATH, "%s/%s", home, PSQLHISTORY);
290 else
292 psql_history = pg_strdup(histfile);
293 expand_tilde(&psql_history);
296 if (psql_history)
298 read_history(psql_history);
299 decode_history();
302 #endif
304 #ifdef HAVE_ATEXIT
305 atexit(finishInput);
306 #else
307 on_exit(finishInput, NULL);
308 #endif
313 * This function is for saving the readline history when user
314 * runs \s command or when psql finishes.
316 * We have an argument named encodeFlag to handle the cases differently.
317 * In case of call via \s we don't really need to encode \n as \x01,
318 * but when we save history for Readline we must do that conversion.
320 bool
321 saveHistory(char *fname, bool encodeFlag)
323 #ifdef USE_READLINE
326 * Suppressing the write attempt when HISTFILE is set to /dev/null may
327 * look like a negligible optimization, but it's necessary on e.g. Darwin,
328 * where write_history will fail because it tries to chmod the target
329 * file.
331 if (useHistory && fname &&
332 strcmp(fname, DEVNULL) != 0)
334 if (encodeFlag)
335 encode_history();
338 * return value of write_history is not standardized across GNU
339 * readline and libedit. Therefore, check for errno becoming set to
340 * see if the write failed.
342 errno = 0;
343 (void) write_history(fname);
344 if (errno == 0)
345 return true;
347 psql_error("could not save history to file \"%s\": %s\n",
348 fname, strerror(errno));
350 #else
351 /* only get here in \s case, so complain */
352 psql_error("history is not supported by this installation\n");
353 #endif
355 return false;
359 static void
360 #ifdef HAVE_ATEXIT
361 finishInput(void)
362 #else
363 finishInput(int exitstatus, void *arg)
364 #endif
366 #ifdef USE_READLINE
367 if (useHistory && psql_history)
369 int hist_size;
371 hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
372 if (hist_size >= 0)
373 stifle_history(hist_size);
375 saveHistory(psql_history, true);
376 free(psql_history);
377 psql_history = NULL;
379 #endif