265 lines
7.3 KiB
C
265 lines
7.3 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "store.h"
|
|
|
|
/*
|
|
* This is the "data store" module for Mush.
|
|
* It maintains a mapping from variable names to values.
|
|
* The values of variables are stored as strings.
|
|
* However, the module provides functions for setting and retrieving
|
|
* the value of a variable as an integer. Setting a variable to
|
|
* an integer value causes the value of the variable to be set to
|
|
* a string representation of that integer. Retrieving the value of
|
|
* a variable as an integer is possible if the current value of the
|
|
* variable is the string representation of an integer.
|
|
*/
|
|
|
|
/**
|
|
* @brief Get the current value of a variable as a string.
|
|
* @details This function retrieves the current value of a variable
|
|
* as a string. If the variable has no value, then NULL is returned.
|
|
* Any string returned remains "owned" by the data store module;
|
|
* the caller should not attempt to free the string or to use it
|
|
* after any subsequent call that would modify the value of the variable
|
|
* whose value was retrieved. If the caller needs to use the string for
|
|
* an indefinite period, a copy should be made immediately.
|
|
*
|
|
* @param var The variable whose value is to be retrieved.
|
|
* @return A string that is the current value of the variable, if any,
|
|
* otherwise NULL.
|
|
*/
|
|
char *store_get_string(char *var) {
|
|
store_data *data = store_get_data(var);
|
|
if (data)
|
|
return data->value;
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the current value of a variable as an integer.
|
|
* @details This retrieves the current value of a variable and
|
|
* attempts to interpret it as an integer. If this is possible,
|
|
* then the integer value is stored at the pointer provided by
|
|
* the caller.
|
|
*
|
|
* @param var The variable whose value is to be retrieved.
|
|
* @param valp Pointer at which the returned value is to be stored.
|
|
* @return If the specified variable has no value or the value
|
|
* cannot be interpreted as an integer, then -1 is returned,
|
|
* otherwise 0 is returned.
|
|
*/
|
|
int store_get_int(char *var, long *valp) {
|
|
store_data *data = store_get_data(var);
|
|
if (data) {
|
|
// is NULL
|
|
char *ptr = data->value;
|
|
if (!ptr)
|
|
return -1;
|
|
|
|
// find whether negative or not
|
|
int sign = 1;
|
|
if (*ptr == '-')
|
|
sign = -1, ptr ++;
|
|
|
|
long ans = 0;
|
|
while (*ptr)
|
|
{
|
|
// cannot be interpreted as an integer
|
|
if(*ptr > '9' || *ptr < '0')
|
|
return -1;
|
|
ans = ans * 10 +(*(ptr++) - '0');
|
|
}
|
|
*valp = ans * sign;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the value of a variable as a string.
|
|
* @details This function sets the current value of a specified
|
|
* variable to be a specified string. If the variable already
|
|
* has a value, then that value is replaced. If the specified
|
|
* value is NULL, then any existing value of the variable is removed
|
|
* and the variable becomes un-set. Ownership of the variable and
|
|
* the value strings is not transferred to the data store module as
|
|
* a result of this call; the data store module makes such copies of
|
|
* these strings as it may require.
|
|
*
|
|
* @param var The variable whose value is to be set.
|
|
* @param val The value to set, or NULL if the variable is to become
|
|
* un-set.
|
|
*/
|
|
int store_set_string(char *var, char *val) {
|
|
store_data* data = store_get_data(var);
|
|
// if want to unset a value that does not exist
|
|
if (!data && !val)
|
|
return -1;
|
|
|
|
// unset is val is NULL
|
|
if (!val)
|
|
{
|
|
store_remove_data(data);
|
|
return 0;
|
|
}
|
|
|
|
// set the data to val if data exists
|
|
if (data)
|
|
{
|
|
char *tmp = data->value;
|
|
data->value = store_strcpy(val);
|
|
free(tmp);
|
|
return 0;
|
|
}
|
|
|
|
// create a new data with the value and insert it
|
|
data = malloc(sizeof(store_data));
|
|
data->name = store_strcpy(var);
|
|
data->value = store_strcpy(val);
|
|
store_add_data(data);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the value of a variable as an integer.
|
|
* @details This function sets the current value of a specified
|
|
* variable to be a specified integer. If the variable already
|
|
* has a value, then that value is replaced. Ownership of the variable
|
|
* string is not transferred to the data store module as a result of
|
|
* this call; the data store module makes such copies of this string
|
|
* as it may require.
|
|
*
|
|
* @param var The variable whose value is to be set.
|
|
* @param val The value to set.
|
|
*/
|
|
int store_set_int(char *var, long val) {
|
|
// if val is 0, set var to 0
|
|
if (val == 0)
|
|
return store_set_string(var, "0");
|
|
|
|
char *str, *tmp, *ptr;
|
|
tmp = malloc(sizeof(char));
|
|
int is_negative = 0, size = 0;
|
|
|
|
// check whether val is negative
|
|
if (val < 0)
|
|
is_negative = 1;
|
|
|
|
// get a string with reversed direction
|
|
while (val)
|
|
{
|
|
int remainder = val % 10;
|
|
if (is_negative)
|
|
remainder *= -1;
|
|
tmp[size] = ('0' + remainder);
|
|
tmp = realloc(tmp, (++size + 1) * sizeof(char));
|
|
val /= 10;
|
|
}
|
|
|
|
// alloc memory to str
|
|
if (is_negative) {
|
|
str = malloc((size+2)*sizeof(char));
|
|
ptr = str + 1;
|
|
str[0] = '-';
|
|
}
|
|
else {
|
|
str = malloc((size+1)*sizeof(char));
|
|
ptr = str;
|
|
}
|
|
|
|
// reverse the string back
|
|
for (size_t i = 0; i < size; i++)
|
|
ptr[i] = tmp[size - i - 1];
|
|
|
|
ptr[size] = '\0';
|
|
|
|
// put it in data
|
|
int return_val = store_set_string(var, str);
|
|
|
|
free(str);
|
|
free(tmp);
|
|
|
|
return return_val;
|
|
}
|
|
|
|
/**
|
|
* @brief Print the current contents of the data store.
|
|
* @details This function prints the current contents of the data store
|
|
* to the specified output stream. The format is not specified; this
|
|
* function is intended to be used for debugging purposes.
|
|
*
|
|
* @param f The stream to which the store contents are to be printed.
|
|
*/
|
|
void store_show(FILE *f) {
|
|
store_data* ptr = store_head->next;
|
|
|
|
fprintf(f, "{");
|
|
while (ptr != store_head)
|
|
{
|
|
fprintf(f, "%s=%s", ptr->name, ptr->value);
|
|
ptr = ptr->next;
|
|
if ((ptr != store_head))
|
|
fprintf(f, ", ");
|
|
|
|
}
|
|
fprintf(f, "}\n");
|
|
}
|
|
|
|
void store_init() {
|
|
store_head = malloc(sizeof(store_data));
|
|
store_head->name = NULL;
|
|
store_head->value = NULL;
|
|
store_head->next = store_head;
|
|
store_head->prev = store_head;
|
|
}
|
|
|
|
store_data* store_get_data(char* var) {
|
|
store_data* ptr = store_head->next;
|
|
|
|
while (ptr != store_head)
|
|
{
|
|
if (strcmp(ptr->name, var) == 0)
|
|
return ptr;
|
|
|
|
ptr = ptr->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void store_remove_data(store_data* data) {
|
|
data->prev->next = data->next;
|
|
data->next->prev = data->prev;
|
|
if (data->name)
|
|
free(data->name);
|
|
if (data->value)
|
|
free(data->value);
|
|
free(data);
|
|
}
|
|
|
|
void store_add_data(store_data* data) {
|
|
data->next = store_head->next;
|
|
data->prev = store_head;
|
|
data->next->prev = data;
|
|
data->prev->next = data;
|
|
}
|
|
|
|
void store_fini() {
|
|
while (store_head->next != store_head)
|
|
store_remove_data(store_head->next);
|
|
|
|
free(store_head);
|
|
store_head = NULL;
|
|
}
|
|
|
|
char* store_strcpy(char *str) {
|
|
size_t size = 0;
|
|
char *result = malloc(sizeof(char));
|
|
while (*str)
|
|
{
|
|
result[size] = *(str++);
|
|
result = realloc(result, (++size + 1) * sizeof(char));
|
|
}
|
|
result[size] = '\0';
|
|
return result;
|
|
} |