]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
[ Have readline save edit history.]
[postgresql] / src / bin / psql / command.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright 2000-2002 by PostgreSQL Global Development Group
5  *
6  * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.89 2003/02/13 04:08:16 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "command.h"
10
11 #include <errno.h>
12 #include <assert.h>
13 #include <ctype.h>
14 #ifdef HAVE_PWD_H
15 #include <pwd.h>
16 #endif
17 #ifndef WIN32
18 #include <sys/types.h>                  /* for umask() */
19 #include <sys/stat.h>                   /* for stat() */
20 #include <fcntl.h>                              /* open() flags */
21 #include <unistd.h>                             /* for geteuid(), getpid(), stat() */
22 #else
23 #include <win32.h>
24 #include <io.h>
25 #include <fcntl.h>
26 #include <direct.h>
27 #endif
28
29 #include "libpq-fe.h"
30 #include "pqexpbuffer.h"
31
32 #include "common.h"
33 #include "copy.h"
34 #include "describe.h"
35 #include "help.h"
36 #include "input.h"
37 #include "large_obj.h"
38 #include "mainloop.h"
39 #include "print.h"
40 #include "settings.h"
41 #include "variables.h"
42 #include "mb/pg_wchar.h"
43
44 /* functions for use in this file */
45
46 static backslashResult exec_command(const char *cmd,
47                          const char *options_string,
48                          const char **continue_parse,
49                          PQExpBuffer query_buf,
50                          volatile int *paren_level);
51
52 /* different ways for scan_option to handle parameter words */
53 enum option_type
54 {
55         OT_NORMAL,                                      /* normal case */
56         OT_SQLID,                                       /* treat as SQL identifier */
57         OT_SQLIDHACK,                           /* SQL identifier, but don't downcase */
58         OT_FILEPIPE                                     /* it's a filename or pipe */
59 };
60
61 static char *scan_option(char **string, enum option_type type,
62                         char *quote, bool semicolon);
63 static char *unescape(const unsigned char *source, size_t len);
64
65 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
66 static bool do_connect(const char *new_dbname, const char *new_user);
67 static bool do_shell(const char *command);
68
69
70
71 /*----------
72  * HandleSlashCmds:
73  *
74  * Handles all the different commands that start with '\',
75  * ordinarily called by MainLoop().
76  *
77  * 'line' is the current input line, which should not start with a '\'
78  * but with the actual command name
79  * (that is taken care of by MainLoop)
80  *
81  * 'query_buf' contains the query-so-far, which may be modified by
82  * execution of the backslash command (for example, \r clears it)
83  * query_buf can be NULL if there is no query so far.
84  *
85  * Returns a status code indicating what action is desired, see command.h.
86  *----------
87  */
88
89 backslashResult
90 HandleSlashCmds(const char *line,
91                                 PQExpBuffer query_buf,
92                                 const char **end_of_cmd,
93                                 volatile int *paren_level)
94 {
95         backslashResult status = CMD_SKIP_LINE;
96         char       *my_line;
97         char       *options_string = NULL;
98         size_t          blank_loc;
99         const char *continue_parse = NULL;      /* tell the mainloop where the
100                                                                                  * backslash command ended */
101
102 #ifdef USE_ASSERT_CHECKING
103         assert(line);
104 #endif
105
106         my_line = xstrdup(line);
107
108         /*
109          * Find the first whitespace. line[blank_loc] will now be the
110          * whitespace character or the \0 at the end
111          *
112          * Also look for a backslash, so stuff like \p\g works.
113          */
114         blank_loc = strcspn(my_line, " \t\n\r\\");
115
116         if (my_line[blank_loc] == '\\')
117         {
118                 continue_parse = &my_line[blank_loc];
119                 my_line[blank_loc] = '\0';
120                 /* If it's a double backslash, we skip it. */
121                 if (my_line[blank_loc + 1] == '\\')
122                         continue_parse += 2;
123         }
124         /* do we have an option string? */
125         else if (my_line[blank_loc] != '\0')
126         {
127                 options_string = &my_line[blank_loc + 1];
128                 my_line[blank_loc] = '\0';
129         }
130
131         status = exec_command(my_line, options_string, &continue_parse, query_buf, paren_level);
132
133         if (status == CMD_UNKNOWN)
134         {
135                 /*
136                  * If the command was not recognized, try to parse it as a
137                  * one-letter command with immediately following argument (a
138                  * still-supported, but no longer encouraged, syntax).
139                  */
140                 char            new_cmd[2];
141
142                 new_cmd[0] = my_line[0];
143                 new_cmd[1] = '\0';
144
145                 /* use line for options, because my_line was clobbered above */
146                 status = exec_command(new_cmd, line + 1, &continue_parse, query_buf, paren_level);
147
148                 /*
149                  * continue_parse must be relative to my_line for calculation
150                  * below
151                  */
152                 continue_parse += my_line - line;
153
154 #if 0                                                   /* turned out to be too annoying */
155                 if (status != CMD_UNKNOWN && isalpha((unsigned char) new_cmd[0]))
156                         psql_error("Warning: This syntax is deprecated.\n");
157 #endif
158         }
159
160         if (status == CMD_UNKNOWN)
161         {
162                 if (pset.cur_cmd_interactive)
163                         fprintf(stderr, gettext("Invalid command \\%s. Try \\? for help.\n"), my_line);
164                 else
165                         psql_error("invalid command \\%s\n", my_line);
166                 status = CMD_ERROR;
167         }
168
169         if (continue_parse && *continue_parse && *(continue_parse + 1) == '\\')
170                 continue_parse += 2;
171
172         if (end_of_cmd)
173         {
174                 if (continue_parse)
175                         *end_of_cmd = line + (continue_parse - my_line);
176                 else
177                         *end_of_cmd = line + strlen(line);
178         }
179
180         free(my_line);
181
182         return status;
183 }
184
185
186
187 static backslashResult
188 exec_command(const char *cmd,
189                          const char *options_string,
190                          const char **continue_parse,
191                          PQExpBuffer query_buf,
192                          volatile int *paren_level)
193 {
194         bool            success = true; /* indicate here if the command ran ok or
195                                                                  * failed */
196         bool            quiet = QUIET();
197         backslashResult status = CMD_SKIP_LINE;
198         char       *string,
199                            *string_cpy,
200                            *val;
201
202         /*
203          * The 'string' variable will be overwritten to point to the next
204          * token, hence we need an extra pointer so we can free this at the
205          * end.
206          */
207         if (options_string)
208                 string = string_cpy = xstrdup(options_string);
209         else
210                 string = string_cpy = NULL;
211
212         /*
213          * \a -- toggle field alignment This makes little sense but we keep it
214          * around.
215          */
216         if (strcmp(cmd, "a") == 0)
217         {
218                 if (pset.popt.topt.format != PRINT_ALIGNED)
219                         success = do_pset("format", "aligned", &pset.popt, quiet);
220                 else
221                         success = do_pset("format", "unaligned", &pset.popt, quiet);
222         }
223
224         /* \C -- override table title (formerly change HTML caption) */
225         else if (strcmp(cmd, "C") == 0)
226         {
227                 char       *opt = scan_option(&string, OT_NORMAL, NULL, true);
228
229                 success = do_pset("title", opt, &pset.popt, quiet);
230                 free(opt);
231         }
232
233         /*----------
234          * \c or \connect -- connect to new database or as different user
235          *
236          * \c foo bar  connect to db "foo" as user "bar"
237          * \c foo [-]  connect to db "foo" as current user
238          * \c - bar    connect to current db as user "bar"
239          * \c              connect to default db as default user
240          *----------
241          */
242         else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
243         {
244                 char       *opt1,
245                                    *opt2;
246                 char            opt1q,
247                                         opt2q;
248
249                 /*
250                  * Ideally we should treat the arguments as SQL identifiers.  But
251                  * for backwards compatibility with 7.2 and older pg_dump files,
252                  * we have to take unquoted arguments verbatim (don't downcase
253                  * them). For now, double-quoted arguments may be stripped of
254                  * double quotes (as if SQL identifiers).  By 7.4 or so, pg_dump
255                  * files can be expected to double-quote all mixed-case \connect
256                  * arguments, and then we can get rid of OT_SQLIDHACK.
257                  */
258                 opt1 = scan_option(&string, OT_SQLIDHACK, &opt1q, true);
259                 opt2 = scan_option(&string, OT_SQLIDHACK, &opt2q, true);
260
261                 if (opt2)
262                         /* gave username */
263                         success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1,
264                                                                  !opt2q && (strcmp(opt2, "-") == 0 || strcmp(opt2, "") == 0) ? "" : opt2);
265                 else if (opt1)
266                         /* gave database name */
267                         success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1, "");
268                 else
269                         /* connect to default db as default user */
270                         success = do_connect(NULL, NULL);
271
272                 free(opt1);
273                 free(opt2);
274         }
275
276         /* \cd */
277         else if (strcmp(cmd, "cd") == 0)
278         {
279                 char       *opt = scan_option(&string, OT_NORMAL, NULL, true);
280                 char       *dir;
281
282                 if (opt)
283                         dir = opt;
284                 else
285                 {
286 #ifndef WIN32
287                         struct passwd *pw;
288
289                         pw = getpwuid(geteuid());
290                         if (!pw)
291                         {
292                                 psql_error("could not get home directory: %s\n", strerror(errno));
293                                 exit(EXIT_FAILURE);
294                         }
295                         dir = pw->pw_dir;
296 #else                                                   /* WIN32 */
297
298                         /*
299                          * On Windows, 'cd' without arguments prints the current
300                          * directory, so if someone wants to code this here instead...
301                          */
302                         dir = "/";
303 #endif   /* WIN32 */
304                 }
305
306                 if (chdir(dir) == -1)
307                 {
308                         psql_error("\\%s: could not change directory to '%s': %s\n",
309                                            cmd, dir, strerror(errno));
310                         success = false;
311                 }
312
313                 if (opt)
314                         free(opt);
315         }
316
317         /* \copy */
318         else if (strcasecmp(cmd, "copy") == 0)
319         {
320                 success = do_copy(options_string);
321                 if (options_string)
322                         string += strlen(string);
323         }
324
325         /* \copyright */
326         else if (strcmp(cmd, "copyright") == 0)
327                 print_copyright();
328
329         /* \d* commands */
330         else if (cmd[0] == 'd')
331         {
332                 char       *pattern;
333                 bool            show_verbose;
334
335                 /* We don't do SQLID reduction on the pattern yet */
336                 pattern = scan_option(&string, OT_NORMAL, NULL, true);
337
338                 show_verbose = strchr(cmd, '+') ? true : false;
339
340                 switch (cmd[1])
341                 {
342                         case '\0':
343                         case '+':
344                                 if (pattern)
345                                         success = describeTableDetails(pattern, show_verbose);
346                                 else
347                                         /* standard listing of interesting things */
348                                         success = listTables("tvs", NULL, show_verbose);
349                                 break;
350                         case 'a':
351                                 success = describeAggregates(pattern, show_verbose);
352                                 break;
353                         case 'c':
354                                 success = listConversions(pattern);
355                                 break;
356                         case 'C':
357                                 success = listCasts(pattern);
358                                 break;
359                         case 'd':
360                                 success = objectDescription(pattern);
361                                 break;
362                         case 'D':
363                                 success = listDomains(pattern);
364                                 break;
365                         case 'f':
366                                 success = describeFunctions(pattern, show_verbose);
367                                 break;
368                         case 'l':
369                                 success = do_lo_list();
370                                 break;
371                         case 'n':
372                                 success = listSchemas(pattern);
373                                 break;
374                         case 'o':
375                                 success = describeOperators(pattern);
376                                 break;
377                         case 'p':
378                                 success = permissionsList(pattern);
379                                 break;
380                         case 'T':
381                                 success = describeTypes(pattern, show_verbose);
382                                 break;
383                         case 't':
384                         case 'v':
385                         case 'i':
386                         case 's':
387                         case 'S':
388                                 success = listTables(&cmd[1], pattern, show_verbose);
389                                 break;
390                         case 'u':
391                                 success = describeUsers(pattern);
392                                 break;
393
394                         default:
395                                 status = CMD_UNKNOWN;
396                 }
397
398                 if (pattern)
399                         free(pattern);
400         }
401
402
403         /*
404          * \e or \edit -- edit the current query buffer (or a file and make it
405          * the query buffer
406          */
407         else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
408         {
409                 char       *fname;
410
411                 if (!query_buf)
412                 {
413                         psql_error("no query buffer\n");
414                         status = CMD_ERROR;
415                 }
416                 else
417                 {
418                         fname = scan_option(&string, OT_NORMAL, NULL, true);
419                         status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
420                         free(fname);
421                 }
422         }
423
424         /* \echo and \qecho */
425         else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
426         {
427                 char       *value;
428                 char            quoted;
429                 bool            no_newline = false;
430                 bool            first = true;
431                 FILE       *fout;
432
433                 if (strcmp(cmd, "qecho") == 0)
434                         fout = pset.queryFout;
435                 else
436                         fout = stdout;
437
438                 while ((value = scan_option(&string, OT_NORMAL, &quoted, false)))
439                 {
440                         if (!quoted && strcmp(value, "-n") == 0)
441                                 no_newline = true;
442                         else
443                         {
444                                 if (first)
445                                         first = false;
446                                 else
447                                         fputc(' ', fout);
448                                 fputs(value, fout);
449                         }
450                         free(value);
451                 }
452                 if (!no_newline)
453                         fputs("\n", fout);
454         }
455
456         /* \encoding -- set/show client side encoding */
457         else if (strcmp(cmd, "encoding") == 0)
458         {
459                 char       *encoding = scan_option(&string, OT_NORMAL, NULL, false);
460
461                 if (!encoding)
462                         /* show encoding */
463                         puts(pg_encoding_to_char(pset.encoding));
464                 else
465                 {
466                         /* set encoding */
467                         if (PQsetClientEncoding(pset.db, encoding) == -1)
468                                 psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
469
470                         else
471                         {
472                                 /* save encoding info into psql internal data */
473                                 pset.encoding = PQclientEncoding(pset.db);
474                                 SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
475                         }
476                         free(encoding);
477                 }
478         }
479
480         /* \f -- change field separator */
481         else if (strcmp(cmd, "f") == 0)
482         {
483                 char       *fname = scan_option(&string, OT_NORMAL, NULL, false);
484
485                 success = do_pset("fieldsep", fname, &pset.popt, quiet);
486                 free(fname);
487         }
488
489         /* \g means send query */
490         else if (strcmp(cmd, "g") == 0)
491         {
492                 char       *fname = scan_option(&string, OT_FILEPIPE, NULL, false);
493
494                 if (!fname)
495                         pset.gfname = NULL;
496                 else
497                         pset.gfname = xstrdup(fname);
498                 free(fname);
499                 status = CMD_SEND;
500         }
501
502         /* help */
503         else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
504         {
505                 helpSQL(options_string ? &options_string[strspn(options_string, " \t\n\r")] : NULL,
506                                 pset.popt.topt.pager);
507                 /* set pointer to end of line */
508                 if (string)
509                         string += strlen(string);
510         }
511
512         /* HTML mode */
513         else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
514         {
515                 if (pset.popt.topt.format != PRINT_HTML)
516                         success = do_pset("format", "html", &pset.popt, quiet);
517                 else
518                         success = do_pset("format", "aligned", &pset.popt, quiet);
519         }
520
521
522         /* \i is include file */
523         else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
524         {
525                 char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
526
527                 if (!fname)
528                 {
529                         psql_error("\\%s: missing required argument\n", cmd);
530                         success = false;
531                 }
532                 else
533                 {
534                         success = (process_file(fname) == EXIT_SUCCESS);
535                         free(fname);
536                 }
537         }
538
539         /* \l is list databases */
540         else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
541                 success = listAllDbs(false);
542         else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
543                 success = listAllDbs(true);
544
545         /*
546          * large object things
547          */
548         else if (strncmp(cmd, "lo_", 3) == 0)
549         {
550                 char       *opt1,
551                                    *opt2;
552
553                 opt1 = scan_option(&string, OT_NORMAL, NULL, true);
554                 opt2 = scan_option(&string, OT_NORMAL, NULL, true);
555
556                 if (strcmp(cmd + 3, "export") == 0)
557                 {
558                         if (!opt2)
559                         {
560                                 psql_error("\\%s: missing required argument\n", cmd);
561                                 success = false;
562                         }
563                         else
564                                 success = do_lo_export(opt1, opt2);
565                 }
566
567                 else if (strcmp(cmd + 3, "import") == 0)
568                 {
569                         if (!opt1)
570                         {
571                                 psql_error("\\%s: missing required argument\n", cmd);
572                                 success = false;
573                         }
574                         else
575                                 success = do_lo_import(opt1, opt2);
576                 }
577
578                 else if (strcmp(cmd + 3, "list") == 0)
579                         success = do_lo_list();
580
581                 else if (strcmp(cmd + 3, "unlink") == 0)
582                 {
583                         if (!opt1)
584                         {
585                                 psql_error("\\%s: missing required argument\n", cmd);
586                                 success = false;
587                         }
588                         else
589                                 success = do_lo_unlink(opt1);
590                 }
591
592                 else
593                         status = CMD_UNKNOWN;
594
595                 free(opt1);
596                 free(opt2);
597         }
598
599
600         /* \o -- set query output */
601         else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
602         {
603                 char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);
604
605                 success = setQFout(fname);
606                 free(fname);
607         }
608
609         /* \p prints the current query buffer */
610         else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
611         {
612                 if (query_buf && query_buf->len > 0)
613                         puts(query_buf->data);
614                 else if (!quiet)
615                         puts(gettext("Query buffer is empty."));
616                 fflush(stdout);
617         }
618
619         /* \pset -- set printing parameters */
620         else if (strcmp(cmd, "pset") == 0)
621         {
622                 char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
623                 char       *opt1 = scan_option(&string, OT_NORMAL, NULL, false);
624
625                 if (!opt0)
626                 {
627                         psql_error("\\%s: missing required argument\n", cmd);
628                         success = false;
629                 }
630                 else
631                         success = do_pset(opt0, opt1, &pset.popt, quiet);
632
633                 free(opt0);
634                 free(opt1);
635         }
636
637         /* \q or \quit */
638         else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
639                 status = CMD_TERMINATE;
640
641         /* reset(clear) the buffer */
642         else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
643         {
644                 resetPQExpBuffer(query_buf);
645                 if (paren_level)
646                         *paren_level = 0;
647                 if (!quiet)
648                         puts(gettext("Query buffer reset (cleared)."));
649         }
650
651         /* \s save history in a file or show it on the screen */
652         else if (strcmp(cmd, "s") == 0)
653         {
654                 char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
655
656                 success = saveHistory(fname ? fname : "/dev/tty");
657
658                 if (success && !quiet && fname)
659                         printf(gettext("Wrote history to %s.\n"), fname);
660                 free(fname);
661         }
662
663         /* \set -- generalized set variable/option command */
664         else if (strcmp(cmd, "set") == 0)
665         {
666                 char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
667
668                 if (!opt0)
669                 {
670                         /* list all variables */
671
672                         /*
673                          * XXX This is in utter violation of the GetVariable
674                          * abstraction, but I have not bothered to do it better.
675                          */
676                         struct _variable *ptr;
677
678                         for (ptr = pset.vars; ptr->next; ptr = ptr->next)
679                                 fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value);
680                         success = true;
681                 }
682                 else
683                 {
684                         /*
685                          * Set variable to the concatenation of the arguments.
686                          */
687                         char       *newval = NULL;
688                         char       *opt;
689
690                         opt = scan_option(&string, OT_NORMAL, NULL, false);
691                         newval = xstrdup(opt ? opt : "");
692                         free(opt);
693
694                         while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
695                         {
696                                 newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
697                                 if (!newval)
698                                 {
699                                         psql_error("out of memory\n");
700                                         exit(EXIT_FAILURE);
701                                 }
702                                 strcat(newval, opt);
703                                 free(opt);
704                         }
705
706                         if (!SetVariable(pset.vars, opt0, newval))
707                         {
708                                 psql_error("\\%s: error\n", cmd);
709                                 success = false;
710                         }
711                         free(newval);
712                 }
713                 free(opt0);
714         }
715
716         /* \t -- turn off headers and row count */
717         else if (strcmp(cmd, "t") == 0)
718                 success = do_pset("tuples_only", NULL, &pset.popt, quiet);
719
720
721         /* \T -- define html <table ...> attributes */
722         else if (strcmp(cmd, "T") == 0)
723         {
724                 char       *value = scan_option(&string, OT_NORMAL, NULL, false);
725
726                 success = do_pset("tableattr", value, &pset.popt, quiet);
727                 free(value);
728         }
729
730         /* \timing -- toggle timing of queries */
731         else if (strcmp(cmd, "timing") == 0)
732         {
733                 pset.timing = !pset.timing;
734                 if (!quiet)
735                 {
736                         if (pset.timing)
737                                 puts(gettext(("Timing is on.")));
738                         else
739                         {
740                                 puts(gettext(("Timing is off.")));
741
742                         }
743                 }
744         }
745
746         /* \unset */
747         else if (strcmp(cmd, "unset") == 0)
748         {
749                 char       *opt = scan_option(&string, OT_NORMAL, NULL, false);
750
751                 if (!opt)
752                 {
753                         psql_error("\\%s: missing required argument\n", cmd);
754                         success = false;
755                 }
756                 else if (!SetVariable(pset.vars, opt, NULL))
757                 {
758                         psql_error("\\%s: error\n", cmd);
759                         success = false;
760                 }
761                 free(opt);
762         }
763
764         /* \w -- write query buffer to file */
765         else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
766         {
767                 FILE       *fd = NULL;
768                 bool            is_pipe = false;
769                 char       *fname = NULL;
770
771                 if (!query_buf)
772                 {
773                         psql_error("no query buffer\n");
774                         status = CMD_ERROR;
775                 }
776                 else
777                 {
778                         fname = scan_option(&string, OT_FILEPIPE, NULL, true);
779
780                         if (!fname)
781                         {
782                                 psql_error("\\%s: missing required argument\n", cmd);
783                                 success = false;
784                         }
785                         else
786                         {
787                                 if (fname[0] == '|')
788                                 {
789                                         is_pipe = true;
790                                         fd = popen(&fname[1], "w");
791                                 }
792                                 else
793                                         fd = fopen(fname, "w");
794
795                                 if (!fd)
796                                 {
797                                         psql_error("%s: %s\n", fname, strerror(errno));
798                                         success = false;
799                                 }
800                         }
801                 }
802
803                 if (fd)
804                 {
805                         int                     result;
806
807                         if (query_buf && query_buf->len > 0)
808                                 fprintf(fd, "%s\n", query_buf->data);
809
810                         if (is_pipe)
811                                 result = pclose(fd);
812                         else
813                                 result = fclose(fd);
814
815                         if (result == EOF)
816                         {
817                                 psql_error("%s: %s\n", fname, strerror(errno));
818                                 success = false;
819                         }
820                 }
821
822                 free(fname);
823         }
824
825         /* \x -- toggle expanded table representation */
826         else if (strcmp(cmd, "x") == 0)
827                 success = do_pset("expanded", NULL, &pset.popt, quiet);
828
829
830         /* \z -- list table rights (equivalent to \dp) */
831         else if (strcmp(cmd, "z") == 0)
832         {
833                 char       *pattern = scan_option(&string, OT_NORMAL, NULL, true);
834
835                 success = permissionsList(pattern);
836                 if (pattern)
837                         free(pattern);
838         }
839
840         /* \! -- shell escape */
841         else if (strcmp(cmd, "!") == 0)
842         {
843                 success = do_shell(options_string);
844                 /* wind pointer to end of line */
845                 if (string)
846                         string += strlen(string);
847         }
848
849         /* \? -- slash command help */
850         else if (strcmp(cmd, "?") == 0)
851                 slashUsage(pset.popt.topt.pager);
852
853 #if 0
854
855         /*
856          * These commands don't do anything. I just use them to test the
857          * parser.
858          */
859         else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
860         {
861                 int                     i = 0;
862                 char       *value;
863
864                 fprintf(stderr, "+ optstr = |%s|\n", options_string);
865                 while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
866                 {
867                         fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
868                         free(value);
869                 }
870         }
871 #endif
872
873         else
874                 status = CMD_UNKNOWN;
875
876         if (!success)
877                 status = CMD_ERROR;
878
879         /* eat the rest of the options string */
880         while ((val = scan_option(&string, OT_NORMAL, NULL, false)))
881         {
882                 if (status != CMD_UNKNOWN)
883                         psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
884         }
885
886         if (options_string && continue_parse)
887                 *continue_parse = options_string + (string - string_cpy);
888         free(string_cpy);
889
890         return status;
891 }
892
893
894
895 /*
896  * scan_option()
897  *
898  * *string points to possible option string on entry; on exit, it's updated
899  * to point past the option string (if any).
900  *
901  * type tells what processing, if any, to perform on the option string;
902  * for example, if it's a SQL identifier, we want to downcase any unquoted
903  * letters.
904  *
905  * if quote is not NULL, *quote is set to 0 if no quoting was found, else
906  * the quote symbol.
907  *
908  * if semicolon is true, trailing semicolon(s) that would otherwise be taken
909  * as part of the option string will be stripped.
910  *
911  * Return value is NULL if no option found, else a malloc'd copy of the
912  * processed option value.
913  */
914 static char *
915 scan_option(char **string, enum option_type type, char *quote, bool semicolon)
916 {
917         unsigned int pos;
918         char       *options_string;
919         char       *return_val;
920
921         if (quote)
922                 *quote = 0;
923
924         if (!string || !(*string))
925                 return NULL;
926
927         options_string = *string;
928         /* skip leading whitespace */
929         pos = strspn(options_string, " \t\n\r");
930
931         switch (options_string[pos])
932         {
933                         /*
934                          * End of line: no option present
935                          */
936                 case '\0':
937                         *string = &options_string[pos];
938                         return NULL;
939
940                         /*
941                          * Next command: treat like end of line
942                          *
943                          * XXX this means we can't conveniently accept options that start
944                          * with a backslash; therefore, option processing that
945                          * encourages use of backslashes is rather broken.
946                          */
947                 case '\\':
948                         *string = &options_string[pos];
949                         return NULL;
950
951                         /*
952                          * A single quote has a psql internal meaning, such as for
953                          * delimiting file names, and it also allows for such escape
954                          * sequences as \t.
955                          */
956                 case '\'':
957                         {
958                                 unsigned int jj;
959                                 unsigned short int bslash_count = 0;
960
961                                 for (jj = pos + 1; options_string[jj]; jj += PQmblen(&options_string[jj], pset.encoding))
962                                 {
963                                         if (options_string[jj] == '\'' && bslash_count % 2 == 0)
964                                                 break;
965
966                                         if (options_string[jj] == '\\')
967                                                 bslash_count++;
968                                         else
969                                                 bslash_count = 0;
970                                 }
971
972                                 if (options_string[jj] == 0)
973                                 {
974                                         psql_error("parse error at the end of line\n");
975                                         *string = &options_string[jj];
976                                         return NULL;
977                                 }
978
979                                 return_val = unescape(&options_string[pos + 1], jj - pos - 1);
980                                 *string = &options_string[jj + 1];
981                                 if (quote)
982                                         *quote = '\'';
983                                 return return_val;
984                         }
985
986                         /*
987                          * Backticks are for command substitution, like in shells
988                          */
989                 case '`':
990                         {
991                                 bool            error = false;
992                                 FILE       *fd;
993                                 char       *file;
994                                 PQExpBufferData output;
995                                 char            buf[512];
996                                 size_t          result,
997                                                         len;
998
999                                 len = strcspn(options_string + pos + 1, "`");
1000                                 if (options_string[pos + 1 + len] == 0)
1001                                 {
1002                                         psql_error("parse error at the end of line\n");
1003                                         *string = &options_string[pos + 1 + len];
1004                                         return NULL;
1005                                 }
1006
1007                                 options_string[pos + 1 + len] = '\0';
1008                                 file = options_string + pos + 1;
1009
1010                                 fd = popen(file, "r");
1011                                 if (!fd)
1012                                 {
1013                                         psql_error("%s: %s\n", file, strerror(errno));
1014                                         error = true;
1015                                 }
1016
1017                                 initPQExpBuffer(&output);
1018
1019                                 if (!error)
1020                                 {
1021                                         do
1022                                         {
1023                                                 result = fread(buf, 1, 512, fd);
1024                                                 if (ferror(fd))
1025                                                 {
1026                                                         psql_error("%s: %s\n", file, strerror(errno));
1027                                                         error = true;
1028                                                         break;
1029                                                 }
1030                                                 appendBinaryPQExpBuffer(&output, buf, result);
1031                                         } while (!feof(fd));
1032                                         appendPQExpBufferChar(&output, '\0');
1033                                 }
1034
1035                                 if (fd && pclose(fd) == -1)
1036                                 {
1037                                         psql_error("%s: %s\n", file, strerror(errno));
1038                                         error = true;
1039                                 }
1040
1041                                 if (!error)
1042                                 {
1043                                         if (output.data[strlen(output.data) - 1] == '\n')
1044                                                 output.data[strlen(output.data) - 1] = '\0';
1045                                         return_val = output.data;
1046                                 }
1047                                 else
1048                                 {
1049                                         return_val = xstrdup("");
1050                                         termPQExpBuffer(&output);
1051                                 }
1052
1053                                 options_string[pos + 1 + len] = '`';
1054                                 *string = options_string + pos + len + 2;
1055                                 if (quote)
1056                                         *quote = '`';
1057                                 return return_val;
1058                         }
1059
1060                         /*
1061                          * Variable substitution
1062                          */
1063                 case ':':
1064                         {
1065                                 size_t          token_end;
1066                                 const char *value;
1067                                 char            save_char;
1068
1069                                 token_end = strcspn(&options_string[pos + 1], " \t\n\r");
1070                                 save_char = options_string[pos + token_end + 1];
1071                                 options_string[pos + token_end + 1] = '\0';
1072                                 value = GetVariable(pset.vars, options_string + pos + 1);
1073                                 if (!value)
1074                                         value = "";
1075                                 return_val = xstrdup(value);
1076                                 options_string[pos + token_end + 1] = save_char;
1077                                 *string = &options_string[pos + token_end + 1];
1078                                 /* XXX should we set *quote to ':' here? */
1079                                 return return_val;
1080                         }
1081
1082                         /*
1083                          * | could be the beginning of a pipe if so, take rest of line
1084                          * as command
1085                          */
1086                 case '|':
1087                         if (type == OT_FILEPIPE)
1088                         {
1089                                 *string += strlen(*string);
1090                                 return xstrdup(options_string + pos);
1091                         }
1092                         /* fallthrough for other option types */
1093
1094                         /*
1095                          * Default case: token extends to next whitespace, except that
1096                          * whitespace within double quotes doesn't end the token.
1097                          *
1098                          * If we are processing the option as a SQL identifier, then
1099                          * downcase unquoted letters and remove double-quotes --- but
1100                          * doubled double-quotes become output double-quotes, per
1101                          * spec.
1102                          *
1103                          * Note that a string like FOO"BAR"BAZ will be converted to
1104                          * fooBARbaz; this is somewhat inconsistent with the SQL spec,
1105                          * which would have us parse it as several identifiers.  But
1106                          * for psql's purposes, we want a string like "foo"."bar" to
1107                          * be treated as one option, so there's little choice.
1108                          */
1109                 default:
1110                         {
1111                                 bool            inquotes = false;
1112                                 size_t          token_len;
1113                                 char       *cp;
1114
1115                                 /* Find end of option */
1116
1117                                 cp = &options_string[pos];
1118                                 for (;;)
1119                                 {
1120                                         /* Find next quote, whitespace, or end of string */
1121                                         cp += strcspn(cp, "\" \t\n\r");
1122                                         if (inquotes)
1123                                         {
1124                                                 if (*cp == '\0')
1125                                                 {
1126                                                         psql_error("parse error at the end of line\n");
1127                                                         *string = cp;
1128                                                         return NULL;
1129                                                 }
1130                                                 if (*cp == '"')
1131                                                         inquotes = false;
1132                                                 cp++;
1133                                         }
1134                                         else
1135                                         {
1136                                                 if (*cp != '"')
1137                                                         break;          /* whitespace or end of string */
1138                                                 if (quote)
1139                                                         *quote = '"';
1140                                                 inquotes = true;
1141                                                 cp++;
1142                                         }
1143                                 }
1144
1145                                 *string = cp;
1146
1147                                 /* Copy the option */
1148                                 token_len = cp - &options_string[pos];
1149
1150                                 return_val = malloc(token_len + 1);
1151                                 if (!return_val)
1152                                 {
1153                                         psql_error("out of memory\n");
1154                                         exit(EXIT_FAILURE);
1155                                 }
1156
1157                                 memcpy(return_val, &options_string[pos], token_len);
1158                                 return_val[token_len] = '\0';
1159
1160                                 /* Strip any trailing semi-colons if requested */
1161                                 if (semicolon)
1162                                 {
1163                                         int                     i;
1164
1165                                         for (i = token_len - 1;
1166                                                  i >= 0 && return_val[i] == ';';
1167                                                  i--)
1168                                                  /* skip */ ;
1169
1170                                         if (i < 0)
1171                                         {
1172                                                 /* nothing left after stripping the semicolon... */
1173                                                 free(return_val);
1174                                                 return NULL;
1175                                         }
1176
1177                                         if (i < (int) token_len - 1)
1178                                                 return_val[i + 1] = '\0';
1179                                 }
1180
1181                                 /*
1182                                  * If SQL identifier processing was requested, then we
1183                                  * strip out excess double quotes and downcase unquoted
1184                                  * letters.
1185                                  */
1186                                 if (type == OT_SQLID || type == OT_SQLIDHACK)
1187                                 {
1188                                         inquotes = false;
1189                                         cp = return_val;
1190
1191                                         while (*cp)
1192                                         {
1193                                                 if (*cp == '"')
1194                                                 {
1195                                                         if (inquotes && cp[1] == '"')
1196                                                         {
1197                                                                 /* Keep the first quote, remove the second */
1198                                                                 cp++;
1199                                                         }
1200                                                         inquotes = !inquotes;
1201                                                         /* Collapse out quote at *cp */
1202                                                         memmove(cp, cp + 1, strlen(cp));
1203                                                         /* do not advance cp */
1204                                                 }
1205                                                 else
1206                                                 {
1207                                                         if (!inquotes && type == OT_SQLID)
1208                                                         {
1209                                                                 if (isupper((unsigned char) *cp))
1210                                                                         *cp = tolower((unsigned char) *cp);
1211                                                         }
1212                                                         cp += PQmblen(cp, pset.encoding);
1213                                                 }
1214                                         }
1215                                 }
1216
1217                                 return return_val;
1218                         }
1219         }
1220 }
1221
1222
1223
1224 /*
1225  * unescape
1226  *
1227  * Replaces \n, \t, and the like.
1228  *
1229  * The return value is malloc()'ed.
1230  */
1231 static char *
1232 unescape(const unsigned char *source, size_t len)
1233 {
1234         const unsigned char *p;
1235         bool            esc = false;    /* Last character we saw was the escape
1236                                                                  * character */
1237         char       *destination,
1238                            *tmp;
1239         size_t          length;
1240
1241 #ifdef USE_ASSERT_CHECKING
1242         assert(source);
1243 #endif
1244
1245         length = Min(len, strlen(source)) + 1;
1246
1247         tmp = destination = malloc(length);
1248         if (!tmp)
1249         {
1250                 psql_error("out of memory\n");
1251                 exit(EXIT_FAILURE);
1252         }
1253
1254         for (p = source; p - source < (int) len && *p; p += PQmblen(p, pset.encoding))
1255         {
1256                 if (esc)
1257                 {
1258                         char            c;
1259
1260                         switch (*p)
1261                         {
1262                                 case 'n':
1263                                         c = '\n';
1264                                         break;
1265                                 case 't':
1266                                         c = '\t';
1267                                         break;
1268                                 case 'b':
1269                                         c = '\b';
1270                                         break;
1271                                 case 'r':
1272                                         c = '\r';
1273                                         break;
1274                                 case 'f':
1275                                         c = '\f';
1276                                         break;
1277                                 case '0':
1278                                 case '1':
1279                                 case '2':
1280                                 case '3':
1281                                 case '4':
1282                                 case '5':
1283                                 case '6':
1284                                 case '7':
1285                                 case '8':
1286                                 case '9':
1287                                         {
1288                                                 long int        l;
1289                                                 char       *end;
1290
1291                                                 l = strtol(p, &end, 0);
1292                                                 c = (char) l;
1293                                                 p = end - 1;
1294                                                 break;
1295                                         }
1296                                 default:
1297                                         c = *p;
1298                         }
1299                         *tmp++ = c;
1300                         esc = false;
1301                 }
1302
1303                 else if (*p == '\\')
1304                         esc = true;
1305
1306                 else
1307                 {
1308                         int                     i;
1309                         const unsigned char *mp = p;
1310
1311                         for (i = 0; i < PQmblen(p, pset.encoding); i++)
1312                                 *tmp++ = *mp++;
1313                         esc = false;
1314                 }
1315         }
1316
1317         *tmp = '\0';
1318         return destination;
1319 }
1320
1321
1322
1323 /* do_connect
1324  * -- handler for \connect
1325  *
1326  * Connects to a database (new_dbname) as a certain user (new_user).
1327  * The new user can be NULL. A db name of "-" is the same as the old one.
1328  * (That is, the one currently in pset. But pset.db can also be NULL. A NULL
1329  * dbname is handled by libpq.)
1330  * Returns true if all ok, false if the new connection couldn't be established.
1331  * The old connection will be kept if the session is interactive.
1332  */
1333 static bool
1334 do_connect(const char *new_dbname, const char *new_user)
1335 {
1336         PGconn     *oldconn = pset.db;
1337         const char *dbparam = NULL;
1338         const char *userparam = NULL;
1339         const char *pwparam = NULL;
1340         char       *prompted_password = NULL;
1341         bool            need_pass;
1342         bool            success = false;
1343
1344         /* Delete variables (in case we fail before setting them anew) */
1345         SetVariable(pset.vars, "DBNAME", NULL);
1346         SetVariable(pset.vars, "USER", NULL);
1347         SetVariable(pset.vars, "HOST", NULL);
1348         SetVariable(pset.vars, "PORT", NULL);
1349         SetVariable(pset.vars, "ENCODING", NULL);
1350
1351         /* If dbname is "" then use old name, else new one (even if NULL) */
1352         if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0)
1353                 dbparam = PQdb(oldconn);
1354         else
1355                 dbparam = new_dbname;
1356
1357         /* If user is "" then use the old one */
1358         if (new_user && PQuser(oldconn) && strcmp(new_user, "") == 0)
1359                 userparam = PQuser(oldconn);
1360         else
1361                 userparam = new_user;
1362
1363         /* need to prompt for password? */
1364         if (pset.getPassword)
1365                 pwparam = prompted_password = simple_prompt("Password: ", 100, false);
1366
1367         /*
1368          * Use old password (if any) if no new one given and we are
1369          * reconnecting as same user
1370          */
1371         if (!pwparam && oldconn && PQuser(oldconn) && userparam &&
1372                 strcmp(PQuser(oldconn), userparam) == 0)
1373                 pwparam = PQpass(oldconn);
1374
1375         do
1376         {
1377                 need_pass = false;
1378                 pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
1379                                                            NULL, NULL, dbparam, userparam, pwparam);
1380
1381                 if (PQstatus(pset.db) == CONNECTION_BAD &&
1382                         strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0 &&
1383                         !feof(stdin))
1384                 {
1385                         PQfinish(pset.db);
1386                         need_pass = true;
1387                         free(prompted_password);
1388                         prompted_password = NULL;
1389                         pwparam = prompted_password = simple_prompt("Password: ", 100, false);
1390                 }
1391         } while (need_pass);
1392
1393         free(prompted_password);
1394
1395         /*
1396          * If connection failed, try at least keep the old one. That's
1397          * probably more convenient than just kicking you out of the program.
1398          */
1399         if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD)
1400         {
1401                 if (pset.cur_cmd_interactive)
1402                 {
1403                         psql_error("%s", PQerrorMessage(pset.db));
1404                         PQfinish(pset.db);
1405                         if (oldconn)
1406                         {
1407                                 fputs(gettext("Previous connection kept\n"), stderr);
1408                                 pset.db = oldconn;
1409                         }
1410                         else
1411                                 pset.db = NULL;
1412                 }
1413                 else
1414                 {
1415                         /*
1416                          * we don't want unpredictable things to happen in scripting
1417                          * mode
1418                          */
1419                         psql_error("\\connect: %s", PQerrorMessage(pset.db));
1420                         PQfinish(pset.db);
1421                         if (oldconn)
1422                                 PQfinish(oldconn);
1423                         pset.db = NULL;
1424                 }
1425         }
1426         else
1427         {
1428                 if (!QUIET())
1429                 {
1430                         if (userparam != new_user)      /* no new user */
1431                                 printf(gettext("You are now connected to database %s.\n"), dbparam);
1432                         else if (dbparam != new_dbname)         /* no new db */
1433                                 printf(gettext("You are now connected as new user %s.\n"), new_user);
1434                         else
1435 /* both new */
1436                                 printf(gettext("You are now connected to database %s as user %s.\n"),
1437                                            PQdb(pset.db), PQuser(pset.db));
1438                 }
1439
1440                 if (oldconn)
1441                         PQfinish(oldconn);
1442
1443                 success = true;
1444         }
1445
1446         PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
1447         pset.encoding = PQclientEncoding(pset.db);
1448
1449         /* Update variables */
1450         SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
1451         SetVariable(pset.vars, "USER", PQuser(pset.db));
1452         SetVariable(pset.vars, "HOST", PQhost(pset.db));
1453         SetVariable(pset.vars, "PORT", PQport(pset.db));
1454         SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
1455
1456         pset.issuper = test_superuser(PQuser(pset.db));
1457
1458         return success;
1459 }
1460
1461
1462
1463 /*
1464  * Test if the given user is a database superuser.
1465  * (Is used to set up the prompt right.)
1466  */
1467 bool
1468 test_superuser(const char *username)
1469 {
1470         PGresult   *res;
1471         PQExpBufferData buf;
1472         bool            answer;
1473
1474         if (!username)
1475                 return false;
1476
1477         /*
1478          * Use begin/commit to avoid starting a transaction block if server
1479          * has autocommit off by default.
1480          */
1481         initPQExpBuffer(&buf);
1482         printfPQExpBuffer(&buf, "BEGIN; SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'; COMMIT", username);
1483         res = PSQLexec(buf.data, true);
1484         termPQExpBuffer(&buf);
1485
1486         answer =
1487                 (res && PQntuples(res) > 0 && PQnfields(res) > 0
1488                  && !PQgetisnull(res, 0, 0)
1489                  && PQgetvalue(res, 0, 0)
1490                  && strcmp(PQgetvalue(res, 0, 0), "t") == 0);
1491         PQclear(res);
1492         return answer;
1493 }
1494
1495
1496
1497 /*
1498  * do_edit -- handler for \e
1499  *
1500  * If you do not specify a filename, the current query buffer will be copied
1501  * into a temporary one.
1502  */
1503
1504 static bool
1505 editFile(const char *fname)
1506 {
1507         const char *editorName;
1508         char       *sys;
1509         int                     result;
1510
1511 #ifdef USE_ASSERT_CHECKING
1512         assert(fname);
1513 #else
1514         if (!fname)
1515                 return false;
1516 #endif
1517
1518         /* Find an editor to use */
1519         editorName = getenv("PSQL_EDITOR");
1520         if (!editorName)
1521                 editorName = getenv("EDITOR");
1522         if (!editorName)
1523                 editorName = getenv("VISUAL");
1524         if (!editorName)
1525                 editorName = DEFAULT_EDITOR;
1526
1527         sys = malloc(strlen(editorName) + strlen(fname) + 10 + 1);
1528         if (!sys)
1529                 return false;
1530         sprintf(sys, "exec  %s '%s'", editorName, fname);
1531         result = system(sys);
1532         if (result == -1)
1533                 psql_error("could not start editor %s\n", editorName);
1534         else if (result == 127)
1535                 psql_error("could not start /bin/sh\n");
1536         free(sys);
1537
1538         return result == 0;
1539 }
1540
1541
1542 /* call this one */
1543 static bool
1544 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1545 {
1546         char            fnametmp[MAXPGPATH];
1547         FILE       *stream = NULL;
1548         const char *fname;
1549         bool            error = false;
1550         int                     fd;
1551
1552 #ifndef WIN32
1553         struct stat before,
1554                                 after;
1555 #endif
1556
1557         if (filename_arg)
1558                 fname = filename_arg;
1559
1560         else
1561         {
1562                 /* make a temp file to edit */
1563 #ifndef WIN32
1564                 const char *tmpdirenv = getenv("TMPDIR");
1565
1566                 snprintf(fnametmp, sizeof(fnametmp), "%s/psql.edit.%ld.%ld",
1567                                  tmpdirenv ? tmpdirenv : "/tmp",
1568                                  (long) geteuid(), (long) getpid());
1569 #else
1570                 GetTempFileName(".", "psql", 0, fnametmp);
1571 #endif
1572                 fname = (const char *) fnametmp;
1573
1574                 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
1575                 if (fd != -1)
1576                         stream = fdopen(fd, "w");
1577
1578                 if (fd == -1 || !stream)
1579                 {
1580                         psql_error("could not open temporary file %s: %s\n", fname, strerror(errno));
1581                         error = true;
1582                 }
1583                 else
1584                 {
1585                         unsigned int ql = query_buf->len;
1586
1587                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
1588                         {
1589                                 appendPQExpBufferChar(query_buf, '\n');
1590                                 ql++;
1591                         }
1592
1593                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
1594                         {
1595                                 psql_error("%s: %s\n", fname, strerror(errno));
1596                                 fclose(stream);
1597                                 remove(fname);
1598                                 error = true;
1599                         }
1600                         else
1601                                 fclose(stream);
1602                 }
1603         }
1604
1605 #ifndef WIN32
1606         if (!error && stat(fname, &before) != 0)
1607         {
1608                 psql_error("%s: %s\n", fname, strerror(errno));
1609                 error = true;
1610         }
1611 #endif
1612
1613         /* call editor */
1614         if (!error)
1615                 error = !editFile(fname);
1616
1617 #ifndef WIN32
1618         if (!error && stat(fname, &after) != 0)
1619         {
1620                 psql_error("%s: %s\n", fname, strerror(errno));
1621                 error = true;
1622         }
1623
1624         if (!error && before.st_mtime != after.st_mtime)
1625         {
1626 #else
1627         if (!error)
1628         {
1629 #endif
1630                 stream = fopen(fname, "r");
1631                 if (!stream)
1632                 {
1633                         psql_error("%s: %s\n", fname, strerror(errno));
1634                         error = true;
1635                 }
1636                 else
1637                 {
1638                         /* read file back in */
1639                         char            line[1024];
1640
1641                         resetPQExpBuffer(query_buf);
1642                         while (fgets(line, sizeof(line), stream) != NULL)
1643                                 appendPQExpBufferStr(query_buf, line);
1644
1645                         if (ferror(stream))
1646                         {
1647                                 psql_error("%s: %s\n", fname, strerror(errno));
1648                                 error = true;
1649                         }
1650
1651 #ifdef USE_READLINE
1652                         replace_history_entry(where_history(),query_buf->data,NULL);
1653 #endif
1654                         fclose(stream);
1655                 }
1656
1657         }
1658
1659         /* remove temp file */
1660         if (!filename_arg)
1661         {
1662                 if (remove(fname) == -1)
1663                 {
1664                         psql_error("%s: %s\n", fname, strerror(errno));
1665                         error = true;
1666                 }
1667         }
1668
1669         return !error;
1670 }
1671
1672
1673
1674 /*
1675  * process_file
1676  *
1677  * Read commands from filename and then them to the main processing loop
1678  * Handler for \i, but can be used for other things as well.
1679  */
1680 int
1681 process_file(char *filename)
1682 {
1683         FILE       *fd;
1684         int                     result;
1685         char       *oldfilename;
1686
1687         if (!filename)
1688                 return false;
1689
1690         fd = fopen(filename, "r");
1691
1692         if (!fd)
1693         {
1694                 psql_error("%s: %s\n", filename, strerror(errno));
1695                 return false;
1696         }
1697
1698         oldfilename = pset.inputfile;
1699         pset.inputfile = filename;
1700         result = MainLoop(fd);
1701         fclose(fd);
1702         pset.inputfile = oldfilename;
1703         return result;
1704 }
1705
1706
1707
1708 /*
1709  * do_pset
1710  *
1711  */
1712 static const char *
1713 _align2string(enum printFormat in)
1714 {
1715         switch (in)
1716         {
1717                 case PRINT_NOTHING:
1718                         return "nothing";
1719                         break;
1720                 case PRINT_UNALIGNED:
1721                         return "unaligned";
1722                         break;
1723                 case PRINT_ALIGNED:
1724                         return "aligned";
1725                         break;
1726                 case PRINT_HTML:
1727                         return "html";
1728                         break;
1729                 case PRINT_LATEX:
1730                         return "latex";
1731                         break;
1732         }
1733         return "unknown";
1734 }
1735
1736
1737 bool
1738 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
1739 {
1740         size_t          vallen = 0;
1741
1742 #ifdef USE_ASSERT_CHECKING
1743         assert(param);
1744 #else
1745         if (!param)
1746                 return false;
1747 #endif
1748
1749         if (value)
1750                 vallen = strlen(value);
1751
1752         /* set format */
1753         if (strcmp(param, "format") == 0)
1754         {
1755                 if (!value)
1756                         ;
1757                 else if (strncasecmp("unaligned", value, vallen) == 0)
1758                         popt->topt.format = PRINT_UNALIGNED;
1759                 else if (strncasecmp("aligned", value, vallen) == 0)
1760                         popt->topt.format = PRINT_ALIGNED;
1761                 else if (strncasecmp("html", value, vallen) == 0)
1762                         popt->topt.format = PRINT_HTML;
1763                 else if (strncasecmp("latex", value, vallen) == 0)
1764                         popt->topt.format = PRINT_LATEX;
1765                 else
1766                 {
1767                         psql_error("\\pset: allowed formats are unaligned, aligned, html, latex\n");
1768                         return false;
1769                 }
1770
1771                 if (!quiet)
1772                         printf(gettext("Output format is %s.\n"), _align2string(popt->topt.format));
1773         }
1774
1775         /* set border style/width */
1776         else if (strcmp(param, "border") == 0)
1777         {
1778                 if (value)
1779                         popt->topt.border = atoi(value);
1780
1781                 if (!quiet)
1782                         printf(gettext("Border style is %d.\n"), popt->topt.border);
1783         }
1784
1785         /* set expanded/vertical mode */
1786         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1787         {
1788                 popt->topt.expanded = !popt->topt.expanded;
1789                 if (!quiet)
1790                         printf(popt->topt.expanded
1791                                    ? gettext("Expanded display is on.\n")
1792                                    : gettext("Expanded display is off.\n"));
1793         }
1794
1795         /* null display */
1796         else if (strcmp(param, "null") == 0)
1797         {
1798                 if (value)
1799                 {
1800                         free(popt->nullPrint);
1801                         popt->nullPrint = xstrdup(value);
1802                 }
1803                 if (!quiet)
1804                         printf(gettext("Null display is '%s'.\n"), popt->nullPrint ? popt->nullPrint : "");
1805         }
1806
1807         /* field separator for unaligned text */
1808         else if (strcmp(param, "fieldsep") == 0)
1809         {
1810                 if (value)
1811                 {
1812                         free(popt->topt.fieldSep);
1813                         popt->topt.fieldSep = xstrdup(value);
1814                 }
1815                 if (!quiet)
1816                         printf(gettext("Field separator is '%s'.\n"), popt->topt.fieldSep);
1817         }
1818
1819         /* record separator for unaligned text */
1820         else if (strcmp(param, "recordsep") == 0)
1821         {
1822                 if (value)
1823                 {
1824                         free(popt->topt.recordSep);
1825                         popt->topt.recordSep = xstrdup(value);
1826                 }
1827                 if (!quiet)
1828                 {
1829                         if (strcmp(popt->topt.recordSep, "\n") == 0)
1830                                 printf(gettext("Record separator is <newline>."));
1831                         else
1832                                 printf(gettext("Record separator is '%s'.\n"), popt->topt.recordSep);
1833                 }
1834         }
1835
1836         /* toggle between full and barebones format */
1837         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1838         {
1839                 popt->topt.tuples_only = !popt->topt.tuples_only;
1840                 if (!quiet)
1841                 {
1842                         if (popt->topt.tuples_only)
1843                                 puts(gettext("Showing only tuples."));
1844                         else
1845                                 puts(gettext("Tuples only is off."));
1846                 }
1847         }
1848
1849         /* set title override */
1850         else if (strcmp(param, "title") == 0)
1851         {
1852                 free(popt->title);
1853                 if (!value)
1854                         popt->title = NULL;
1855                 else
1856                         popt->title = xstrdup(value);
1857
1858                 if (!quiet)
1859                 {
1860                         if (popt->title)
1861                                 printf(gettext("Title is \"%s\".\n"), popt->title);
1862                         else
1863                                 printf(gettext("Title is unset.\n"));
1864                 }
1865         }
1866
1867         /* set HTML table tag options */
1868         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1869         {
1870                 free(popt->topt.tableAttr);
1871                 if (!value)
1872                         popt->topt.tableAttr = NULL;
1873                 else
1874                         popt->topt.tableAttr = xstrdup(value);
1875
1876                 if (!quiet)
1877                 {
1878                         if (popt->topt.tableAttr)
1879                                 printf(gettext("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
1880                         else
1881                                 printf(gettext("Table attributes unset.\n"));
1882                 }
1883         }
1884
1885         /* toggle use of pager */
1886         else if (strcmp(param, "pager") == 0)
1887         {
1888                 if (value && strcasecmp(value, "always") == 0)
1889                                 popt->topt.pager = 2;
1890                 else if (popt->topt.pager == 1)
1891                                 popt->topt.pager = 0;
1892                 else
1893                                 popt->topt.pager = 1;
1894                 if (!quiet)
1895                 {
1896                         if (popt->topt.pager == 1)
1897                                 puts(gettext("Using pager is on."));
1898                         else if (popt->topt.pager == 2)
1899                                 puts(gettext("Using pager is always."));
1900                         else
1901                                 puts(gettext("Using pager is off."));
1902                 }
1903         }
1904
1905         /* disable "(x rows)" footer */
1906         else if (strcmp(param, "footer") == 0)
1907         {
1908                 popt->default_footer = !popt->default_footer;
1909                 if (!quiet)
1910                 {
1911                         if (popt->default_footer)
1912                                 puts(gettext("Default footer is on."));
1913                         else
1914                                 puts(gettext("Default footer is off."));
1915                 }
1916         }
1917
1918         else
1919         {
1920                 psql_error("\\pset: unknown option: %s\n", param);
1921                 return false;
1922         }
1923
1924         return true;
1925 }
1926
1927
1928
1929 #define DEFAULT_SHELL "/bin/sh"
1930
1931 static bool
1932 do_shell(const char *command)
1933 {
1934         int                     result;
1935
1936         if (!command)
1937         {
1938                 char       *sys;
1939                 const char *shellName;
1940
1941                 shellName = getenv("SHELL");
1942                 if (shellName == NULL)
1943                         shellName = DEFAULT_SHELL;
1944
1945                 sys = malloc(strlen(shellName) + 16);
1946                 if (!sys)
1947                 {
1948                         psql_error("out of memory\n");
1949                         if (pset.cur_cmd_interactive)
1950                                 return false;
1951                         else
1952                                 exit(EXIT_FAILURE);
1953                 }
1954                 sprintf(sys, "exec %s", shellName);
1955                 result = system(sys);
1956                 free(sys);
1957         }
1958         else
1959                 result = system(command);
1960
1961         if (result == 127 || result == -1)
1962         {
1963                 psql_error("\\!: failed\n");
1964                 return false;
1965         }
1966         return true;
1967 }