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

@ -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);
/* don't update the screen with shorter intervals than sdelay */ /* should we really draw the screen again? */
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);