]> granicus.if.org Git - postgresql/blob - src/bin/psql/variables.c
Update copyright for 2014
[postgresql] / src / bin / psql / variables.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2014, 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.  Valid values are: true,
83  * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof.
84  */
85 bool
86 ParseVariableBool(const char *value)
87 {
88         size_t          len;
89
90         if (value == NULL)
91                 return false;                   /* not set -> assume "off" */
92
93         len = strlen(value);
94
95         if (pg_strncasecmp(value, "true", len) == 0)
96                 return true;
97         else if (pg_strncasecmp(value, "false", len) == 0)
98                 return false;
99         else if (pg_strncasecmp(value, "yes", len) == 0)
100                 return true;
101         else if (pg_strncasecmp(value, "no", len) == 0)
102                 return false;
103         /* 'o' is not unique enough */
104         else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
105                 return true;
106         else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
107                 return false;
108         else if (pg_strcasecmp(value, "1") == 0)
109                 return true;
110         else if (pg_strcasecmp(value, "0") == 0)
111                 return false;
112         else
113         {
114                 /* NULL is treated as false, so a non-matching value is 'true' */
115                 psql_error("unrecognized Boolean value; assuming \"on\"\n");
116                 return true;
117         }
118 }
119
120
121 /*
122  * Read numeric variable, or defaultval if it is not set, or faultval if its
123  * value is not a valid numeric string.  If allowtrail is false, this will
124  * include the case where there are trailing characters after the number.
125  */
126 int
127 ParseVariableNum(const char *val,
128                                  int defaultval,
129                                  int faultval,
130                                  bool allowtrail)
131 {
132         int                     result;
133
134         if (!val)
135                 result = defaultval;
136         else if (!val[0])
137                 result = faultval;
138         else
139         {
140                 char       *end;
141
142                 result = strtol(val, &end, 0);
143                 if (!allowtrail && *end)
144                         result = faultval;
145         }
146
147         return result;
148 }
149
150 int
151 GetVariableNum(VariableSpace space,
152                            const char *name,
153                            int defaultval,
154                            int faultval,
155                            bool allowtrail)
156 {
157         const char *val;
158
159         val = GetVariable(space, name);
160         return ParseVariableNum(val, defaultval, faultval, allowtrail);
161 }
162
163 void
164 PrintVariables(VariableSpace space)
165 {
166         struct _variable *ptr;
167
168         if (!space)
169                 return;
170
171         for (ptr = space->next; ptr; ptr = ptr->next)
172         {
173                 if (ptr->value)
174                         printf("%s = '%s'\n", ptr->name, ptr->value);
175                 if (cancel_pressed)
176                         break;
177         }
178 }
179
180 bool
181 SetVariable(VariableSpace space, const char *name, const char *value)
182 {
183         struct _variable *current,
184                            *previous;
185
186         if (!space)
187                 return false;
188
189         if (!valid_variable_name(name))
190                 return false;
191
192         if (!value)
193                 return DeleteVariable(space, name);
194
195         for (previous = space, current = space->next;
196                  current;
197                  previous = current, current = current->next)
198         {
199                 if (strcmp(current->name, name) == 0)
200                 {
201                         /* found entry, so update */
202                         if (current->value)
203                                 free(current->value);
204                         current->value = pg_strdup(value);
205                         if (current->assign_hook)
206                                 (*current->assign_hook) (current->value);
207                         return true;
208                 }
209         }
210
211         /* not present, make new entry */
212         current = pg_malloc(sizeof *current);
213         current->name = pg_strdup(name);
214         current->value = pg_strdup(value);
215         current->assign_hook = NULL;
216         current->next = NULL;
217         previous->next = current;
218         return true;
219 }
220
221 /*
222  * This both sets a hook function, and calls it on the current value (if any)
223  */
224 bool
225 SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook)
226 {
227         struct _variable *current,
228                            *previous;
229
230         if (!space)
231                 return false;
232
233         if (!valid_variable_name(name))
234                 return false;
235
236         for (previous = space, current = space->next;
237                  current;
238                  previous = current, current = current->next)
239         {
240                 if (strcmp(current->name, name) == 0)
241                 {
242                         /* found entry, so update */
243                         current->assign_hook = hook;
244                         (*hook) (current->value);
245                         return true;
246                 }
247         }
248
249         /* not present, make new entry */
250         current = pg_malloc(sizeof *current);
251         current->name = pg_strdup(name);
252         current->value = NULL;
253         current->assign_hook = hook;
254         current->next = NULL;
255         previous->next = current;
256         (*hook) (NULL);
257         return true;
258 }
259
260 bool
261 SetVariableBool(VariableSpace space, const char *name)
262 {
263         return SetVariable(space, name, "on");
264 }
265
266 bool
267 DeleteVariable(VariableSpace space, const char *name)
268 {
269         struct _variable *current,
270                            *previous;
271
272         if (!space)
273                 return false;
274
275         for (previous = space, current = space->next;
276                  current;
277                  previous = current, current = current->next)
278         {
279                 if (strcmp(current->name, name) == 0)
280                 {
281                         if (current->value)
282                                 free(current->value);
283                         current->value = NULL;
284                         /* Physically delete only if no hook function to remember */
285                         if (current->assign_hook)
286                                 (*current->assign_hook) (NULL);
287                         else
288                         {
289                                 previous->next = current->next;
290                                 free(current->name);
291                                 free(current);
292                         }
293                         return true;
294                 }
295         }
296
297         return true;
298 }