CSE320/hw4/src/store.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;
}