OSDN Git Service

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