]> granicus.if.org Git - postgresql/blob - src/bin/psql/input.c
here are the patches for psql on Win32:
[postgresql] / src / bin / psql / input.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright 2000 by PostgreSQL Global Development Group
5  *
6  * $Header: /cvsroot/pgsql/src/bin/psql/input.c,v 1.26 2003/07/27 03:32:26 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "input.h"
10
11 #include <errno.h>
12
13 #ifdef WIN32
14 #include <windows.h>
15 #endif
16
17 #include "pqexpbuffer.h"
18 #include "settings.h"
19 #include "tab-complete.h"
20 #include "common.h"
21
22 /* Runtime options for turning off readline and history */
23 /* (of course there is no runtime command for doing that :) */
24 #ifdef USE_READLINE
25 static bool useReadline;
26 static bool useHistory;
27
28 enum histcontrol
29 {
30   hctl_none = 0,
31   hctl_ignorespace = 1,
32   hctl_ignoredups = 2,
33   hctl_ignoreboth = hctl_ignorespace | hctl_ignoredups
34 };
35
36 #endif
37
38 #ifdef HAVE_ATEXIT
39 static void finishInput(void);
40
41 #else
42 /* designed for use with on_exit() */
43 static void finishInput(int, void *);
44 #endif
45
46 #define PSQLHISTORY     ".psql_history"
47
48
49 #ifdef WIN32
50         /*
51          * translate DOS console character set into ANSI, needed e.g. for
52          * German umlauts
53          */
54         if (GetVariableBool(pset.vars, "WIN32_CONSOLE"))
55                 OemToChar(s, s);
56 #endif
57
58 #ifdef USE_READLINE
59 static enum histcontrol
60 GetHistControlConfig(void)
61 {
62         enum histcontrol HC;
63         const char *var;
64
65         var = GetVariable(pset.vars, "HISTCONTROL");
66
67         if (!var)                                                                                               HC = hctl_none;
68         else if         (strcmp(var, "ignorespace") == 0)       HC = hctl_ignorespace;
69         else if         (strcmp(var, "ignoredups") == 0)                HC = hctl_ignoredups;
70         else if (strcmp(var, "ignoreboth") == 0)                HC = hctl_ignoreboth;
71         else                                                                                                            HC = hctl_none;
72
73         return HC;
74 }
75 #endif
76
77
78 static char *
79 gets_basic(const char prompt[])
80 {
81         fputs(prompt, stdout);
82         fflush(stdout);
83         return gets_fromFile(stdin);
84 }
85
86
87 /*
88  * gets_interactive()
89  *
90  * Gets a line of interactive input, using readline of desired.
91  * The result is malloced.
92  */
93 char *
94 gets_interactive(const char *prompt)
95 {
96 #ifdef USE_READLINE
97         char       *s;
98
99         static char *prev_hist = NULL;
100
101         if (useReadline)
102                 /* On some platforms, readline is declared as readline(char *) */
103                 s = readline((char *) prompt);
104         else
105                 s = gets_basic(prompt);
106
107         if (useHistory && s && s[0])
108         {
109                 enum histcontrol HC;
110
111                 HC = GetHistControlConfig();
112
113                 if (((HC & hctl_ignorespace) && s[0] == ' ') ||
114                     ((HC & hctl_ignoredups) && prev_hist && strcmp(s, prev_hist) == 0))
115         {
116                   /* Ignore this line as far as history is concerned */
117                 }
118                 else
119                 {
120                         free(prev_hist);
121                         prev_hist = strdup(s);
122                         add_history(s);
123                 }
124         }
125
126         return s;
127 #else
128         return gets_basic(prompt);
129 #endif
130 }
131
132
133
134 /*
135  * gets_fromFile
136  *
137  * Gets a line of noninteractive input from a file (which could be stdin).
138  */
139 char *
140 gets_fromFile(FILE *source)
141 {
142         PQExpBufferData buffer;
143         char            line[1024];
144
145         initPQExpBuffer(&buffer);
146
147         while (fgets(line, sizeof(line), source) != NULL)
148         {
149                 appendPQExpBufferStr(&buffer, line);
150                 if (buffer.data[buffer.len - 1] == '\n')
151                 {
152                         buffer.data[buffer.len - 1] = '\0';
153                         return buffer.data;
154                 }
155         }
156
157         if (buffer.len > 0)
158                 return buffer.data;             /* EOF after reading some bufferload(s) */
159
160         /* EOF, so return null */
161         termPQExpBuffer(&buffer);
162         return NULL;
163 }
164
165
166
167 /*
168  * Put any startup stuff related to input in here. It's good to maintain
169  * abstraction this way.
170  *
171  * The only "flag" right now is 1 for use readline & history.
172  */
173 void
174 initializeInput(int flags)
175 {
176 #ifdef USE_READLINE
177         if (flags & 1)
178         {
179                 const char *home;
180
181                 useReadline = true;
182                 initialize_readline();
183
184                 useHistory = true;
185                 SetVariable(pset.vars, "HISTSIZE", "500");
186                 using_history();
187                 home = getenv("HOME");
188                 if (home)
189                 {
190                         char       *psql_history = (char *) malloc(strlen(home) + 1 +
191                                                                                                 strlen(PSQLHISTORY) + 1);
192
193                         if (psql_history)
194                         {
195                                 sprintf(psql_history, "%s/%s", home, PSQLHISTORY);
196                                 read_history(psql_history);
197                                 free(psql_history);
198                         }
199                 }
200         }
201 #endif
202
203 #ifdef HAVE_ATEXIT
204         atexit(finishInput);
205 #else
206         on_exit(finishInput, NULL);
207 #endif
208 }
209
210
211
212 bool
213 saveHistory(char *fname)
214 {
215 #ifdef USE_READLINE
216         if (useHistory && fname)
217         {
218                 if (write_history(fname) == 0)
219                 return true;
220
221                 psql_error("could not save history to file \"%s\": %s\n", fname, strerror(errno));
222         }
223 #endif
224
225         return false;
226 }
227
228
229
230 static void
231 #ifdef HAVE_ATEXIT
232 finishInput(void)
233 #else
234 finishInput(int exitstatus, void *arg)
235 #endif
236 {
237 #ifdef USE_READLINE
238         if (useHistory)
239         {
240                 char       *home;
241                 char       *psql_history;
242
243                 home = getenv("HOME");
244                 if (home)
245                 {
246                         psql_history = (char *) malloc(strlen(home) + 1 +
247                                                                         strlen(PSQLHISTORY) + 1);
248                         if (psql_history)
249                         {
250                                 int hist_size;
251                                 hist_size = GetVariableNum(pset.vars,"HISTSIZE",-1,-1,true);
252
253                                 if (hist_size >= 0)
254                                         stifle_history(hist_size);
255
256                                 sprintf(psql_history, "%s/%s", home, PSQLHISTORY);
257                                 write_history(psql_history);
258                                 free(psql_history);
259                         }
260                 }
261         }
262 #endif
263 }