Skip to content

Commit df9f599

Browse files
committed
psql: Add quit/help behavior/hint, for other tool portability
Issuing 'quit'/'exit' in an empty psql buffer exits psql. Issuing 'quit'/'exit' in a non-empty psql buffer alone on a line with no prefix whitespace issues a hint on how to exit. Also add similar 'help' hints for 'help' in a non-empty psql buffer. Reported-by: Everaldo Canuto Discussion: https://postgr.es/m/flat/CALVFHFb-C_5_94hueWg6Dd0zu7TfbpT7hzsh9Zf0DEDOSaAnfA%40mail.gmail.com Author: original author Robert Haas, modified by me
1 parent eab30cc commit df9f599

File tree

1 file changed

+100
-13
lines changed

1 file changed

+100
-13
lines changed

src/bin/psql/mainloop.c

Lines changed: 100 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -216,21 +216,108 @@ MainLoop(FILE *source)
216216
continue;
217217
}
218218

219-
/* A request for help? Be friendly and give them some guidance */
220-
if (pset.cur_cmd_interactive && query_buf->len == 0 &&
221-
pg_strncasecmp(line, "help", 4) == 0 &&
222-
(line[4] == '\0' || line[4] == ';' || isspace((unsigned char) line[4])))
219+
/* Recognize "help", "quit", "exit" only in interactive mode */
220+
if (pset.cur_cmd_interactive)
223221
{
224-
free(line);
225-
puts(_("You are using psql, the command-line interface to PostgreSQL."));
226-
printf(_("Type: \\copyright for distribution terms\n"
227-
" \\h for help with SQL commands\n"
228-
" \\? for help with psql commands\n"
229-
" \\g or terminate with semicolon to execute query\n"
230-
" \\q to quit\n"));
222+
char *first_word = line;
223+
char *rest_of_line = NULL;
224+
bool found_help = false;
225+
bool found_exit_or_quit = false;
231226

232-
fflush(stdout);
233-
continue;
227+
/* Search for the words we recognize; must be first word */
228+
if (pg_strncasecmp(first_word, "help", 4) == 0)
229+
{
230+
rest_of_line = first_word + 4;
231+
found_help = true;
232+
}
233+
else if (pg_strncasecmp(first_word, "exit", 4) == 0 ||
234+
pg_strncasecmp(first_word, "quit", 4) == 0)
235+
{
236+
rest_of_line = first_word + 4;
237+
found_exit_or_quit = true;
238+
}
239+
240+
/*
241+
* If we found a command word, check whether the rest of the line
242+
* contains only whitespace plus maybe one semicolon. If not,
243+
* ignore the command word after all.
244+
*/
245+
if (rest_of_line != NULL)
246+
{
247+
/*
248+
* Ignore unless rest of line is whitespace, plus maybe one
249+
* semicolon
250+
*/
251+
while (isspace((unsigned char) *rest_of_line))
252+
++rest_of_line;
253+
if (*rest_of_line == ';')
254+
++rest_of_line;
255+
while (isspace((unsigned char) *rest_of_line))
256+
++rest_of_line;
257+
if (*rest_of_line != '\0')
258+
{
259+
found_help = false;
260+
found_exit_or_quit = false;
261+
}
262+
}
263+
264+
/*
265+
* "help" is only a command when the query buffer is empty, but we
266+
* emit a one-line message even when it isn't to help confused
267+
* users. The text is still added to the query buffer in that
268+
* case.
269+
*/
270+
if (found_help)
271+
{
272+
if (query_buf->len != 0)
273+
#ifndef WIN32
274+
puts(_("Use \\? for help or press control-C to clear the input buffer."));
275+
#else
276+
puts(_("Use \\? for help."));
277+
#endif
278+
else
279+
{
280+
puts(_("You are using psql, the command-line interface to PostgreSQL."));
281+
printf(_("Type: \\copyright for distribution terms\n"
282+
" \\h for help with SQL commands\n"
283+
" \\? for help with psql commands\n"
284+
" \\g or terminate with semicolon to execute query\n"
285+
" \\q to quit\n"));
286+
free(line);
287+
fflush(stdout);
288+
continue;
289+
}
290+
}
291+
/*
292+
* "quit" and "exit" are only commands when the query buffer is
293+
* empty, but we emit a one-line message even when it isn't to
294+
* help confused users. The text is still added to the query
295+
* buffer in that case.
296+
*/
297+
if (found_exit_or_quit)
298+
{
299+
if (query_buf->len != 0)
300+
{
301+
if (prompt_status == PROMPT_READY ||
302+
prompt_status == PROMPT_CONTINUE ||
303+
prompt_status == PROMPT_PAREN)
304+
puts(_("Use \\q to quit."));
305+
else
306+
#ifndef WIN32
307+
puts(_("Use control-D to quit."));
308+
#else
309+
puts(_("Use control-C to quit."));
310+
#endif
311+
}
312+
else
313+
{
314+
/* exit app */
315+
free(line);
316+
fflush(stdout);
317+
successResult = EXIT_SUCCESS;
318+
break;
319+
}
320+
}
234321
}
235322

236323
/* echo back if flag is set, unless interactive */

0 commit comments

Comments
 (0)