I'm working on a shell and I have a pair of linked lists (one to store shell variables (ones that have been defined by or accessible to scripts/users) and one to store internal variables (ones which are accessible only within the shell itself)) to store variables. I'm having a problem, though, where if I add more than one variable, I can't access the most recently added one, but I can add any that were added before it.
shell_varlist.c
12 13 14 15 16 17
|
struct varlist {
char* variable;
char* value;
struct varlist* prev;
struct varlist* next;
};
| |
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/* Get a pointer to the node containing a variable or NULL if the variable is
* not stored */
static struct varlist* __get_variable(const char* var)
{
struct varlist* pvar = NULL;
if (!vars)
return NULL;
__rewind_list();
if (__list_end()) {
if (strcmp(vars->variable, var) == 0)
pvar = vars;
} else {
while (!(__list_end())) {
if (strcmp(vars->variable, var) == 0) {
pvar = vars;
break;
}
__list_roll_right();
}
}
__fastforward_list();
return pvar;
}
/**
* \brief Add a variable to the list
* \param var Used to refer to the variable
* \param value Value to set for the variable
*
* \note If the variable exists already, its value will be changed
*/
void add_shell_variable(const char* var, const char* value)
{
if (shell_variable_exists(var)) {
/*
* Varialbe already exists, modify its value
*/
struct varlist* node = __get_variable(var);
free(node->value);
node->value = calloc(strlen(value) + 1, 1);
strcpy(node->value, value);
} else {
/*
* New variable - add it to the end of the list
*/
struct varlist* newvar = malloc(sizeof(struct varlist));
newvar->variable = calloc(strlen(var) + 1, 1);
newvar->value = calloc(strlen(value) + 1, 1);
strcpy(newvar->variable, var);
strcpy(newvar->value, value);
newvar->prev = NULL;
newvar->next = NULL;
if (vars) {
__fastforward_list();
newvar->prev = vars;
vars->next = newvar;
__fastforward_list();
} else {
vars = newvar;
}
}
}
| |
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
/**
* \brief Check if a variable exists
* \param var Name of the variable
* \return If the variable exists, 1 is returned. Otherwise, 0 is returned.
*/
int shell_variable_exists(const char* var)
{
if (__get_variable(var))
return 1;
return 0;
}
/**
* \brief Retrieve the value associated with a variable
* \param var Name of the variable
* \return On success, a string containing the value is returned. On error,
* a pointer to NULL is returned.
*/
const char* get_shell_value(const char* var)
{
if (shell_variable_exists(var)) {
struct varlist* node = NULL;
if (!(node = __get_variable(var)))
return NULL;
return node->value;
}
return NULL;
}
| |
At the start of the program, main() calls a function called push_builtins() to add built-in shell variables (like the default prompt string):
builtins.c
11 12 13 14 15
|
void push_builtins()
{
add_shell_variable("PS1", BUILTIN_PS1);
add_shell_variable("PS2", BUILTIN_PS2);
}
| |
after initialization, my (skeletal) interactive function tries to use the variables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
/**
* \brief Read commands from a file, writing prompts to stdout in between
* \return On success, 0 is returned. On error, -1 is returned.
*/
int seash_interactive()
{
for (;;) {
char* input = readline(get_shell_value("PS1"));
add_history(input);
input = readline(get_shell_value("PS2"));
}
return 0;
}
| |
but the output is
seash $
seash $
seash $ ^C |
(the value of PS2 is not printed).
If you need to see anything else, just ask.
Note 1: This code is C, so I can't use C++ constructs or the STL or anything like that.
Note 2: The code for both lists is exactly the same. I'm in the process of unifying it so that both lists will use one set of functions, but I want to work out this problem first.