Rewrote calc.c in the new style & framework

ncdu is currently pretty much in a non-working state, but things will
get fixed eventually after porting the other source files to the new
framework.
This commit is contained in:
Yorhel 2009-04-10 18:16:33 +02:00
parent 02705d2c7f
commit f392bf3ee1
4 changed files with 289 additions and 252 deletions

View file

@ -428,12 +428,12 @@ void showBrowser(void) {
} }
break; break;
/* refresh */ /* refresh *
case 'r': case 'r':
hideinfo; hideinfo;
drawBrowser(0); drawBrowser(0);
if((n = showCalc(getpath(bcur, tmp))) != NULL) { if((n = showCalc(getpath(bcur, tmp))) != NULL) {
/* free current items */ * free current items *
d = bcur; d = bcur;
bcur = bcur->parent; bcur = bcur->parent;
while(d != NULL) { while(d != NULL) {
@ -442,7 +442,7 @@ void showBrowser(void) {
freedir(t); freedir(t);
} }
/* update parent dir */ * update parent dir *
bcur->sub = n->sub; bcur->sub = n->sub;
bcur->items = n->items; bcur->items = n->items;
bcur->size = n->size; bcur->size = n->size;
@ -450,7 +450,7 @@ void showBrowser(void) {
for(t = bcur->sub; t != NULL; t = t->next) for(t = bcur->sub; t != NULL; t = t->next)
t->parent = bcur; t->parent = bcur;
/* update sizes of parent dirs */ * update sizes of parent dirs *
for(t = bcur; (t = t->parent) != NULL; ) { for(t = bcur; (t = t->parent) != NULL; ) {
t->size += bcur->size; t->size += bcur->size;
t->asize += bcur->asize; t->asize += bcur->asize;
@ -462,6 +462,7 @@ void showBrowser(void) {
free(n); free(n);
} }
break; break;
*/
/* and other stuff */ /* and other stuff */
case KEY_RESIZE: case KEY_RESIZE:

View file

@ -1,5 +1,5 @@
/* ncdu - NCurses Disk Usage /* ncdu - NCurses Disk Usage
Copyright (c) 2007-2009 Yoran Heling Copyright (c) 2007-2009 Yoran Heling
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
@ -9,10 +9,10 @@
distribute, sublicense, and/or sell copies of the Software, and to distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to permit persons to whom the Software is furnished to do so, subject to
the following conditions: the following conditions:
The above copyright notice and this permission notice shall be included The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software. in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@ -26,18 +26,6 @@
#include "ncdu.h" #include "ncdu.h"
/* parent dir we are calculating */
struct dir *parent;
/* current device we are on */
dev_t curdev;
/* path of the last dir we couldn't read */
char lasterr[PATH_MAX];
/* and for the animation... */
int anpos;
char antext[15] = "Calculating...";
suseconds_t lastupdate;
/* My own implementation of realpath() /* My own implementation of realpath()
- assumes that *every* possible path fits in PATH_MAX bytes - assumes that *every* possible path fits in PATH_MAX bytes
@ -54,7 +42,7 @@ char *rpath(const char *from, char *to) {
app[0] = 0; app[0] = 0;
loop: loop:
/* not an absolute path, add current directory */ /* not an absolute path, add current directory */
if(cur[0] != '/') { if(cur[0] != '/') {
if(!(cwd[0] == '/' && cwd[1] == 0)) if(!(cwd[0] == '/' && cwd[1] == 0))
strcpy(tmp, cwd); strcpy(tmp, cwd);
@ -67,7 +55,7 @@ char *rpath(const char *from, char *to) {
} else } else
strcpy(tmp, cur); strcpy(tmp, cur);
/* now fix things like '.' and '..' */ /* now fix things like '.' and '..' */
i = j = last = 0; i = j = last = 0;
l = strlen(tmp); l = strlen(tmp);
while(1) { while(1) {
@ -95,23 +83,23 @@ char *rpath(const char *from, char *to) {
} }
to[j++] = tmp[i++]; to[j++] = tmp[i++];
} }
/* remove leading slashes */ /* remove leading slashes */
while(--j > 0) { while(--j > 0) {
if(to[j] != '/') if(to[j] != '/')
break; break;
} }
to[j+1] = 0; to[j+1] = 0;
/* make sure we do have something left in case our path is / */ /* make sure we do have something left in case our path is / */
if(to[0] == 0) { if(to[0] == 0) {
to[0] = '/'; to[0] = '/';
to[1] = 0; to[1] = 0;
} }
/* append 'app' */ /* append 'app' */
if(app[0] != 0) if(app[0] != 0)
strcat(to, app); strcat(to, app);
j = strlen(to); j = strlen(to);
/* check for symlinks */ /* check for symlinks */
for(i=1; i<=j; i++) { for(i=1; i<=j; i++) {
if(to[i] == '/' || to[i] == 0) { if(to[i] == '/' || to[i] == 0) {
strncpy(tmp, to, i); strncpy(tmp, to, i);
@ -140,268 +128,264 @@ char *rpath(const char *from, char *to) {
} }
/* the progress window */ int calc_item(struct dir *par, char *path, char *name) {
static void drawProgress(char *cdir) { char tmp[PATH_MAX];
struct dir *t, *d;
struct stat fs;
if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
return 0;
/* path too long - ignore file */
if(strlen(path)+strlen(name)+1 > PATH_MAX)
return 1;
/* allocate dir and fix references */
d = calloc(sizeof(struct dir), 1);
d->parent = par;
if(par->sub == NULL)
par->sub = d;
else {
for(t=par->sub; t->next!=NULL; t=t->next)
;
t->next = d;
}
d->name = malloc(strlen(name)+1);
strcpy(d->name, name);
#ifdef __CYGWIN__
/* /proc/registry names may contain slashes */
if(strchr(d->name, '/') || strchr(d->name, '\\')) {
d->flags |= FF_ERR;
return 0;
}
#endif
/* lstat */
strcpy(tmp, path);
strcat(tmp, name);
if(lstat(tmp, &fs)) {
d->flags |= FF_ERR;
return 0;
}
/* check for excludes and same filesystem */
if(matchExclude(tmp))
d->flags |= FF_EXL;
if(sflags & SF_SMFS && pstate.calc.curdev != fs.st_dev)
d->flags |= FF_OTHFS;
/* determine type of this item */
if(S_ISREG(fs.st_mode))
d->flags |= FF_FILE;
else if(S_ISDIR(fs.st_mode))
d->flags |= FF_DIR;
/* update parent dirs */
if(!(d->flags & FF_EXL))
for(t=d; t!=NULL; t=t->parent)
t->items++;
/* count the size */
if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
d->size = fs.st_blocks * S_BLKSIZE;
d->asize = fs.st_size;
for(t=d; t!=NULL; t=t->parent) {
t->size += d->size;
t->asize += d->asize;
}
}
return 0;
}
/* recursively walk through the directory tree */
int calc_dir(struct dir *dest, char *path) {
struct dir *t;
DIR *dir;
struct dirent *dr;
char tmp[PATH_MAX];
int len;
if(input_handle(1))
return 1;
/* open directory */
if((dir = opendir(path)) == NULL) {
strcpy(pstate.calc.lasterr, path);
dest->flags |= FF_ERR;
t = dest;
while((t = t->parent) != NULL)
t->flags |= FF_SERR;
return 0;
}
/* add leading slash */
len = strlen(path);
if(path[len-1] != '/') {
path[len] = '/';
path[++len] = '\0';
}
/* read directory */
while((dr = readdir(dir)) != NULL) {
if(calc_item(dest, path, dr->d_name))
dest->flags |= FF_ERR;
if(input_handle(1))
return 1;
errno = 0;
}
if(errno) {
if(dest->flags & FF_SERR)
dest->flags -= FF_SERR;
dest->flags |= FF_ERR;
}
closedir(dir);
/* error occured while reading this dir, update parent dirs */
for(t=dest->sub; t!=NULL; t=t->next)
if(t->flags & FF_ERR || t->flags & FF_SERR)
dest->flags |= FF_SERR;
if(dest->flags & FF_ERR || dest->flags & FF_SERR) {
for(t = dest; (t = t->parent) != NULL; )
t->flags |= FF_SERR;
}
/* calculate subdirectories */
for(t=dest->sub; t!=NULL; t=t->next)
if(t->flags & FF_DIR && !(t->flags & FF_EXL || t->flags & FF_OTHFS)) {
strcpy(tmp, path);
strcat(tmp, t->name);
if(calc_dir(t, tmp))
return 1;
}
return 0;
}
void calc_draw_progress() {
static char antext[15] = "Calculating...";
char ani[15]; char ani[15];
int i; int i;
nccreate(10, 60, dat == NULL ? "Calculating..." : "Recalculating..."); nccreate(10, 60, dat == NULL ? "Calculating..." : "Recalculating...");
ncprint(2, 2, "Total items: %-8d size: %s", ncprint(2, 2, "Total items: %-8d size: %s",
parent->items, cropsize(parent->size)); pstate.calc.parent->items, cropsize(pstate.calc.parent->size));
ncprint(3, 2, "Current dir: %s", cropdir(cdir, 43)); ncprint(3, 2, "Current dir: %s", cropdir(pstate.calc.cur, 43));
ncaddstr(8, 43, "Press q to quit"); ncaddstr(8, 43, "Press q to quit");
/* show warning if we couldn't open a dir */ /* show warning if we couldn't open a dir */
if(lasterr[0] != '\0') { if(pstate.calc.lasterr[0] != '\0') {
attron(A_BOLD); attron(A_BOLD);
ncaddstr(5, 2, "Warning:"); ncaddstr(5, 2, "Warning:");
attroff(A_BOLD); attroff(A_BOLD);
ncprint(5, 11, "could not open %-32s", cropdir(lasterr, 32)); ncprint(5, 11, "could not open %-32s", cropdir(pstate.calc.lasterr, 32));
ncaddstr(6, 3, "some directory sizes may not be correct"); ncaddstr(6, 3, "some directory sizes may not be correct");
} }
/* animation - but only if the screen refreshes more than or once every second */ /* animation - but only if the screen refreshes more than or once every second */
if(sdelay <= 1000) { if(sdelay <= 1000) {
if(++anpos == 28) anpos = 0; if(++pstate.calc.anpos == 28)
strcpy(ani, " "); pstate.calc.anpos = 0;
if(anpos < 14) strcpy(ani, " ");
for(i=0; i<=anpos; i++) if(pstate.calc.anpos < 14)
ani[i] = antext[i]; for(i=0; i<=pstate.calc.anpos; i++)
else ani[i] = antext[i];
for(i=13; i>anpos-14; i--) else
ani[i] = antext[i]; for(i=13; i>pstate.calc.anpos-14; i--)
ani[i] = antext[i];
} else } else
strcpy(ani, antext); strcpy(ani, antext);
ncaddstr(8, 3, ani); ncaddstr(8, 3, ani);
refresh();
} }
/* show error if can't open parent dir */ void calc_draw_error(char *cur, char *msg) {
static void drawError(char *dir) { nccreate(7, 60, "Error!");
nccreate(10, 60, "Error!");
attron(A_BOLD); attron(A_BOLD);
ncaddstr(5, 2, "Error:"); ncaddstr(2, 2, "Error:");
attroff(A_BOLD); attroff(A_BOLD);
ncprint(5, 9, "could not open %s", cropdir(dir, 34)); ncprint(2, 9, "could not open %s", cropdir(cur, 34));
ncaddstr(6, 3, "press any key to continue..."); ncprint(3, 4, "%s", cropdir(msg, 52));
ncaddstr(5, 30, "press any key to continue...");
refresh();
} }
/* checks for input and calls drawProgress */ int calc_draw() {
int updateProgress(char *path) {
struct timeval tv; struct timeval tv;
int ch;
/* check for input or screen resizes */ if(pstate.calc.err) {
nodelay(stdscr, 1); calc_draw_error(pstate.calc.cur, pstate.calc.errmsg);
while((ch = getch()) != ERR) { return 0;
if(ch == 'q')
return(0);
if(ch == KEY_RESIZE) {
ncresize();
if(dat != NULL)
drawBrowser(0);
drawProgress(path);
}
} }
nodelay(stdscr, 0);
/* should we really draw the screen again? */
/* don't update the screen with shorter intervals than sdelay */
gettimeofday(&tv, (void *)NULL); gettimeofday(&tv, (void *)NULL);
tv.tv_usec = (1000*(tv.tv_sec % 1000) + (tv.tv_usec / 1000)) / sdelay; tv.tv_usec = (1000*(tv.tv_sec % 1000) + (tv.tv_usec / 1000)) / sdelay;
if(lastupdate != tv.tv_usec) { if(pstate.calc.lastupdate != tv.tv_usec) {
drawProgress(path); calc_draw_progress();
lastupdate = tv.tv_usec; pstate.calc.lastupdate = tv.tv_usec;
return 0;
} }
return(1); return 1;
} }
/* recursive */ int calc_key(int ch) {
int calcDir(struct dir *dest, char *path) { if(pstate.calc.err)
struct dir *d, *t, *last; return 1;
struct stat fs; if(ch == 'q')
DIR *dir; return 1;
struct dirent *dr; return 0;
char *f, tmp[PATH_MAX];
int len, derr = 0, serr = 0;
if(!updateProgress(path))
return(0);
/* open directory */
if((dir = opendir(path)) == NULL) {
strcpy(lasterr, path);
dest->flags |= FF_ERR;
t = dest;
while((t = t->parent) != NULL)
t->flags |= FF_SERR;
return(1);
}
len = strlen(path);
/* add leading slash */
if(path[len-1] != '/') {
path[len] = '/';
path[++len] = '\0';
}
/* read directory */
last = NULL;
while((dr = readdir(dir)) != NULL) {
f = dr->d_name;
if(f[0] == '.' && (f[1] == '\0' || (f[1] == '.' && f[2] == '\0')))
continue;
/* path too long - ignore file */
if(len+strlen(f)+1 > PATH_MAX) {
derr = 1;
errno = 0;
continue;
}
/* allocate dir and fix references */
d = calloc(sizeof(struct dir), 1);
d->parent = dest;
if(dest->sub == NULL)
dest->sub = d;
if(last != NULL)
last->next = d;
last = d;
/* set d->name */
d->name = malloc(strlen(f)+1);
strcpy(d->name, f);
#ifdef __CYGWIN__
/* /proc/registry names may contain slashes */
if(strchr(d->name, '/') || strchr(d->name, '\\')) {
serr = 1;
errno = 0;
d->flags |= FF_ERR;
continue;
}
#endif
/* get full path */
strcpy(tmp, path);
strcat(tmp, f);
/* lstat */
if(lstat(tmp, &fs)) {
serr = 1;
errno = 0;
d->flags |= FF_ERR;
continue;
}
/* check for excludes and same filesystem */
if(matchExclude(tmp))
d->flags |= FF_EXL;
if(sflags & SF_SMFS && curdev != fs.st_dev)
d->flags |= FF_OTHFS;
/* determine type of this item */
if(S_ISREG(fs.st_mode))
d->flags |= FF_FILE;
else if(S_ISDIR(fs.st_mode))
d->flags |= FF_DIR;
/* update parent dirs */
if(!(d->flags & FF_EXL))
for(t = dest; t != NULL; t = t->parent)
t->items++;
/* count the size */
if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
d->size = fs.st_blocks * S_BLKSIZE;
d->asize = fs.st_size;
for(t = dest; t != NULL; t = t->parent) {
t->size += d->size;
t->asize += d->asize;
}
}
/* show status */
if(!updateProgress(tmp))
return(0);
errno = 0;
}
derr = derr || errno;
closedir(dir);
/* error occured while reading this dir, update parent dirs */
if(derr || serr) {
dest->flags |= derr ? FF_ERR : FF_SERR;
for(t = dest; (t = t->parent) != NULL; )
t->flags |= FF_SERR;
}
if(dest->sub) {
/* calculate subdirectories */
for(d = dest->sub; d != NULL; d = d->next)
if(d->flags & FF_DIR && !(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
strcpy(tmp, path);
strcat(tmp, d->name);
if(!calcDir(d, tmp))
return(0);
}
}
return(1);
} }
struct dir *showCalc(char *path) { void calc_process() {
char tmp[PATH_MAX]; char tmp[PATH_MAX];
struct stat fs; struct stat fs;
struct dir *t; struct dir *t;
/* init/reset global vars */ /* init/reset global vars */
*lasterr = '\0'; pstate.calc.err = 0;
anpos = 0; pstate.calc.lastupdate = 999;
lastupdate = 999; pstate.calc.lasterr[0] = 0;
memset(tmp, 0, PATH_MAX); pstate.calc.anpos = 0;
/* init parent dir */ /* check root directory */
if(rpath(path, tmp) == NULL || lstat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) { if(rpath(pstate.calc.cur, tmp) == NULL || lstat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
do { pstate.calc.err = 1;
ncresize(); strcpy(pstate.calc.errmsg, "Directory not found");
if(dat != NULL) goto fail;
drawBrowser(0);
drawError(path);
} while (getch() == KEY_RESIZE);
return(NULL);
}
parent = calloc(sizeof(struct dir), 1);
parent->size = fs.st_blocks * S_BLKSIZE;
parent->asize = fs.st_size;
parent->flags |= FF_DIR;
curdev = fs.st_dev;
parent->name = malloc(strlen(tmp)+1);
strcpy(parent->name, tmp);
/* start calculating */
if(!calcDir(parent, tmp)) {
freedir(parent);
return(NULL);
} }
return(parent); /* initialize parent dir */
t = (struct dir *) calloc(1, sizeof(struct dir));
t->size = fs.st_blocks * S_BLKSIZE;
t->asize = fs.st_size;
t->flags |= FF_DIR;
t->name = (char *) malloc(strlen(tmp)+1);
strcpy(t->name, tmp);
pstate.calc.parent = t;
pstate.calc.curdev = fs.st_dev;
/* start calculating */
if(!calc_dir(pstate.calc.parent, tmp) && !pstate.calc.err) {
pstate.st = ST_BROWSE;
return;
}
/* something went wrong... */
freedir(pstate.calc.parent);
fail:
while(pstate.calc.err && !input_handle(0))
;
pstate.st = dat != NULL ? ST_BROWSE : ST_QUIT;
return;
} }

View file

@ -28,14 +28,44 @@
/* check ncdu.h what these are for */ /* check ncdu.h what these are for */
struct dir *dat; struct dir *dat;
int winrows, wincols; int winrows, wincols;
char sdir[PATH_MAX];
int sflags, bflags, sdelay, bgraph; int sflags, bflags, sdelay, bgraph;
int subwinc, subwinr; int subwinc, subwinr;
struct state pstate; struct state pstate;
void screen_draw() {
int n = 1;
switch(pstate.st) {
case ST_CALC: n = calc_draw();
}
if(!n)
refresh();
}
int input_handle(int wait) {
int ch;
nodelay(stdscr, wait);
screen_draw();
while((ch = getch()) != ERR) {
if(ch == KEY_RESIZE) {
ncresize();
screen_draw();
continue;
}
switch(pstate.st) {
case ST_CALC: return calc_key(ch);
}
}
return 0;
}
/* parse command line */ /* parse command line */
void argv_parse(int argc, char **argv, char *dir) { void argv_parse(int argc, char **argv, char *dir) {
int i, j; int i, j, len;
/* load defaults */ /* load defaults */
memset(dir, 0, PATH_MAX); memset(dir, 0, PATH_MAX);
@ -63,7 +93,8 @@ void argv_parse(int argc, char **argv, char *dir) {
continue; continue;
} }
/* small flags */ /* small flags */
for(j=1; j < strlen(argv[i]); j++) len = strlen(argv[i]);
for(j=1; j<len; j++)
switch(argv[i][j]) { switch(argv[i][j]) {
case 'x': sflags |= SF_SMFS; break; case 'x': sflags |= SF_SMFS; break;
case 'q': sdelay = 2000; break; case 'q': sdelay = 2000; break;
@ -85,12 +116,12 @@ void argv_parse(int argc, char **argv, char *dir) {
exit(1); exit(1);
} }
} else { } else {
dir[PATH_MAX - 1] = 0;
strncpy(dir, argv[i], PATH_MAX); strncpy(dir, argv[i], PATH_MAX);
if(dir[PATH_MAX - 1] != 0) { if(dir[PATH_MAX - 1] != 0) {
printf("Error: path length exceeds PATH_MAX\n"); printf("Error: path length exceeds PATH_MAX\n");
exit(1); exit(1);
} }
dir[PATH_MAX - 1] = 0;
} }
} }
} }
@ -100,7 +131,8 @@ void argv_parse(int argc, char **argv, char *dir) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
dat = NULL; dat = NULL;
argv_parse(argc, argv, pstate.calc.root); memset((void *)&pstate, 0, sizeof(struct state));
argv_parse(argc, argv, pstate.calc.cur);
pstate.st = ST_CALC; pstate.st = ST_CALC;
initscr(); initscr();
@ -110,8 +142,16 @@ int main(int argc, char **argv) {
keypad(stdscr, TRUE); keypad(stdscr, TRUE);
ncresize(); ncresize();
while(pstate.st != ST_QUIT) {
if(pstate.st == ST_CALC)
calc_process();
/*else
wait_for_input() */
}
/*
if((dat = showCalc(pstate.calc.root)) != NULL) if((dat = showCalc(pstate.calc.root)) != NULL)
showBrowser(); showBrowser();*/
erase(); erase();
refresh(); refresh();

View file

@ -121,6 +121,7 @@
#define ST_BROWSE 1 #define ST_BROWSE 1
#define ST_DEL 2 #define ST_DEL 2
#define ST_HELP 3 #define ST_HELP 3
#define ST_QUIT 4
@ -129,7 +130,7 @@
*/ */
struct dir { struct dir {
struct dir *parent, *next, *sub; struct dir *parent, *next, *sub;
unsigned char *name; char *name;
off_t size, asize; off_t size, asize;
unsigned long items; unsigned long items;
unsigned char flags; unsigned char flags;
@ -138,7 +139,14 @@ struct dir {
struct state { struct state {
int st; /* SC_x */ int st; /* SC_x */
struct { struct {
char root[PATH_MAX]; char err;
char cur[PATH_MAX];
char lasterr[PATH_MAX];
char errmsg[128];
struct dir *parent;
dev_t curdev;
suseconds_t lastupdate;
int anpos;
} calc; } calc;
/* TODO: information structs for the other states */ /* TODO: information structs for the other states */
}; };
@ -166,6 +174,8 @@ extern struct state pstate;
/* /*
* G L O B A L F U N C T I O N S * G L O B A L F U N C T I O N S
*/ */
/* main.c */
int input_handle(int);
/* util.c */ /* util.c */
char *cropdir(const char *, int); char *cropdir(const char *, int);
char *cropsize(const off_t); char *cropsize(const off_t);
@ -176,7 +186,9 @@ void ncprint(int, int, char *, ...);
struct dir *freedir(struct dir *); struct dir *freedir(struct dir *);
char *getpath(struct dir *, char *); char *getpath(struct dir *, char *);
/* calc.c */ /* calc.c */
struct dir *showCalc(char *); void calc_process(void);
int calc_key(int);
int calc_draw(void);
/* browser.c */ /* browser.c */
void drawBrowser(int); void drawBrowser(int);
void showBrowser(void); void showBrowser(void);