]> granicus.if.org Git - postgresql/blob - src/bin/psql/variables.c
Update copyright for 2015
[postgresql] / src / bin / psql / variables.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2015, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/variables.c
7  */
8 #include "postgres_fe.h"
9
10 #include "common.h"
11 #include "variables.h"
12
13
14 /*
15  * Check whether a variable's name is allowed.
16  *
17  * We allow any non-ASCII character, as well as ASCII letters, digits, and
18  * underscore.  Keep this in sync with the definition of variable_char in
19  * psqlscan.l.
20  */
21 static bool
22 valid_variable_name(const char *name)
23 {
24         const unsigned char *ptr = (const unsigned char *) name;
25
26         /* Mustn't be zero-length */
27         if (*ptr == '\0')
28                 return false;
29
30         while (*ptr)
31         {
32                 if (IS_HIGHBIT_SET(*ptr) ||
33                         strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
34                                    "_0123456789", *ptr) != NULL)
35                         ptr++;
36                 else
37                         return false;
38         }
39
40         return true;
41 }
42
43 /*
44  * A "variable space" is represented by an otherwise-unused struct _variable
45  * that serves as list header.
46  */
47 VariableSpace
48 CreateVariableSpace(void)
49 {
50         struct _variable *ptr;
51
52         ptr = pg_malloc(sizeof *ptr);
53         ptr->name = NULL;
54         ptr->value = NULL;
55         ptr->assign_hook = NULL;
56         ptr->next = NULL;
57
58         return ptr;
59 }
60
61 const char *
62 GetVariable(VariableSpace space, const char *name)
63 {
64         struct _variable *current;
65
66         if (!space)
67                 return NULL;
68
69         for (current = space->next; current; current = current->next)
70         {
71                 if (strcmp(current->name, name) == 0)
72                 {
73                         /* this is correct answer when value is NULL, too */
74                         return current->value;
75                 }
76         }
77
78         return NULL;
79 }
80
81 /*
82  * Try to interpret "value" as boolean value.
83  *
84  * Valid values are: true, false, yes, no, on, off, 1, 0; as well as unique
85  * prefixes thereof.
86  *
87  * "name" is the name of the variable we're assigning to, to use in error
88  * report if any.  Pass name == NULL to suppress the error report.
89  */
90 bool
91 ParseVariableBool(const char *value, const char *name)
92 {
93         size_t          len;
94
95         if (value == NULL)
96                 return false;                   /* not set -> assume "off" */
97
98         len = strlen(value);
99
100         if (pg_strncasecmp(value, "true", len) == 0)
101                 return true;
102         else if (pg_strncasecmp(value, "false", len) == 0)
103                 return false;
104         else if (pg_strncasecmp(value, "yes", len) == 0)
105                 return true;
106         else if (pg_strncasecmp(value, "no", len) == 0)
107                 return false;
108         /* 'o' is not unique enough */
109         else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
110                 return true;
111         else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
112                 return false;
113         else if (pg_strcasecmp(value, "1") == 0)
114                 return true;
115         else if (pg_strcasecmp(value, "0") == 0)
116                 return false;
117         else
118         {
119                 /* NULL is treated as false, so a non-matching value is 'true' */
120                 if (name)
121                         psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
122                                            value, name, "on");
123                 return true;
124         }
125 }
126
127
128 /*
129  * Read numeric variable, or defaultval if it is not set, or faultval if its
130  * value is not a valid numeric string.  If allowtrail is false, this will
131  * include the case where there are trailing characters after the number.
132  */
133 int
134 ParseVariableNum(const char *val,
135                                  int defaultval,
136                                  int faultval,
137                                  bool allowtrail)
138 {
139         int                     result;
140
141         if (!val)
142                 result = defaultval;
143         else if (!val[0])
144                 result = faultval;
145         else
146         {
147                 char       *end;
148
149                 result = strtol(val, &end, 0);
150                 if (!allowtrail && *end)
151                         result = faultval;
152         }
153
154         return result;
155 }
156
157 int
158 GetVariableNum(VariableSpace space,
159                            const char *name,
160                            int defaultval,
161                            int faultval,
162                            bool allowtrail)
163 {
164         const char *val;
165
166         val = GetVariable(space, name);
167         return ParseVariableNum(val, defaultval, faultval, allowtrail);
168 }
169
170 void
171 PrintVariables(VariableSpace space)
172 {
173         struct _variable *ptr;
174
175         if (!space)
176                 return;
177
178         for (ptr = space->next; ptr; ptr = ptr->next)
179         {
180                 if (ptr->value)
181                         printf("%s = '%s'\n", ptr->name, ptr->value);
182                 if (cancel_pressed)
183                         break;
184         }
185 }
186
187 bool
188 SetVariable(VariableSpace space, const char *name, const char *value)
189 {
190         struct _variable *current,
191                            *previous;
192
193         if (!space)
194                 return false;
195
196         if (!valid_variable_name(name))
197                 return false;
198
199         if (!value)
200                 return DeleteVariable(space, name);
201
202         for (previous = space, current = space->next;
203                  current;
204                  previous = current, current = current->next)
205         {
206                 if (strcmp(current->name, name) == 0)
207                 {
208                         /* found entry, so update */
209                         if (current->value)
210                                 free(current->value);
211                         current->value = pg_strdup(value);
212                         if (current->assign_hook)
213                                 (*current->assign_hook) (current->value);
214                         return true;
215                 }
216         }
217
218         /* not present, make new entry */
219         current = pg_malloc(sizeof *current);
220         current->name = pg_strdup(name);
221         current->value = pg_strdup(value);
222         current->assign_hook = NULL;
223         current->next = NULL;
224         previous->next = current;
225         return true;
226 }
227
228 /*
229  * This both sets a hook function, and calls it on the current value (if any)
230  */
231 bool
232 SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook)
233 {
234         struct _variable *current,
235                            *previous;
236
237         if (!space)
238                 return false;
239
240         if (!valid_variable_name(name))
241                 return false;
242
243         for (previous = space, current = space->next;
244                  current;
245                  previous = current, current = current->next)
246         {
247                 if (strcmp(current->name, name) == 0)
248                 {
249                         /* found entry, so update */
250                         current->assign_hook = hook;
251                         (*hook) (current->value);
252                         return true;
253                 }
254         }
255
256         /* not present, make new entry */
257         current = pg_malloc(sizeof *current);
258         current->name = pg_strdup(name);
259         current->value = NULL;
260         current->assign_hook = hook;
261         current->next = NULL;
262         previous->next = current;
263         (*hook) (NULL);
264         return true;
265 }
266
267 bool
268 SetVariableBool(VariableSpace space, const char *name)
269 {
270         return SetVariable(space, name, "on");
271 }
272
273 bool
274 DeleteVariable(VariableSpace space, const char *name)
275 {
276         struct _variable *current,
277                            *previous;
278
279         if (!space)
280                 return false;
281
282         for (previous = space, current = space->next;
283                  current;
284                  previous = current, current = current->next)
285         {
286                 if (strcmp(current->name, name) == 0)
287                 {
288                         if (current->value)
289                                 free(current->value);
290                         current->value = NULL;
291                         /* Physically delete only if no hook function to remember */
292                         if (current->assign_hook)
293                                 (*current->assign_hook) (NULL);
294                         else
295                         {
296                                 previous->next = current->next;
297                                 free(current->name);
298                                 free(current);
299                         }
300                         return true;
301                 }
302         }
303
304         return true;
305 }