diff --git a/src/passbook.c b/src/passbook.c
index d42c1e6d67e6e8913f8f5017933ba2b6434faea5..6c2224be00a5ecc5470fd3470bff7ad94a7af81c 100644
--- a/src/passbook.c
+++ b/src/passbook.c
@@ -5,11 +5,6 @@
#include "debug.h"
-/**
- The idea is to eventually implement state dumping by writing a series
- of commands to a file <file> that we can then reload next time by doing
- cat <file> - | ./passbook
-**/
const char INSTRUCTION_PUT[] = "put";
@@ -19,6 +14,8 @@ const char INSTRUCTION_GET[] = "get";
const char INSTRUCTION_SAVE[] = "save";
+const char INSTRUCTION_LIST[] = "list";
+
typedef struct {
char * username;
char * password;
@@ -196,35 +193,55 @@ node_t * map = NULL;
is used to implement stacks/queues of nodes so we can implement various
tree traversal algorithms without using recursion (to avoid stack overflow
for very large trees). */
-typedef struct nodeptr_list {
+typedef struct nodeptr_list_elem {
const node_t *p;
- struct nodeptr_list *next;
- struct nodeptr_list *prev;
+ struct nodeptr_list_elem *next;
+ struct nodeptr_list_elem *prev;
+} nodeptr_list_elem_t;
+
+typedef struct nodeptr_list {
+ nodeptr_list_elem_t *head;
+ nodeptr_list_elem_t *last;
} nodeptr_list_t;
-nodeptr_list_t * list_push(nodeptr_list_t *lst, const node_t *p){
- nodeptr_list_t *n = malloc(sizeof(nodeptr_list_t));
+nodeptr_list_t list_push(nodeptr_list_t lst, const node_t *p){
+ nodeptr_list_elem_t *n = malloc(sizeof(nodeptr_list_elem_t));
assert(n != NULL && "push: malloc failed");
n->p = p;
- n->next = lst;
- if (lst != NULL){
- lst->prev = n;
+ n->next = lst.head;
+ n->prev = NULL;
+ if (lst.head != NULL){
+ assert(lst.last != NULL);
+ lst.head->prev = n;
+ }else{
+ assert(lst.last == NULL);
+ lst.last = n;
}
- n->prev = NULL;
- return n;
+ lst.head = n;
+
+ return lst;
}
/* when out is non-NULL we place a pointer to the first node into it */
-nodeptr_list_t * list_pop(nodeptr_list_t *lst, const node_t **out){
- if (lst != NULL){
+nodeptr_list_t list_pop(nodeptr_list_t lst, const node_t **out){
+ if (lst.head != NULL){
+ assert(lst.last != NULL);
if (out != NULL){
- *out = lst->p;
+ *out = lst.head->p;
+ }
+ if (lst.last == lst.head){
+ free(lst.head);
+ lst.head = NULL;
+ lst.last = NULL;
+ }else{
+ nodeptr_list_elem_t *ret = lst.head->next;
+ free(lst.head);
+ lst.head = ret;
}
- nodeptr_list_t *ret = lst->next;
- free(lst);
- return ret;
+ return lst;
}else{
+ assert(lst.last == NULL);
if (out != NULL){
*out = (const node_t *)NULL;
}
@@ -232,15 +249,43 @@ nodeptr_list_t * list_pop(nodeptr_list_t *lst, const node_t **out){
}
}
-void list_destroy(nodeptr_list_t *lst){
- while (lst != NULL){
+nodeptr_list_t list_dequeue(nodeptr_list_t lst, const node_t **out){
+ if (lst.last != NULL){
+ assert(lst.head != NULL);
+ if (out != NULL){
+ *out = lst.last->p;
+ }
+
+ if (lst.last == lst.head){
+ free(lst.head);
+ lst.head = NULL;
+ lst.last = NULL;
+ }else{
+ nodeptr_list_elem_t *ret = lst.last->prev;
+ free(lst.last);
+ lst.last = ret;
+ }
+ return lst;
+ }else{
+ assert(lst.head == NULL);
+ if (out != NULL){
+ *out = (const node_t *)NULL;
+ }
+ return lst;
+ }
+}
+
+
+nodeptr_list_t list_destroy(nodeptr_list_t lst){
+ while (lst.head != NULL){
lst = list_pop(lst,NULL);
}
+ return lst;
}
-void list_print(nodeptr_list_t *lst){
+void list_print(nodeptr_list_t lst){
printf("\nBegin list print:\n");
- while (lst != NULL){
+ while (lst.head != NULL){
const node_t *p;
lst = list_pop(lst,&p);
node_print(p);
@@ -248,13 +293,24 @@ void list_print(nodeptr_list_t *lst){
printf("End list print.\n\n");
}
+void list_print_rev(nodeptr_list_t lst){
+ printf("\nBegin list reverse print:\n");
+ while (lst.last != NULL){
+ const node_t *p;
+ lst = list_dequeue(lst,&p);
+ node_print(p);
+ }
+ printf("End list reverse print.\n\n");
+}
+
-void print_all(const node_t *p){
- nodeptr_list_t *lst = NULL;
+/* in order traversal to print out nodes in sorted order */
+void print_inorder(const node_t *p){
+ nodeptr_list_t lst = {.head = NULL, .last = NULL};
if (p != NULL){
lst = list_push(lst,p);
- while(lst != NULL){
+ while(lst.head != NULL){
// keep recursing left until we can go no further
while (p->left != NULL){
lst = list_push(lst,p->left);
@@ -277,6 +333,46 @@ void print_all(const node_t *p){
}
}
+void node_save(const node_t *p, FILE *f){
+ fprintf(f,"%s",INSTRUCTION_PUT);
+ fprintf(f," ");
+ fprintf(f,"%s",p->url);
+ fprintf(f," ");
+ fprintf(f,"%s",p->cred.username);
+ fprintf(f," ");
+ fprintf(f,"%s",p->cred.password);
+ fprintf(f,"\n");
+}
+
+/* level order (i.e. breadth-first) traversal to print nodes out in the
+ order that they would need to be put back in to an empty tree to ensure
+ that the resulting tree has the same structure as the original one that
+ was printed out. Returns 0 on success; nonzero on failure */
+int save_levelorder(const node_t *p, const char * filename){
+ FILE *f = fopen(filename,"w");
+ if (f == NULL){
+ debug_printf("Couldn't open file %s for writing.\n",filename);
+ return -1;
+ }
+ nodeptr_list_t lst = {.head = NULL, .last = NULL};
+ if (p != NULL){
+ lst = list_push(lst,p);
+
+ while(lst.last != NULL){
+ lst = list_dequeue(lst,&p);
+ node_save(p,f);
+ if (p->left != NULL){
+ lst = list_push(lst,p->left);
+ }
+ if (p->right != NULL){
+ lst = list_push(lst,p->right);
+ }
+ }
+ }
+ fclose(f);
+ return 0;
+}
+
/* returns 0 on successful execution of the instruction in inst */
static int execute(void){
char * toks[4]; /* these are pointers to start of different tokens */
@@ -288,10 +384,6 @@ static int execute(void){
return 0;
}
- if (numToks < 2){
- return -1;
- }
-
if (strcmp(toks[0],INSTRUCTION_GET) == 0){
if (numToks != 2){
return -1;
@@ -325,8 +417,17 @@ static int execute(void){
return -1;
}
debug_printf("Saving to: %s\n",toks[1]);
- print_all(map);
-
+ if (save_levelorder(map,toks[1]) != 0){
+ return -1;
+ }
+ debug_printf("---\n");
+
+ } else if (strcmp(toks[0],INSTRUCTION_LIST) == 0){
+ if (numToks != 1){
+ return -1;
+ }
+ print_inorder(map);
+
}else{
debug_printf("Unrecognised instruction\n");
return -1;