2007-07-20 15:15:46 +04:00
|
|
|
/* ncdu - NCurses Disk Usage
|
|
|
|
|
|
|
|
Copyright (c) 2007 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 "ncdu.h"
|
|
|
|
|
|
|
|
struct dir *bcur;
|
|
|
|
int helpwin;
|
|
|
|
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
struct dir * removedir(struct dir *dr) {
|
|
|
|
return(dr);
|
2007-07-20 15:15:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int cmp(struct dir *x, struct dir *y) {
|
|
|
|
struct dir *a, *b;
|
|
|
|
int r = 0;
|
2007-07-24 11:58:22 +04:00
|
|
|
|
|
|
|
if(y->flags & FF_PAR)
|
|
|
|
return(1);
|
|
|
|
if(x->flags & FF_PAR)
|
|
|
|
return(-1);
|
|
|
|
|
2007-07-20 15:15:46 +04:00
|
|
|
if(bflags & BF_DESC) {
|
|
|
|
a = y; b = x;
|
|
|
|
} else {
|
|
|
|
b = y; a = x;
|
|
|
|
}
|
|
|
|
if(!(bflags & BF_NDIRF) && y->flags & FF_DIR && !(x->flags & FF_DIR))
|
|
|
|
r = 1;
|
|
|
|
else if(!(bflags & BF_NDIRF) && !(y->flags & FF_DIR) && x->flags & FF_DIR)
|
|
|
|
r = -1;
|
|
|
|
else if(bflags & BF_NAME)
|
|
|
|
r = strcmp(a->name, b->name);
|
|
|
|
else if(bflags & BF_FILES)
|
|
|
|
r = (a->files - b->files);
|
|
|
|
if(r == 0)
|
|
|
|
r = a->size > b->size ? 1 : (a->size == b->size ? 0 : -1);
|
|
|
|
return(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mergesort algorithm, many thanks to
|
|
|
|
http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
|
|
|
*/
|
|
|
|
struct dir *sortFiles(struct dir *list) {
|
|
|
|
struct dir *p, *q, *e, *tail;
|
|
|
|
int insize, nmerges, psize, qsize, i;
|
|
|
|
|
|
|
|
while(list->prev != NULL)
|
|
|
|
list = list->prev;
|
|
|
|
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(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;
|
|
|
|
e->prev = tail;
|
|
|
|
tail = e;
|
|
|
|
}
|
|
|
|
p = q;
|
|
|
|
}
|
|
|
|
tail->next = NULL;
|
|
|
|
if(nmerges <= 1)
|
|
|
|
return list;
|
|
|
|
insize *= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char graphdat[11];
|
|
|
|
char *graph(off_t max, off_t size) {
|
|
|
|
int i, c = (int) (((float) size / (float) max) * 10.0f);
|
|
|
|
for(i=0; i<10; i++)
|
|
|
|
graphdat[i] = i < c ? '#' : ' ';
|
|
|
|
graphdat[10] = '\0';
|
|
|
|
return graphdat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
#define exlhid(x) if(bflags & BF_HIDE && !(x->flags & FF_PAR) && x->name[0] == '.') { i--; continue; }
|
|
|
|
|
|
|
|
void drawBrowser(int change) {
|
|
|
|
struct dir *n;
|
|
|
|
char tmp[PATH_MAX], ct, dt;
|
|
|
|
int selected, i, o;
|
2007-07-20 15:15:46 +04:00
|
|
|
off_t max;
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
erase();
|
|
|
|
|
|
|
|
/* exit if there are no items to display */
|
2007-07-20 15:15:46 +04:00
|
|
|
if(bcur->parent == NULL) {
|
|
|
|
if(bcur->sub == NULL) {
|
|
|
|
erase();
|
|
|
|
refresh();
|
|
|
|
endwin();
|
|
|
|
printf("No items to display...\n");
|
|
|
|
exit(0);
|
|
|
|
} else
|
|
|
|
bcur = bcur->sub;
|
|
|
|
}
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
/* create header and status bar */
|
2007-07-20 15:15:46 +04:00
|
|
|
attron(A_REVERSE);
|
2007-07-24 11:58:22 +04:00
|
|
|
mvhline(0, 0, ' ', wincols);
|
|
|
|
mvhline(winrows-1, 0, ' ', wincols);
|
2007-07-20 15:15:46 +04:00
|
|
|
mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ? for help", PACKAGE_NAME, PACKAGE_VERSION);
|
2007-07-24 11:58:22 +04:00
|
|
|
|
2007-07-20 15:15:46 +04:00
|
|
|
mvprintw(winrows-1, 0, " Total size: %s Files: %-6d Dirs: %-6d",
|
|
|
|
cropsize(bcur->parent->size), bcur->parent->files, bcur->parent->dirs);
|
|
|
|
attroff(A_REVERSE);
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
mvhline(1, 0, '-', wincols);
|
|
|
|
mvaddstr(1, 3, cropdir(getpath(bcur, tmp), wincols-5));
|
|
|
|
|
|
|
|
/* make sure we have the first item, and the items are in correct order */
|
2007-07-20 15:15:46 +04:00
|
|
|
bcur = sortFiles(bcur);
|
2007-07-24 11:58:22 +04:00
|
|
|
while(bcur->prev != NULL)
|
|
|
|
bcur = bcur->prev;
|
|
|
|
|
|
|
|
/* get maximum size and selected item */
|
|
|
|
for(n = bcur, selected = i = 0; n != NULL; n = n->next, i++) {
|
|
|
|
exlhid(n)
|
|
|
|
if(n->flags & FF_BSEL)
|
|
|
|
selected = i;
|
|
|
|
if(n->size > max)
|
|
|
|
max = n->size;
|
2007-07-20 15:15:46 +04:00
|
|
|
}
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
if(selected+change < 0)
|
|
|
|
change -= selected+change;
|
|
|
|
if(selected+change > --i)
|
|
|
|
change -= (selected+change)-i;
|
|
|
|
for(n = bcur, i = 0; n != NULL; n = n->next, i++) {
|
|
|
|
exlhid(n)
|
|
|
|
if(i == selected && n->flags & FF_BSEL)
|
|
|
|
n->flags -= FF_BSEL;
|
|
|
|
if(i == selected+change)
|
|
|
|
n->flags |= FF_BSEL;
|
|
|
|
}
|
|
|
|
selected += change;
|
2007-07-20 15:15:46 +04:00
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
/* determine the listing format */
|
2007-07-20 15:15:46 +04:00
|
|
|
switch(bgraph) {
|
|
|
|
case 0:
|
|
|
|
sprintf(tmp, "%%c %%7s %%c%%-%ds", wincols-12);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
sprintf(tmp, "%%c %%7s [%%10s] %%c%%-%ds", wincols-24);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sprintf(tmp, "%%c %%7s [%%4.1f%%%%] %%c%%-%ds", wincols-19);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
sprintf(tmp, "%%c %%7s [%%4.1f%%%% %%10s] %%c%%-%ds", wincols-30);
|
|
|
|
}
|
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
/* determine start position */
|
|
|
|
for(n = bcur, i = 0; n != NULL; n = n->next, i++) {
|
|
|
|
exlhid(n)
|
|
|
|
if(i == (selected / (winrows-3)) * (winrows-3))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
selected -= i;
|
|
|
|
|
|
|
|
/* print the list to the screen */
|
|
|
|
for(i=0; n != NULL && i < winrows-3; n = n->next, i++) {
|
|
|
|
exlhid(n)
|
|
|
|
if(i == selected)
|
|
|
|
attron(A_REVERSE);
|
|
|
|
|
|
|
|
/* reference to parent dir has a different format */
|
|
|
|
if(n->flags & FF_PAR) {
|
|
|
|
mvhline(i+2, 0, ' ', wincols);
|
|
|
|
o = bgraph == 0 ? 11 :
|
|
|
|
bgraph == 1 ? 23 :
|
|
|
|
bgraph == 2 ? 18 :
|
|
|
|
29 ;
|
|
|
|
mvaddstr(i+2, o, "/..");
|
|
|
|
if(i == selected)
|
|
|
|
attroff(A_REVERSE);
|
2007-07-20 15:15:46 +04:00
|
|
|
continue;
|
|
|
|
}
|
2007-07-24 11:58:22 +04:00
|
|
|
|
|
|
|
/* determine indication character */
|
|
|
|
ct = n->flags & FF_EXL ? '<' :
|
|
|
|
n->flags & FF_ERR ? '!' :
|
|
|
|
n->flags & FF_SERR ? '.' :
|
|
|
|
n->flags & FF_OTHFS ? '>' :
|
|
|
|
n->flags & FF_OTHER ? '@' :
|
|
|
|
n->flags & FF_DIR
|
|
|
|
&& n->sub == NULL ? 'e' :
|
2007-07-21 17:55:51 +04:00
|
|
|
' ' ;
|
2007-07-24 11:58:22 +04:00
|
|
|
dt = n->flags & FF_DIR ? '/' : ' ';
|
|
|
|
|
|
|
|
/* format and add item to the list */
|
2007-07-20 15:15:46 +04:00
|
|
|
switch(bgraph) {
|
|
|
|
case 0:
|
2007-07-24 11:58:22 +04:00
|
|
|
mvprintw(i+2, 0, tmp, ct, cropsize(n->size),
|
|
|
|
dt, cropdir(n->name, wincols-12)
|
|
|
|
);
|
2007-07-20 15:15:46 +04:00
|
|
|
break;
|
|
|
|
case 1:
|
2007-07-24 11:58:22 +04:00
|
|
|
mvprintw(i+2, 0, tmp, ct, cropsize(n->size),
|
|
|
|
graph(max, n->size),
|
|
|
|
dt, cropdir(n->name, wincols-24)
|
|
|
|
);
|
2007-07-20 15:15:46 +04:00
|
|
|
break;
|
|
|
|
case 2:
|
2007-07-24 11:58:22 +04:00
|
|
|
mvprintw(i+2, 0, tmp, ct, cropsize(n->size),
|
|
|
|
((float) n->size / (float) n->parent->size) * 100.0f,
|
|
|
|
dt, cropdir(n->name, wincols-19)
|
|
|
|
);
|
2007-07-20 15:15:46 +04:00
|
|
|
break;
|
|
|
|
case 3:
|
2007-07-24 11:58:22 +04:00
|
|
|
mvprintw(i+2, 0, tmp, ct, cropsize(n->size),
|
|
|
|
((float) n->size / (float) n->parent->size) * 100.0f, graph(max, n->size),
|
|
|
|
dt, cropdir(n->name, wincols-30)
|
|
|
|
);
|
2007-07-20 15:15:46 +04:00
|
|
|
}
|
2007-07-24 11:58:22 +04:00
|
|
|
|
|
|
|
if(i == selected)
|
|
|
|
attroff(A_REVERSE);
|
2007-07-20 15:15:46 +04:00
|
|
|
}
|
2007-07-24 11:58:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct dir * selected(void) {
|
|
|
|
struct dir *n = bcur;
|
|
|
|
do {
|
|
|
|
if(n->flags & FF_BSEL)
|
|
|
|
return n;
|
|
|
|
} while((n = n->next) != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define toggle(x,y) if(x & y) x -=y; else x |= y
|
|
|
|
|
|
|
|
void showBrowser(void) {
|
|
|
|
int ch, change;
|
|
|
|
struct dir *n;
|
2007-07-20 15:15:46 +04:00
|
|
|
|
2007-07-24 11:58:22 +04:00
|
|
|
bcur = dat.sub;
|
|
|
|
bgraph = 1;
|
|
|
|
nodelay(stdscr, 0);
|
2007-07-24 12:25:44 +04:00
|
|
|
bflags = BF_SIZE | BF_DESC | BF_NDIRF;
|
2007-07-24 11:58:22 +04:00
|
|
|
|
|
|
|
drawBrowser(0);
|
2007-07-20 15:15:46 +04:00
|
|
|
refresh();
|
2007-07-24 11:58:22 +04:00
|
|
|
|
2007-07-20 15:15:46 +04:00
|
|
|
while((ch = getch())) {
|
2007-07-24 11:58:22 +04:00
|
|
|
change = 0;
|
2007-07-20 15:15:46 +04:00
|
|
|
switch(ch) {
|
2007-07-24 11:58:22 +04:00
|
|
|
/* selecting items */
|
|
|
|
case KEY_UP:
|
|
|
|
change = -1;
|
2007-07-20 15:15:46 +04:00
|
|
|
break;
|
2007-07-24 11:58:22 +04:00
|
|
|
case KEY_DOWN:
|
|
|
|
change = 1;
|
2007-07-20 15:15:46 +04:00
|
|
|
break;
|
2007-07-24 11:58:22 +04:00
|
|
|
case KEY_HOME:
|
|
|
|
change = -16777216;
|
|
|
|
break;
|
|
|
|
case KEY_LL:
|
|
|
|
case KEY_END:
|
|
|
|
change = 16777216;
|
|
|
|
break;
|
|
|
|
case KEY_PPAGE:
|
|
|
|
change = -1*(winrows-3);
|
|
|
|
break;
|
|
|
|
case KEY_NPAGE:
|
|
|
|
change = winrows-3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* sorting items */
|
2007-07-20 15:15:46 +04:00
|
|
|
case 'n':
|
|
|
|
if(bflags & BF_NAME)
|
|
|
|
toggle(bflags, BF_DESC);
|
|
|
|
else
|
|
|
|
bflags = (bflags & BF_HIDE) + (bflags & BF_NDIRF) + BF_NAME;
|
2007-07-24 11:58:22 +04:00
|
|
|
break;
|
2007-07-20 15:15:46 +04:00
|
|
|
case 's':
|
|
|
|
if(bflags & BF_SIZE)
|
|
|
|
toggle(bflags, BF_DESC);
|
|
|
|
else
|
2007-07-24 12:25:44 +04:00
|
|
|
bflags = (bflags & BF_HIDE) + (bflags & BF_NDIRF) + BF_SIZE + BF_DESC;
|
2007-07-24 11:58:22 +04:00
|
|
|
break;
|
2007-07-20 15:15:46 +04:00
|
|
|
case 'p':
|
|
|
|
toggle(sflags, SF_SI);
|
2007-07-24 11:58:22 +04:00
|
|
|
break;
|
2007-07-20 15:15:46 +04:00
|
|
|
case 'h':
|
|
|
|
toggle(bflags, BF_HIDE);
|
2007-07-24 11:58:22 +04:00
|
|
|
break;
|
2007-07-20 15:15:46 +04:00
|
|
|
case 't':
|
|
|
|
toggle(bflags, BF_NDIRF);
|
2007-07-24 11:58:22 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* browsing */
|
|
|
|
case 10:
|
|
|
|
case KEY_RIGHT:
|
|
|
|
n = selected();
|
|
|
|
if(n->flags & FF_PAR)
|
|
|
|
bcur = bcur->parent;
|
|
|
|
else if(n->sub != NULL)
|
|
|
|
bcur = n->sub;
|
|
|
|
break;
|
|
|
|
case KEY_LEFT:
|
|
|
|
if(bcur->parent->parent != NULL) {
|
|
|
|
bcur = bcur->parent;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* and other stuff */
|
|
|
|
case KEY_RESIZE:
|
|
|
|
ncresize();
|
|
|
|
break;
|
2007-07-20 15:15:46 +04:00
|
|
|
case 'g':
|
|
|
|
if(++bgraph > 3) bgraph = 0;
|
2007-07-24 11:58:22 +04:00
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
showHelp();
|
|
|
|
break;
|
2007-07-20 15:15:46 +04:00
|
|
|
case 'd':
|
2007-07-24 11:58:22 +04:00
|
|
|
n = selected();
|
|
|
|
if(!(n->flags & FF_PAR))
|
|
|
|
bcur = showDelete(n);
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
goto endloop;
|
2007-07-20 15:15:46 +04:00
|
|
|
}
|
2007-07-24 11:58:22 +04:00
|
|
|
drawBrowser(change);
|
2007-07-20 15:15:46 +04:00
|
|
|
refresh();
|
|
|
|
}
|
2007-07-24 11:58:22 +04:00
|
|
|
endloop:
|
2007-07-20 15:15:46 +04:00
|
|
|
erase();
|
|
|
|
}
|
|
|
|
|
|
|
|
|