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;
 | 
						|
} |