summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2010-03-07 11:10:00 +0100
committerYorhel <git@yorhel.nl>2010-03-07 11:10:00 +0100
commit5db9c2aea11052451c7e11bf8eef73393e4a072e (patch)
treeca038011883471a3f2efa853659f9eedf2c3a3ad
parentfe21608e98053540d2b8b5d7af42f80a8ee03c46 (diff)
Abstracted dir list handling from browser.c into dirlist.c
This optimizes a few actions (though not all), and makes the code easier to understand and expand. The behaviour of the browser has changed a bit with regards to multi-page listings. Personally I don't like this change much, so I'd probably fix that later on.
-rw-r--r--src/Makefile.am4
-rw-r--r--src/browser.c386
-rw-r--r--src/dirlist.c293
-rw-r--r--src/dirlist.h78
-rw-r--r--src/global.h1
5 files changed, 476 insertions, 286 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index bf6a746..3047a5e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
bin_PROGRAMS = ncdu
-ncdu_SOURCES = browser.c calc.c delete.c exclude.c help.c main.c path.c util.c
+ncdu_SOURCES = browser.c calc.c delete.c dirlist.c exclude.c help.c main.c path.c util.c
-noinst_HEADERS = browser.h calc.h delete.h exclude.h global.h help.h path.h util.h
+noinst_HEADERS = browser.h calc.h delete.h dirlist.h exclude.h global.h help.h path.h util.h
diff --git a/src/browser.c b/src/browser.c
index 76c3ebd..84b42cb 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -30,103 +30,12 @@
#include <ncurses.h>
-#define BF_NAME 0x01
-#define BF_SIZE 0x02
-#define BF_NDIRF 0x04 /* Normally, dirs before files, setting this disables it */
-#define BF_DESC 0x08
-#define BF_HIDE 0x10 /* don't show hidden files... */
-#define BF_AS 0x40 /* show apparent sizes instead of disk usage */
-#define BF_INFO 0x80 /* show file information window */
-
-struct dir *browse_dir = NULL;
-unsigned char graph = 0,
- flags = BF_SIZE | BF_DESC,
- info_page = 0, info_start = 0;
-
-
-#define ishidden(x) (flags & BF_HIDE && (\
- (x->next != browse_dir && (x->name[0] == '.' || x->name[strlen(x->name)-1] == '~'))\
- || x->flags & FF_EXL))
-
-
-int browse_cmp(struct dir *x, struct dir *y) {
- struct dir *a, *b;
- int r = 0;
-
- if(flags & BF_DESC) {
- a = y; b = x;
- } else {
- b = y; a = x;
- }
- if(!(flags & BF_NDIRF) && y->flags & FF_DIR && !(x->flags & FF_DIR))
- return(1);
- if(!(flags & BF_NDIRF) && !(y->flags & FF_DIR) && x->flags & FF_DIR)
- return(-1);
-
- if(flags & BF_NAME)
- r = strcmp(a->name, b->name);
- if(flags & BF_AS) {
- if(r == 0)
- r = a->asize > b->asize ? 1 : (a->asize == b->asize ? 0 : -1);
- if(r == 0)
- r = a->size > b->size ? 1 : (a->size == b->size ? 0 : -1);
- } else {
- if(r == 0)
- r = a->size > b->size ? 1 : (a->size == b->size ? 0 : -1);
- if(r == 0)
- r = a->asize > b->asize ? 1 : (a->asize == b->asize ? 0 : -1);
- }
- if(r == 0)
- r = strcmp(x->name, y->name);
- return(r);
-}
-
+int graph = 0,
+ show_as = 0,
+ info_show = 0,
+ info_page = 0,
+ info_start = 0;
-struct dir *browse_sort(struct dir *list) {
- struct dir *p, *q, *e, *tail;
- int insize, nmerges, psize, qsize, i;
-
- insize = 1;
- while(1) {
- p = list;
- list = NULL;
- tail = NULL;
- nmerges = 0;
- while(p) {
- nmerges++;
- q = p;
- psize = 0;
- for(i=0; i<insize; i++) {
- psize++;
- q = q->next;
- if(!q) break;
- }
- qsize = insize;
- while(psize > 0 || (qsize > 0 && q)) {
- if(psize == 0) {
- e = q; q = q->next; qsize--;
- } else if(qsize == 0 || !q) {
- e = p; p = p->next; psize--;
- } else if(browse_cmp(p,q) <= 0) {
- e = p; p = p->next; psize--;
- } else {
- e = q; q = q->next; qsize--;
- }
- if(tail) tail->next = e;
- else list = e;
- tail = e;
- }
- p = q;
- }
- tail->next = NULL;
- if(nmerges <= 1) {
- if(list->parent)
- list->parent->sub = list;
- return list;
- }
- insize *= 2;
- }
-}
void browse_draw_info(struct dir *dr) {
@@ -181,7 +90,7 @@ void browse_draw_info(struct dir *dr) {
}
-void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
+void browse_draw_item(struct dir *n, int row) {
char *line, ct, dt, *size, gr[11];
int i, o;
float pc;
@@ -190,7 +99,7 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
attron(A_REVERSE);
/* reference to parent dir has a different format */
- if(ispar) {
+ if(n == dirlist_parent) {
mvhline(row, 0, ' ', wincols);
o = graph == 0 ? 12 :
graph == 1 ? 24 :
@@ -214,17 +123,21 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
&& n->sub == NULL ? 'e' :
' ' ;
dt = n->flags & FF_DIR ? '/' : ' ';
- size = formatsize(flags & BF_AS ? n->asize : n->size);
+ size = formatsize(show_as ? n->asize : n->size);
/* create graph (if necessary) */
- if((pc = (float)(flags & BF_AS ? n->parent->asize : n->parent->size)) < 1)
- pc = 1.0f;
- pc = ((float)(flags & BF_AS ? n->asize : n->size) / pc) * 100.0f;
- if(graph == 1 || graph == 3) {
- o = (int)(10.0f*(float)(flags & BF_AS ? n->asize : n->size) / (float)max);
- for(i=0; i<10; i++)
- gr[i] = i < o ? '#' : ' ';
- gr[10] = '\0';
+ if(graph) {
+ /* percentage */
+ if((pc = (float)(show_as ? n->parent->asize : n->parent->size)) < 1)
+ pc = 1.0f;
+ pc = ((float)(show_as ? n->asize : n->size) / pc) * 100.0f;
+ /* graph */
+ if(graph == 1 || graph == 3) {
+ o = (int)(10.0f*(float)(show_as ? n->asize : n->size) / (float)(show_as ? dirlist_maxa : dirlist_maxs));
+ for(i=0; i<10; i++)
+ gr[i] = i < o ? '#' : ' ';
+ gr[10] = '\0';
+ }
}
/* format and add item to the list */
@@ -254,134 +167,74 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
void browse_draw() {
- struct dir *n, ref, *cur, *sel = NULL;
- char *line, *tmp;
+ struct dir *t;
+ char fmtsize[9], *tmp;
int selected, i;
- off_t max = 1;
erase();
- cur = browse_dir;
+ t = dirlist_get(0);
- /* create header and status bar */
+ /* top line - basic info */
attron(A_REVERSE);
mvhline(0, 0, ' ', wincols);
mvhline(winrows-1, 0, ' ', wincols);
mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ? for help", PACKAGE_NAME, PACKAGE_VERSION);
-
- if(cur) {
- line = malloc(winrows+1);
- strcpy(line, formatsize(cur->parent->size));
- mvprintw(winrows-1, 0, " Total disk usage: %s Apparent size: %s Items: %d",
- line, formatsize(cur->parent->asize), cur->parent->items);
- free(line);
- } else
- mvaddstr(winrows-1, 0, " No items to display.");
attroff(A_REVERSE);
+ /* second line - the path */
mvhline(1, 0, '-', wincols);
- if(cur) {
+ if(t) {
mvaddch(1, 3, ' ');
- tmp = getpath(cur->parent);
+ tmp = getpath(t->parent);
mvaddstr(1, 4, cropstr(tmp, wincols-8));
mvaddch(1, 4+((int)strlen(tmp) > wincols-8 ? wincols-8 : (int)strlen(tmp)), ' ');
}
- if(!cur)
- return;
+ /* bottom line - stats */
+ attron(A_REVERSE);
+ if(t) {
+ strcpy(fmtsize, formatsize(t->parent->size));
+ mvprintw(winrows-1, 0, " Total disk usage: %s Apparent size: %s Items: %d",
+ fmtsize, formatsize(t->parent->asize), t->parent->items);
+ } else
+ mvaddstr(winrows-1, 0, " No items to display.");
+ attroff(A_REVERSE);
- /* add reference to parent dir */
- memset(&ref, 0, sizeof(struct dir));
- if(cur->parent->parent) {
- ref.name = "..";
- ref.next = cur;
- ref.parent = cur->parent;
- cur = &ref;
- }
+ /* nothing to display? stop here. */
+ if(!t)
+ return;
- /* get maximum size and selected item */
- for(n=cur, selected=-1, i=0; n!=NULL; n=n->next) {
- if(ishidden(n))
- continue;
- if(n->flags & FF_BSEL) {
- selected = i;
- sel = n;
- }
- if((flags & BF_AS ? n->asize : n->size) > max)
- max = flags & BF_AS ? n->asize : n->size;
- i++;
- }
- if(selected < 0)
- cur->flags |= FF_BSEL;
-
- /* determine start position */
- for(n=cur,i=0; n!=NULL; n=n->next) {
- if(ishidden(n))
- continue;
- if(i == (selected / (winrows-3)) * (winrows-3))
- break;
- i++;
- }
- selected -= i;
+ /* get start position */
+ t = dirlist_get(-1*((winrows)/2));
+ if(t == dirlist_next(NULL))
+ t = NULL;
/* print the list to the screen */
- for(i=0; n!=NULL && i<winrows-3; n=n->next) {
- if(ishidden(n))
- continue;
- browse_draw_item(n, 2+i++, max, n == &ref);
+ for(i=0; (t=dirlist_next(t)) && i<winrows-3; i++) {
+ browse_draw_item(t, 2+i);
+ /* save the selected row number for later */
+ if(t->flags & FF_BSEL)
+ selected = i;
}
/* draw information window */
- if(sel && (flags & BF_INFO) && sel != &ref)
- browse_draw_info(sel);
+ t = dirlist_get(0);
+ if(info_show && t != dirlist_parent)
+ browse_draw_info(t);
/* move cursor to selected row for accessibility */
move(selected+2, 0);
}
-void browse_key_sel(int change) {
- struct dir *n, *cur, par;
- int i, max;
-
- if((cur = browse_dir) == NULL)
- return;
- par.next = cur;
- par.flags = 0;
- if(cur->parent->parent)
- cur = &par;
-
- i = 0;
- max = -1;
- for(n=cur; n!=NULL; n=n->next) {
- if(!ishidden(n)) {
- max++;
- if(n->flags & FF_BSEL)
- i = max;
- }
- n->flags &= ~FF_BSEL;
- }
- i += change;
- i = i<0 ? 0 : i>max ? max : i;
-
- for(n=cur; n!=NULL; n=n->next)
- if(!ishidden(n) && !i--)
- n->flags |= FF_BSEL;
-}
-
-
-#define toggle(x,y) if(x & y) x -=y; else x |= y
-
int browse_key(int ch) {
- char sort = 0, nonfo = 0, catch = 0;
- struct dir *r, *sel;
- int i;
+ struct dir *t, *sel;
+ int i, catch = 0;
- for(sel=browse_dir; sel!=NULL; sel=sel->next)
- if(sel->flags & FF_BSEL)
- break;
+ sel = dirlist_get(0);
/* info window overwrites a few keys */
- if(flags & BF_INFO && sel)
+ if(info_show && sel)
switch(ch) {
case '1':
info_page = 0;
@@ -416,7 +269,7 @@ int browse_key(int ch) {
case 'j':
case ' ':
if(sel->hlnk && info_page == 1) {
- for(i=0,r=sel->hlnk; r!=sel; r=r->hlnk)
+ for(i=0,t=sel->hlnk; t!=sel; t=t->hlnk)
i++;
if(i > info_start+6)
info_start++;
@@ -430,155 +283,120 @@ int browse_key(int ch) {
/* selecting items */
case KEY_UP:
case 'k':
- browse_key_sel(-1);
+ dirlist_select(dirlist_get(-1));
info_start = 0;
break;
case KEY_DOWN:
case 'j':
- browse_key_sel(1);
+ dirlist_select(dirlist_get(1));
info_start = 0;
break;
case KEY_HOME:
- browse_key_sel(-1*(1<<30));
+ dirlist_select(dirlist_next(NULL));
info_start = 0;
break;
case KEY_LL:
case KEY_END:
- browse_key_sel(1<<30);
+ dirlist_select(dirlist_get(1<<30));
info_start = 0;
break;
case KEY_PPAGE:
- browse_key_sel(-1*(winrows-3));
+ dirlist_select(dirlist_get(-1*(winrows-3)));
info_start = 0;
break;
case KEY_NPAGE:
- browse_key_sel(winrows-3);
+ dirlist_select(dirlist_get(winrows-3));
info_start = 0;
break;
/* sorting items */
case 'n':
- if(flags & BF_NAME)
- toggle(flags, BF_DESC);
- else
- flags = (flags & BF_HIDE) + (flags & BF_NDIRF) + BF_NAME;
- sort++;
- nonfo++;
+ dirlist_set_sort(DL_COL_NAME, dirlist_sort_col == DL_COL_NAME ? !dirlist_sort_desc : DL_NOCHANGE, DL_NOCHANGE);
+ info_show = 0;
break;
case 's':
- if(flags & BF_SIZE)
- toggle(flags, BF_DESC);
- else
- flags = (flags & BF_HIDE) + (flags & BF_NDIRF) + BF_SIZE + BF_DESC;
- sort++;
- nonfo++;
+ i = show_as ? DL_COL_ASIZE : DL_COL_SIZE;
+ dirlist_set_sort(i, dirlist_sort_col == i ? !dirlist_sort_desc : DL_NOCHANGE, DL_NOCHANGE);
+ info_show = 0;
break;
case 'e':
- toggle(flags, BF_HIDE);
- browse_key_sel(0);
- nonfo++;
+ dirlist_set_hidden(!dirlist_hidden);
+ info_show = 0;
break;
case 't':
- toggle(flags, BF_NDIRF);
- sort++;
- nonfo++;
+ dirlist_set_sort(DL_NOCHANGE, DL_NOCHANGE, dirlist_sort_df);
+ info_show = 0;
break;
case 'a':
- toggle(flags, BF_AS);
- nonfo++;
+ show_as = !show_as;
+ if(dirlist_sort_col == DL_COL_ASIZE || dirlist_sort_col == DL_COL_SIZE)
+ dirlist_set_sort(show_as ? DL_COL_ASIZE : DL_COL_SIZE, DL_NOCHANGE, DL_NOCHANGE);
+ info_show = 0;
break;
/* browsing */
case 10:
case KEY_RIGHT:
case 'l':
- if(sel != NULL && sel->sub != NULL) {
- browse_dir = sel->sub;
- sort++;
- }
- if(sel == NULL && browse_dir != NULL && browse_dir->parent->parent) {
- browse_dir = browse_dir->parent->parent->sub;
- sort++;
- }
- browse_key_sel(0);
- nonfo++;
+ if(sel != NULL && sel->sub != NULL)
+ dirlist_open(sel->sub);
+ info_show = 0;
break;
case KEY_LEFT:
case 'h':
case '<':
- if(browse_dir != NULL && browse_dir->parent->parent != NULL) {
- browse_dir = browse_dir->parent->parent->sub;
- sort++;
- }
- browse_key_sel(0);
- nonfo++;
+ if(sel != NULL && sel->parent->parent != NULL)
+ dirlist_open(sel->parent);
+ info_show = 0;
break;
/* and other stuff */
case 'r':
- if(browse_dir != NULL)
- calc_init(getpath(browse_dir->parent), browse_dir->parent);
- nonfo++;
+ if(sel != NULL)
+ calc_init(getpath(sel->parent), sel->parent);
+ info_show = 0;
break;
case 'q':
- if(flags & BF_INFO)
- nonfo++;
+ if(info_show)
+ info_show = 0;
else
return 1;
break;
case 'g':
if(++graph > 3)
graph = 0;
- nonfo++;
+ info_show = 0;
break;
case 'i':
- toggle(flags, BF_INFO);
+ info_show = !info_show;
break;
case '?':
help_init();
- nonfo++;
+ info_show = 0;
break;
case 'd':
- if(sel == NULL)
+ if(sel == NULL || sel == dirlist_parent)
break;
- nonfo++;
- /* quirky method of getting the next selected dir without actually selecting it */
- browse_key_sel(sel->next ? 1 : -1);
- for(r=browse_dir; r!=NULL; r=r->next)
- if(r->flags & FF_BSEL)
- break;
- browse_key_sel(sel->next ? -1 : 1);
- delete_init(sel, r);
+ info_show = 0;
+ if((t = dirlist_get(1)) == sel)
+ t = dirlist_get(-1);
+ delete_init(sel, t);
break;
}
- if(sort && browse_dir != NULL)
- browse_dir = browse_sort(browse_dir);
- if(nonfo) {
- flags &= ~BF_INFO;
- info_start = 0;
- }
- if(flags & BF_INFO) {
- for(sel=browse_dir; sel!=NULL; sel=sel->next)
- if(sel->flags & FF_BSEL)
- break;
- if(sel && !sel->hlnk)
- info_page = 0;
- }
+ /* make sure the info_* options are correct */
+ sel = dirlist_get(0);
+ if(!info_show || sel == dirlist_parent)
+ info_show = info_page = info_start = 0;
+ else if(sel && !sel->hlnk)
+ info_page = info_start = 0;
+
return 0;
}
void browse_init(struct dir *cur) {
pstate = ST_BROWSE;
- if(cur != NULL && cur->parent == NULL)
- browse_dir = cur->sub;
- else
- browse_dir = cur;
- if(browse_dir != NULL && browse_dir->parent->sub != browse_dir)
- browse_dir = cur->parent->sub;
- if(browse_dir != NULL)
- browse_dir = browse_sort(browse_dir);
- browse_key_sel(0);
+ dirlist_open(cur);
}
diff --git a/src/dirlist.c b/src/dirlist.c
new file mode 100644
index 0000000..ed1d1da
--- /dev/null
+++ b/src/dirlist.c
@@ -0,0 +1,293 @@
+/* ncdu - NCurses Disk Usage
+
+ Copyright (c) 2007-2010 Yoran Heling
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include "global.h"
+
+#include <string.h>
+
+
+/* public variables */
+struct dir *dirlist_parent = NULL;
+off_t dirlist_maxs = 0,
+ dirlist_maxa = 0;
+
+int dirlist_sort_desc = 1,
+ dirlist_sort_col = DL_COL_SIZE,
+ dirlist_sort_df = 0,
+ dirlist_hidden = 0;
+
+/* private state vars */
+struct dir dirlist_parent_alloc;
+struct dir *head, *head_real, *selected;
+
+
+
+#define ISHIDDEN(d) (dirlist_hidden && (d) != dirlist_parent && (\
+ (d)->flags & FF_EXL || (d)->name[0] == '.' || (d)->name[strlen((d)->name)-1] == '~'\
+ ))
+
+
+
+int dirlist_cmp(struct dir *x, struct dir *y) {
+ int r;
+
+ /* dirs are always before files when that option is set */
+ if(dirlist_sort_df) {
+ if(y->flags & FF_DIR && !(x->flags & FF_DIR))
+ return 1;
+ else if(!(y->flags & FF_DIR) && x->flags & FF_DIR)
+ return -1;
+ }
+
+ /* sort columns:
+ * 1 -> 2 -> 3
+ * NAME: name -> size -> asize
+ * SIZE: size -> asize -> name
+ * ASIZE: asize -> size -> name
+ *
+ * Note that the method used below is supposed to be fast, not readable :-)
+ */
+#define CMP_NAME strcmp(x->name, y->name)
+#define CMP_SIZE (x->size > y->size ? 1 : (x->size == y->size ? 0 : -1))
+#define CMP_ASIZE (x->asize > y->asize ? 1 : (x->asize == y->asize ? 0 : -1))
+
+ /* try 1 */
+ r = dirlist_sort_col == DL_COL_NAME ? CMP_NAME : dirlist_sort_col == DL_COL_SIZE ? CMP_SIZE : CMP_ASIZE;
+ /* try 2 */
+ if(!r)
+ r = dirlist_sort_col == DL_COL_SIZE ? CMP_ASIZE : CMP_SIZE;
+ /* try 3 */
+ if(!r)
+ r = dirlist_sort_col == DL_COL_NAME ? CMP_ASIZE : CMP_NAME;
+
+ /* reverse when sorting in descending order */
+ if(dirlist_sort_desc && r != 0)
+ r = r < 0 ? 1 : -1;
+
+ return r;
+}
+
+
+struct dir *dirlist_sort(struct dir *list) {
+ struct dir *p, *q, *e, *tail;
+ int insize, nmerges, psize, qsize, i;
+
+ insize = 1;
+ while(1) {
+ p = list;
+ list = NULL;
+ tail = NULL;
+ nmerges = 0;
+ while(p) {
+ nmerges++;
+ q = p;
+ psize = 0;
+ for(i=0; i<insize; i++) {
+ psize++;
+ q = q->next;
+ if(!q) break;
+ }
+ qsize = insize;
+ while(psize > 0 || (qsize > 0 && q)) {
+ if(psize == 0) {
+ e = q; q = q->next; qsize--;
+ } else if(qsize == 0 || !q) {
+ e = p; p = p->next; psize--;
+ } else if(dirlist_cmp(p,q) <= 0) {
+ e = p; p = p->next; psize--;
+ } else {
+ e = q; q = q->next; qsize--;
+ }
+ if(tail) tail->next = e;
+ else list = e;
+ tail = e;
+ }
+ p = q;
+ }
+ tail->next = NULL;
+ if(nmerges <= 1) {
+ if(list->parent)
+ list->parent->sub = list;
+ return list;
+ }
+ insize *= 2;
+ }
+}
+
+
+/* passes through the dir listing once and:
+ * - makes sure one, and only one, visible item is selected
+ * - updates the dirlist_(maxs|maxa) values
+ * - makes sure that the FF_BSEL bits are correct */
+void dirlist_fixup() {
+ struct dir *t;
+
+ /* we're going to determine the selected items from the list itself, so reset this one */
+ selected = NULL;
+
+ for(t=head; t; t=t->next) {
+ /* not visible? not selected! */
+ if(ISHIDDEN(t))
+ t->flags &= ~FF_BSEL;
+ else {
+ /* visible and selected? make sure only one item is selected */
+ if(t->flags & FF_BSEL) {
+ if(!selected)
+ selected = t;
+ else
+ t->flags &= ~FF_BSEL;
+ }
+ }
+
+ /* update dirlist_(maxs|maxa) */
+ if(t->size > dirlist_maxs)
+ dirlist_maxs = t->size;
+ if(t->asize > dirlist_maxa)
+ dirlist_maxa = t->asize;
+ }
+
+ /* no selected items found after one pass? select the first visible item */
+ if(!selected) {
+ selected = dirlist_next(NULL);
+ selected->flags |= FF_BSEL;
+ }
+}
+
+
+void dirlist_open(struct dir *d) {
+ /* set the head of the list */
+ head_real = head = d == NULL ? NULL : d->parent == NULL ? d->sub : d->parent->sub;
+
+ /* reset internal status */
+ dirlist_maxs = dirlist_maxa = 0;
+
+ /* stop if this is not a directory list we can work with */
+ if(head == NULL) {
+ dirlist_parent = NULL;
+ return;
+ }
+
+ /* sort the dir listing */
+ head_real = head = dirlist_sort(head);
+
+ /* set the reference to the parent dir */
+ if(head->parent->parent) {
+ dirlist_parent = &dirlist_parent_alloc;
+ dirlist_parent->name = "..";
+ dirlist_parent->next = head;
+ dirlist_parent->parent = head->parent;
+ dirlist_parent->sub = head->parent;
+ head = dirlist_parent;
+ } else
+ dirlist_parent = NULL;
+
+ dirlist_fixup();
+}
+
+
+struct dir *dirlist_next(struct dir *d) {
+ if(!head)
+ return NULL;
+ if(!d) {
+ if(!ISHIDDEN(head))
+ return head;
+ else
+ d = head;
+ }
+ while((d = d->next)) {
+ if(!ISHIDDEN(d))
+ return d;
+ }
+ 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;
+
+ /* i == 0? return the selected item */
+ if(!i)
+ return selected;
+
+ /* positive number? simply move forward */
+ while(i > 0) {
+ d = dirlist_next(t);
+ if(!d)
+ return t;
+ t = d;
+ if(!--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;
+}
+
+
+void dirlist_select(struct dir *d) {
+ if(!head || ISHIDDEN(d) || d->parent != head->parent)
+ return;
+
+ selected->flags &= ~FF_BSEL;
+ selected = d;
+ selected->flags |= FF_BSEL;
+}
+
+
+void dirlist_set_sort(int col, int desc, int df) {
+ /* update config */
+ if(col != DL_NOCHANGE)
+ dirlist_sort_col = col;
+ if(desc != DL_NOCHANGE)
+ dirlist_sort_desc = desc;
+ if(df != DL_NOCHANGE)
+ dirlist_sort_df = df;
+
+ /* sort the list (excluding the parent, which is always on top) */
+ head_real = dirlist_sort(head_real);
+ if(dirlist_parent)
+ dirlist_parent->next = head_real;
+ else
+ head = head_real;
+}
+
+
+void dirlist_set_hidden(int hidden) {
+ dirlist_hidden = hidden;
+ dirlist_fixup();
+}
+
diff --git a/src/dirlist.h b/src/dirlist.h
new file mode 100644
index 0000000..f3e7c58
--- /dev/null
+++ b/src/dirlist.h
@@ -0,0 +1,78 @@
+/* ncdu - NCurses Disk Usage
+
+ Copyright (c) 2007-2010 Yoran Heling
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+/* Note: all functions below include a 'reference to parent dir' node at the
+ * top of the list. */
+
+#ifndef _dirlist_h
+#define _dirlist_h
+
+#include "global.h"
+
+
+#define DL_NOCHANGE -1
+#define DL_COL_NAME 0
+#define DL_COL_SIZE 1
+#define DL_COL_ASIZE 2
+
+
+void dirlist_open(struct dir *);
+
+/* Get the next non-hidden item,
+ * NULL = get first non-hidden item */
+struct dir *dirlist_next(struct dir *);
+
+/* Get the struct dir item relative to the selected item, or the item nearest to the requested item
+ * i = 0 get selected item
+ * hidden items aren't considered */
+struct dir *dirlist_get(int i);
+
+/* Set selected dir (must be in the currently opened directory, obviously) */
+void dirlist_select(struct dir *);
+
+/* Change sort column (arguments should have a NO_CHANGE option) */
+void dirlist_set_sort(int column, int desc, int df);
+
+/* Set the hidden thingy */
+void dirlist_set_hidden(int hidden);
+
+
+/* DO NOT WRITE TO ANY OF THE BELOW VARIABLES FROM OUTSIDE OF dirlist.c! */
+
+/* The 'reference to parent dir' */
+extern struct dir *dirlist_parent;
+
+/* current sorting configuration (set with dirlist_set_sort()) */
+extern int dirlist_sort_desc, dirlist_sort_col, dirlist_sort_df;
+
+/* set with dirlist_set_hidden() */
+extern int dirlist_hidden;
+
+/* maximum size of an item in the opened dir */
+extern off_t dirlist_maxs, dirlist_maxa;
+
+
+#endif
+
diff --git a/src/global.h b/src/global.h
index 0ca5d43..66f0107 100644
--- a/src/global.h
+++ b/src/global.h
@@ -78,5 +78,6 @@ int input_handle(int);
#include "browser.h"
#include "help.h"
#include "path.h"
+#include "dirlist.h"
#endif