| /* |
| * psql - the PostgreSQL interactive terminal |
| * |
| * Copyright (c) 2000-2010, PostgreSQL Global Development Group |
| * |
| * src/bin/psql/variables.c |
| */ |
| #include "postgres_fe.h" |
| #include "common.h" |
| #include "variables.h" |
| |
| |
| /* |
| * A "variable space" is represented by an otherwise-unused struct _variable |
| * that serves as list header. |
| */ |
| VariableSpace |
| CreateVariableSpace(void) |
| { |
| struct _variable *ptr; |
| |
| ptr = pg_malloc(sizeof *ptr); |
| ptr->name = NULL; |
| ptr->value = NULL; |
| ptr->assign_hook = NULL; |
| ptr->next = NULL; |
| |
| return ptr; |
| } |
| |
| const char * |
| GetVariable(VariableSpace space, const char *name) |
| { |
| struct _variable *current; |
| |
| if (!space) |
| return NULL; |
| |
| for (current = space->next; current; current = current->next) |
| { |
| if (strcmp(current->name, name) == 0) |
| { |
| /* this is correct answer when value is NULL, too */ |
| return current->value; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /* |
| * Try to interpret value as boolean value. Valid values are: true, |
| * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof. |
| */ |
| bool |
| ParseVariableBool(const char *value) |
| { |
| size_t len; |
| |
| if (value == NULL) |
| return false; /* not set -> assume "off" */ |
| |
| len = strlen(value); |
| |
| if (pg_strncasecmp(value, "true", len) == 0) |
| return true; |
| else if (pg_strncasecmp(value, "false", len) == 0) |
| return false; |
| else if (pg_strncasecmp(value, "yes", len) == 0) |
| return true; |
| else if (pg_strncasecmp(value, "no", len) == 0) |
| return false; |
| /* 'o' is not unique enough */ |
| else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0) |
| return true; |
| else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0) |
| return false; |
| else if (pg_strcasecmp(value, "1") == 0) |
| return true; |
| else if (pg_strcasecmp(value, "0") == 0) |
| return false; |
| else |
| { |
| /* NULL is treated as false, so a non-matching value is 'true' */ |
| psql_error("unrecognized boolean value; assuming \"on\".\n"); |
| return true; |
| } |
| /* suppress compiler warning */ |
| return true; |
| } |
| |
| |
| /* |
| * Read numeric variable, or defaultval if it is not set, or faultval if its |
| * value is not a valid numeric string. If allowtrail is false, this will |
| * include the case where there are trailing characters after the number. |
| */ |
| int |
| ParseVariableNum(const char *val, |
| int defaultval, |
| int faultval, |
| bool allowtrail) |
| { |
| int result; |
| |
| if (!val) |
| result = defaultval; |
| else if (!val[0]) |
| result = faultval; |
| else |
| { |
| char *end; |
| |
| result = strtol(val, &end, 0); |
| if (!allowtrail && *end) |
| result = faultval; |
| } |
| |
| return result; |
| } |
| |
| int |
| GetVariableNum(VariableSpace space, |
| const char *name, |
| int defaultval, |
| int faultval, |
| bool allowtrail) |
| { |
| const char *val; |
| |
| val = GetVariable(space, name); |
| return ParseVariableNum(val, defaultval, faultval, allowtrail); |
| } |
| |
| void |
| PrintVariables(VariableSpace space) |
| { |
| struct _variable *ptr; |
| |
| if (!space) |
| return; |
| |
| for (ptr = space->next; ptr; ptr = ptr->next) |
| { |
| if (ptr->value) |
| printf("%s = '%s'\n", ptr->name, ptr->value); |
| if (cancel_pressed) |
| break; |
| } |
| } |
| |
| bool |
| SetVariable(VariableSpace space, const char *name, const char *value) |
| { |
| struct _variable *current, |
| *previous; |
| |
| if (!space) |
| return false; |
| |
| if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) |
| return false; |
| |
| if (!value) |
| return DeleteVariable(space, name); |
| |
| for (previous = space, current = space->next; |
| current; |
| previous = current, current = current->next) |
| { |
| if (strcmp(current->name, name) == 0) |
| { |
| /* found entry, so update */ |
| if (current->value) |
| free(current->value); |
| current->value = pg_strdup(value); |
| if (current->assign_hook) |
| (*current->assign_hook) (current->value); |
| return true; |
| } |
| } |
| |
| /* not present, make new entry */ |
| current = pg_malloc(sizeof *current); |
| current->name = pg_strdup(name); |
| current->value = pg_strdup(value); |
| current->assign_hook = NULL; |
| current->next = NULL; |
| previous->next = current; |
| return true; |
| } |
| |
| /* |
| * This both sets a hook function, and calls it on the current value (if any) |
| */ |
| bool |
| SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook) |
| { |
| struct _variable *current, |
| *previous; |
| |
| if (!space) |
| return false; |
| |
| if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) |
| return false; |
| |
| for (previous = space, current = space->next; |
| current; |
| previous = current, current = current->next) |
| { |
| if (strcmp(current->name, name) == 0) |
| { |
| /* found entry, so update */ |
| current->assign_hook = hook; |
| (*hook) (current->value); |
| return true; |
| } |
| } |
| |
| /* not present, make new entry */ |
| current = pg_malloc(sizeof *current); |
| current->name = pg_strdup(name); |
| current->value = NULL; |
| current->assign_hook = hook; |
| current->next = NULL; |
| previous->next = current; |
| (*hook) (NULL); |
| return true; |
| } |
| |
| bool |
| SetVariableBool(VariableSpace space, const char *name) |
| { |
| return SetVariable(space, name, "on"); |
| } |
| |
| bool |
| DeleteVariable(VariableSpace space, const char *name) |
| { |
| struct _variable *current, |
| *previous; |
| |
| if (!space) |
| return false; |
| |
| for (previous = space, current = space->next; |
| current; |
| previous = current, current = current->next) |
| { |
| if (strcmp(current->name, name) == 0) |
| { |
| if (current->value) |
| free(current->value); |
| current->value = NULL; |
| /* Physically delete only if no hook function to remember */ |
| if (current->assign_hook) |
| (*current->assign_hook) (NULL); |
| else |
| { |
| previous->next = current->next; |
| free(current->name); |
| free(current); |
| } |
| return true; |
| } |
| } |
| |
| return true; |
| } |