Header And Logo

PostgreSQL
| The world's most advanced open source database.

variables.c

Go to the documentation of this file.
00001 /*
00002  * psql - the PostgreSQL interactive terminal
00003  *
00004  * Copyright (c) 2000-2013, PostgreSQL Global Development Group
00005  *
00006  * src/bin/psql/variables.c
00007  */
00008 #include "postgres_fe.h"
00009 
00010 #include "common.h"
00011 #include "variables.h"
00012 
00013 
00014 /*
00015  * Check whether a variable's name is allowed.
00016  *
00017  * We allow any non-ASCII character, as well as ASCII letters, digits, and
00018  * underscore.  Keep this in sync with the definition of variable_char in
00019  * psqlscan.l.
00020  */
00021 static bool
00022 valid_variable_name(const char *name)
00023 {
00024     const unsigned char *ptr = (const unsigned char *) name;
00025 
00026     /* Mustn't be zero-length */
00027     if (*ptr == '\0')
00028         return false;
00029 
00030     while (*ptr)
00031     {
00032         if (IS_HIGHBIT_SET(*ptr) ||
00033             strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
00034                    "_0123456789", *ptr) != NULL)
00035             ptr++;
00036         else
00037             return false;
00038     }
00039 
00040     return true;
00041 }
00042 
00043 /*
00044  * A "variable space" is represented by an otherwise-unused struct _variable
00045  * that serves as list header.
00046  */
00047 VariableSpace
00048 CreateVariableSpace(void)
00049 {
00050     struct _variable *ptr;
00051 
00052     ptr = pg_malloc(sizeof *ptr);
00053     ptr->name = NULL;
00054     ptr->value = NULL;
00055     ptr->assign_hook = NULL;
00056     ptr->next = NULL;
00057 
00058     return ptr;
00059 }
00060 
00061 const char *
00062 GetVariable(VariableSpace space, const char *name)
00063 {
00064     struct _variable *current;
00065 
00066     if (!space)
00067         return NULL;
00068 
00069     for (current = space->next; current; current = current->next)
00070     {
00071         if (strcmp(current->name, name) == 0)
00072         {
00073             /* this is correct answer when value is NULL, too */
00074             return current->value;
00075         }
00076     }
00077 
00078     return NULL;
00079 }
00080 
00081 /*
00082  * Try to interpret value as boolean value.  Valid values are: true,
00083  * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof.
00084  */
00085 bool
00086 ParseVariableBool(const char *value)
00087 {
00088     size_t      len;
00089 
00090     if (value == NULL)
00091         return false;           /* not set -> assume "off" */
00092 
00093     len = strlen(value);
00094 
00095     if (pg_strncasecmp(value, "true", len) == 0)
00096         return true;
00097     else if (pg_strncasecmp(value, "false", len) == 0)
00098         return false;
00099     else if (pg_strncasecmp(value, "yes", len) == 0)
00100         return true;
00101     else if (pg_strncasecmp(value, "no", len) == 0)
00102         return false;
00103     /* 'o' is not unique enough */
00104     else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
00105         return true;
00106     else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
00107         return false;
00108     else if (pg_strcasecmp(value, "1") == 0)
00109         return true;
00110     else if (pg_strcasecmp(value, "0") == 0)
00111         return false;
00112     else
00113     {
00114         /* NULL is treated as false, so a non-matching value is 'true' */
00115         psql_error("unrecognized Boolean value; assuming \"on\"\n");
00116         return true;
00117     }
00118 }
00119 
00120 
00121 /*
00122  * Read numeric variable, or defaultval if it is not set, or faultval if its
00123  * value is not a valid numeric string.  If allowtrail is false, this will
00124  * include the case where there are trailing characters after the number.
00125  */
00126 int
00127 ParseVariableNum(const char *val,
00128                  int defaultval,
00129                  int faultval,
00130                  bool allowtrail)
00131 {
00132     int         result;
00133 
00134     if (!val)
00135         result = defaultval;
00136     else if (!val[0])
00137         result = faultval;
00138     else
00139     {
00140         char       *end;
00141 
00142         result = strtol(val, &end, 0);
00143         if (!allowtrail && *end)
00144             result = faultval;
00145     }
00146 
00147     return result;
00148 }
00149 
00150 int
00151 GetVariableNum(VariableSpace space,
00152                const char *name,
00153                int defaultval,
00154                int faultval,
00155                bool allowtrail)
00156 {
00157     const char *val;
00158 
00159     val = GetVariable(space, name);
00160     return ParseVariableNum(val, defaultval, faultval, allowtrail);
00161 }
00162 
00163 void
00164 PrintVariables(VariableSpace space)
00165 {
00166     struct _variable *ptr;
00167 
00168     if (!space)
00169         return;
00170 
00171     for (ptr = space->next; ptr; ptr = ptr->next)
00172     {
00173         if (ptr->value)
00174             printf("%s = '%s'\n", ptr->name, ptr->value);
00175         if (cancel_pressed)
00176             break;
00177     }
00178 }
00179 
00180 bool
00181 SetVariable(VariableSpace space, const char *name, const char *value)
00182 {
00183     struct _variable *current,
00184                *previous;
00185 
00186     if (!space)
00187         return false;
00188 
00189     if (!valid_variable_name(name))
00190         return false;
00191 
00192     if (!value)
00193         return DeleteVariable(space, name);
00194 
00195     for (previous = space, current = space->next;
00196          current;
00197          previous = current, current = current->next)
00198     {
00199         if (strcmp(current->name, name) == 0)
00200         {
00201             /* found entry, so update */
00202             if (current->value)
00203                 free(current->value);
00204             current->value = pg_strdup(value);
00205             if (current->assign_hook)
00206                 (*current->assign_hook) (current->value);
00207             return true;
00208         }
00209     }
00210 
00211     /* not present, make new entry */
00212     current = pg_malloc(sizeof *current);
00213     current->name = pg_strdup(name);
00214     current->value = pg_strdup(value);
00215     current->assign_hook = NULL;
00216     current->next = NULL;
00217     previous->next = current;
00218     return true;
00219 }
00220 
00221 /*
00222  * This both sets a hook function, and calls it on the current value (if any)
00223  */
00224 bool
00225 SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook)
00226 {
00227     struct _variable *current,
00228                *previous;
00229 
00230     if (!space)
00231         return false;
00232 
00233     if (!valid_variable_name(name))
00234         return false;
00235 
00236     for (previous = space, current = space->next;
00237          current;
00238          previous = current, current = current->next)
00239     {
00240         if (strcmp(current->name, name) == 0)
00241         {
00242             /* found entry, so update */
00243             current->assign_hook = hook;
00244             (*hook) (current->value);
00245             return true;
00246         }
00247     }
00248 
00249     /* not present, make new entry */
00250     current = pg_malloc(sizeof *current);
00251     current->name = pg_strdup(name);
00252     current->value = NULL;
00253     current->assign_hook = hook;
00254     current->next = NULL;
00255     previous->next = current;
00256     (*hook) (NULL);
00257     return true;
00258 }
00259 
00260 bool
00261 SetVariableBool(VariableSpace space, const char *name)
00262 {
00263     return SetVariable(space, name, "on");
00264 }
00265 
00266 bool
00267 DeleteVariable(VariableSpace space, const char *name)
00268 {
00269     struct _variable *current,
00270                *previous;
00271 
00272     if (!space)
00273         return false;
00274 
00275     for (previous = space, current = space->next;
00276          current;
00277          previous = current, current = current->next)
00278     {
00279         if (strcmp(current->name, name) == 0)
00280         {
00281             if (current->value)
00282                 free(current->value);
00283             current->value = NULL;
00284             /* Physically delete only if no hook function to remember */
00285             if (current->assign_hook)
00286                 (*current->assign_hook) (NULL);
00287             else
00288             {
00289                 previous->next = current->next;
00290                 free(current->name);
00291                 free(current);
00292             }
00293             return true;
00294         }
00295     }
00296 
00297     return true;
00298 }