diff --git a/src/calc.c b/src/calc.c index 5f6c9cc..451273d 100644 --- a/src/calc.c +++ b/src/calc.c @@ -172,6 +172,8 @@ int calc_item(struct dir *par, char *name) { d->parent = par; d->next = par->sub; par->sub = d; + if(d->next) + d->next->prev = d; d->name = malloc(strlen(name)+1); strcpy(d->name, name); @@ -496,15 +498,14 @@ int calc_process() { /* update references and free original item */ if(orig) { root->next = orig->next; - if(orig->parent) { - t = orig->parent->sub; - if(t == orig) - orig->parent->sub = root; - else if(t != NULL) - for(; t->next!=NULL; t=t->next) - if(t->next == orig) - t->next = root; - } + root->prev = orig->prev; + if(root->parent && root->parent->sub == orig) + root->parent->sub = root; + if(root->prev) + root->prev->next = root; + if(root->next) + root->next->prev = root; + orig->next = orig->prev = NULL; freedir(orig); } browse_init(root->sub); diff --git a/src/dirlist.c b/src/dirlist.c index 35ae634..9e43eec 100644 --- a/src/dirlist.c +++ b/src/dirlist.c @@ -122,6 +122,7 @@ struct dir *dirlist_sort(struct dir *list) { } if(tail) tail->next = e; else list = e; + e->prev = tail; tail = e; } p = q; @@ -225,10 +226,22 @@ struct dir *dirlist_next(struct dir *d) { } +struct dir *dirlist_prev(struct dir *d) { + if(!head || !d) + return NULL; + while((d = d->prev)) { + if(!ISHIDDEN(d)) + return d; + } + if(dirlist_parent) + return dirlist_parent; + return NULL; +} + + /* this function assumes that 'selected' is valid and points to a visible item */ struct dir *dirlist_get(int i) { struct dir *t = selected, *d; - int j; if(!head) return NULL; @@ -247,15 +260,15 @@ struct dir *dirlist_get(int i) { return t; } - /* negative number? start from beginning to get the index of the selected - * item, and then start all over to get the requested item before that. - * XXX: This can obviously be optimized by using a doubly linked list. */ - for(j=0,t=NULL; (t=dirlist_next(t)); j++) - if(t == selected) - break; - for(t=NULL,j+=i; (t=dirlist_next(t))&&j>0; j--) - ; - return t; + /* otherwise, backward */ + while(1) { + d = dirlist_prev(t); + if(!d) + return t; + t = d; + if(!++i) + return t; + } } diff --git a/src/global.h b/src/global.h index 66f0107..e48a58b 100644 --- a/src/global.h +++ b/src/global.h @@ -52,7 +52,7 @@ * XXX: probably a good idea to get rid of the custom _t types and use * fixed-size integers instead, which are much more predictable */ struct dir { - struct dir *parent, *next, *sub, *hlnk; + struct dir *parent, *next, *prev, *sub, *hlnk; char *name; off_t size, asize; unsigned long items; diff --git a/src/util.c b/src/util.c index 6553424..a0dc92d 100644 --- a/src/util.c +++ b/src/util.c @@ -226,16 +226,12 @@ void freedir(struct dir *dr) { freedir_rec(dr->sub); /* update references */ - if(dr->parent) { - /* item is at the top of the dir, refer to next item */ - if(dr->parent->sub == dr) - dr->parent->sub = dr->next; - /* else, get the previous item and update it's "next"-reference */ - else - for(tmp = dr->parent->sub; tmp != NULL; tmp = tmp->next) - if(tmp->next == dr) - tmp->next = dr->next; - } + if(dr->parent && dr->parent->sub == dr) + dr->parent->sub = dr->next; + if(dr->prev) + dr->prev->next = dr->next; + if(dr->next) + dr->next->prev = dr->prev; freedir_hlnk(dr);