]> granicus.if.org Git - postgresql/blob - src/bin/psql/variables.c
Invent an assign-hook mechanism for psql variables similar to the one
[postgresql] / src / bin / psql / variables.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/variables.c,v 1.26 2006/08/29 15:19:51 tgl Exp $
7  */
8 #include "postgres_fe.h"
9 #include "common.h"
10 #include "variables.h"
11
12
13 /*
14  * A "variable space" is represented by an otherwise-unused struct _variable
15  * that serves as list header.
16  */
17 VariableSpace
18 CreateVariableSpace(void)
19 {
20         struct _variable *ptr;
21
22         ptr = pg_malloc(sizeof *ptr);
23         ptr->name = NULL;
24         ptr->value = NULL;
25         ptr->assign_hook = NULL;
26         ptr->next = NULL;
27
28         return ptr;
29 }
30
31 const char *
32 GetVariable(VariableSpace space, const char *name)
33 {
34         struct _variable *current;
35
36         if (!space)
37                 return NULL;
38
39         for (current = space->next; current; current = current->next)
40         {
41                 if (strcmp(current->name, name) == 0)
42                 {
43                         /* this is correct answer when value is NULL, too */
44                         return current->value;
45                 }
46         }
47
48         return NULL;
49 }
50
51 bool
52 ParseVariableBool(const char *val)
53 {
54         if (val == NULL)
55                 return false;                   /* not set -> assume "off" */
56         if (pg_strcasecmp(val, "off") == 0)
57                 return false;                   /* accept "off" or "OFF" as true */
58
59         /*
60          * for backwards compatibility, anything except "off" or "OFF" is taken as
61          * "true"
62          */
63         return true;
64 }
65
66 /*
67  * Read numeric variable, or defaultval if it is not set, or faultval if its
68  * value is not a valid numeric string.  If allowtrail is false, this will
69  * include the case where there are trailing characters after the number.
70  */
71 int
72 ParseVariableNum(const char *val,
73                                  int defaultval,
74                                  int faultval,
75                                  bool allowtrail)
76 {
77         int                     result;
78
79         if (!val)
80                 result = defaultval;
81         else if (!val[0])
82                 result = faultval;
83         else
84         {
85                 char       *end;
86
87                 result = strtol(val, &end, 0);
88                 if (!allowtrail && *end)
89                         result = faultval;
90         }
91
92         return result;
93 }
94
95 int
96 GetVariableNum(VariableSpace space,
97                            const char *name,
98                            int defaultval,
99                            int faultval,
100                            bool allowtrail)
101 {
102         const char *val;
103
104         val = GetVariable(space, name);
105         return ParseVariableNum(val, defaultval, faultval, allowtrail);
106 }
107
108 void
109 PrintVariables(VariableSpace space)
110 {
111         struct _variable *ptr;
112
113         if (!space)
114                 return;
115
116         for (ptr = space->next; ptr; ptr = ptr->next)
117         {
118                 if (ptr->value)
119                         printf("%s = '%s'\n", ptr->name, ptr->value);
120                 if (cancel_pressed)
121                         break;
122         }
123 }
124
125 bool
126 SetVariable(VariableSpace space, const char *name, const char *value)
127 {
128         struct _variable *current,
129                            *previous;
130
131         if (!space)
132                 return false;
133
134         if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name))
135                 return false;
136
137         if (!value)
138                 return DeleteVariable(space, name);
139
140         for (previous = space, current = space->next;
141                  current;
142                  previous = current, current = current->next)
143         {
144                 if (strcmp(current->name, name) == 0)
145                 {
146                         /* found entry, so update */
147                         if (current->value)
148                                 free(current->value);
149                         current->value = pg_strdup(value);
150                         if (current->assign_hook)
151                                 (*current->assign_hook) (current->value);
152                         return true;
153                 }
154         }
155
156         /* not present, make new entry */
157         current = pg_malloc(sizeof *current);
158         current->name = pg_strdup(name);
159         current->value = pg_strdup(value);
160         current->assign_hook = NULL;
161         current->next = NULL;
162         previous->next = current;
163         return true;
164 }
165
166 /*
167  * This both sets a hook function, and calls it on the current value (if any)
168  */
169 bool
170 SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook)
171 {
172         struct _variable *current,
173                            *previous;
174
175         if (!space)
176                 return false;
177
178         if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name))
179                 return false;
180
181         for (previous = space, current = space->next;
182                  current;
183                  previous = current, current = current->next)
184         {
185                 if (strcmp(current->name, name) == 0)
186                 {
187                         /* found entry, so update */
188                         current->assign_hook = hook;
189                         (*hook) (current->value);
190                         return true;
191                 }
192         }
193
194         /* not present, make new entry */
195         current = pg_malloc(sizeof *current);
196         current->name = pg_strdup(name);
197         current->value = NULL;
198         current->assign_hook = hook;
199         current->next = NULL;
200         previous->next = current;
201         (*hook) (NULL);
202         return true;
203 }
204
205 bool
206 SetVariableBool(VariableSpace space, const char *name)
207 {
208         return SetVariable(space, name, "on");
209 }
210
211 bool
212 DeleteVariable(VariableSpace space, const char *name)
213 {
214         struct _variable *current,
215                            *previous;
216
217         if (!space)
218                 return false;
219
220         for (previous = space, current = space->next;
221                  current;
222                  previous = current, current = current->next)
223         {
224                 if (strcmp(current->name, name) == 0)
225                 {
226                         if (current->value)
227                                 free(current->value);
228                         current->value = NULL;
229                         /* Physically delete only if no hook function to remember */
230                         if (current->assign_hook)
231                                 (*current->assign_hook) (NULL);
232                         else
233                         {
234                                 previous->next = current->next;
235                                 free(current->name);
236                                 free(current);
237                         }
238                         return true;
239                 }
240         }
241
242         return true;
243 }