Doubly linked list - most recently added variable can't be retrieved

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.
Last edited on
lines 81-87 will only work until __list_end() but form lines above it seems that that is still a valid case. I'd have (instead of lines 77-88)
1
2
3
4
5
6
7
8
while(true){
   if (strcmp(vars->variable, var) == 0) {
      pvar = vars;
      break;
   }
   if(__end_list())break;
   else __list_roll_right();
}
I think..
anyway, this looks like a task for a map..

by the way, how do you set the number of first line in [code] ?
hamsterman wrote:
lines 81-87 will only work until __list_end() but form lines above it seems that that is still a valid case. I'd have (instead of lines 77-88)

Of course! __list_end() returns 0 when vars->next is NULL; so I'm always ignoring the last node. That fixed it. Thanks!

hamsterman wrote:
by the way, how do you set the number of first line in [code] ?

Use [code firstline=n].
glad I could help.

but really, as I said, why would you use a list (in a rather inefficient way, I should add) for a task like this.
don't be lazy, write a map (I'm actually unsure what exactly a map is. I'm thinking of a binary search tree really..)
Topic archived. No new replies allowed.