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

View file

@ -26,18 +26,6 @@
#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()
- assumes that *every* possible path fits in PATH_MAX bytes
@ -54,7 +42,7 @@ char *rpath(const char *from, char *to) {
app[0] = 0;
loop:
/* not an absolute path, add current directory */
/* not an absolute path, add current directory */
if(cur[0] != '/') {
if(!(cwd[0] == '/' && cwd[1] == 0))
strcpy(tmp, cwd);
@ -67,7 +55,7 @@ char *rpath(const char *from, char *to) {
} else
strcpy(tmp, cur);
/* now fix things like '.' and '..' */
/* now fix things like '.' and '..' */
i = j = last = 0;
l = strlen(tmp);
while(1) {
@ -95,23 +83,23 @@ char *rpath(const char *from, char *to) {
}
to[j++] = tmp[i++];
}
/* remove leading slashes */
/* remove leading slashes */
while(--j > 0) {
if(to[j] != '/')
break;
}
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) {
to[0] = '/';
to[1] = 0;
}
/* append 'app' */
/* append 'app' */
if(app[0] != 0)
strcat(to, app);
j = strlen(to);
/* check for symlinks */
/* check for symlinks */
for(i=1; i<=j; i++) {
if(to[i] == '/' || to[i] == 0) {
strncpy(tmp, to, i);
@ -140,268 +128,264 @@ char *rpath(const char *from, char *to) {
}
/* the progress window */
static void drawProgress(char *cdir) {
int calc_item(struct dir *par, char *path, char *name) {
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];
int i;
nccreate(10, 60, dat == NULL ? "Calculating..." : "Recalculating...");
ncprint(2, 2, "Total items: %-8d size: %s",
parent->items, cropsize(parent->size));
ncprint(3, 2, "Current dir: %s", cropdir(cdir, 43));
pstate.calc.parent->items, cropsize(pstate.calc.parent->size));
ncprint(3, 2, "Current dir: %s", cropdir(pstate.calc.cur, 43));
ncaddstr(8, 43, "Press q to quit");
/* show warning if we couldn't open a dir */
if(lasterr[0] != '\0') {
/* show warning if we couldn't open a dir */
if(pstate.calc.lasterr[0] != '\0') {
attron(A_BOLD);
ncaddstr(5, 2, "Warning:");
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");
}
/* 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(++anpos == 28) anpos = 0;
strcpy(ani, " ");
if(anpos < 14)
for(i=0; i<=anpos; i++)
ani[i] = antext[i];
else
for(i=13; i>anpos-14; i--)
ani[i] = antext[i];
if(++pstate.calc.anpos == 28)
pstate.calc.anpos = 0;
strcpy(ani, " ");
if(pstate.calc.anpos < 14)
for(i=0; i<=pstate.calc.anpos; i++)
ani[i] = antext[i];
else
for(i=13; i>pstate.calc.anpos-14; i--)
ani[i] = antext[i];
} else
strcpy(ani, antext);
ncaddstr(8, 3, ani);
refresh();
}
/* show error if can't open parent dir */
static void drawError(char *dir) {
nccreate(10, 60, "Error!");
void calc_draw_error(char *cur, char *msg) {
nccreate(7, 60, "Error!");
attron(A_BOLD);
ncaddstr(5, 2, "Error:");
ncaddstr(2, 2, "Error:");
attroff(A_BOLD);
ncprint(5, 9, "could not open %s", cropdir(dir, 34));
ncaddstr(6, 3, "press any key to continue...");
refresh();
ncprint(2, 9, "could not open %s", cropdir(cur, 34));
ncprint(3, 4, "%s", cropdir(msg, 52));
ncaddstr(5, 30, "press any key to continue...");
}
/* checks for input and calls drawProgress */
int updateProgress(char *path) {
int calc_draw() {
struct timeval tv;
int ch;
/* check for input or screen resizes */
nodelay(stdscr, 1);
while((ch = getch()) != ERR) {
if(ch == 'q')
return(0);
if(ch == KEY_RESIZE) {
ncresize();
if(dat != NULL)
drawBrowser(0);
drawProgress(path);
}
if(pstate.calc.err) {
calc_draw_error(pstate.calc.cur, pstate.calc.errmsg);
return 0;
}
nodelay(stdscr, 0);
/* don't update the screen with shorter intervals than sdelay */
/* should we really draw the screen again? */
gettimeofday(&tv, (void *)NULL);
tv.tv_usec = (1000*(tv.tv_sec % 1000) + (tv.tv_usec / 1000)) / sdelay;
if(lastupdate != tv.tv_usec) {
drawProgress(path);
lastupdate = tv.tv_usec;
if(pstate.calc.lastupdate != tv.tv_usec) {
calc_draw_progress();
pstate.calc.lastupdate = tv.tv_usec;
return 0;
}
return(1);
return 1;
}
/* recursive */
int calcDir(struct dir *dest, char *path) {
struct dir *d, *t, *last;
struct stat fs;
DIR *dir;
struct dirent *dr;
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);
int calc_key(int ch) {
if(pstate.calc.err)
return 1;
if(ch == 'q')
return 1;
return 0;
}
struct dir *showCalc(char *path) {
void calc_process() {
char tmp[PATH_MAX];
struct stat fs;
struct dir *t;
/* init/reset global vars */
*lasterr = '\0';
anpos = 0;
lastupdate = 999;
memset(tmp, 0, PATH_MAX);
/* init/reset global vars */
pstate.calc.err = 0;
pstate.calc.lastupdate = 999;
pstate.calc.lasterr[0] = 0;
pstate.calc.anpos = 0;
/* init parent dir */
if(rpath(path, tmp) == NULL || lstat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
do {
ncresize();
if(dat != NULL)
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);
/* check root directory */
if(rpath(pstate.calc.cur, tmp) == NULL || lstat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
pstate.calc.err = 1;
strcpy(pstate.calc.errmsg, "Directory not found");
goto fail;
}
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 */
struct dir *dat;
int winrows, wincols;
char sdir[PATH_MAX];
int sflags, bflags, sdelay, bgraph;
int subwinc, subwinr;
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 */
void argv_parse(int argc, char **argv, char *dir) {
int i, j;
int i, j, len;
/* load defaults */
memset(dir, 0, PATH_MAX);
@ -63,7 +93,8 @@ void argv_parse(int argc, char **argv, char *dir) {
continue;
}
/* small flags */
for(j=1; j < strlen(argv[i]); j++)
len = strlen(argv[i]);
for(j=1; j<len; j++)
switch(argv[i][j]) {
case 'x': sflags |= SF_SMFS; break;
case 'q': sdelay = 2000; break;
@ -85,12 +116,12 @@ void argv_parse(int argc, char **argv, char *dir) {
exit(1);
}
} else {
dir[PATH_MAX - 1] = 0;
strncpy(dir, argv[i], PATH_MAX);
if(dir[PATH_MAX - 1] != 0) {
printf("Error: path length exceeds PATH_MAX\n");
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) {
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;
initscr();
@ -110,8 +142,16 @@ int main(int argc, char **argv) {
keypad(stdscr, TRUE);
ncresize();
while(pstate.st != ST_QUIT) {
if(pstate.st == ST_CALC)
calc_process();
/*else
wait_for_input() */
}
/*
if((dat = showCalc(pstate.calc.root)) != NULL)
showBrowser();
showBrowser();*/
erase();
refresh();

View file

@ -121,6 +121,7 @@
#define ST_BROWSE 1
#define ST_DEL 2
#define ST_HELP 3
#define ST_QUIT 4
@ -129,7 +130,7 @@
*/
struct dir {
struct dir *parent, *next, *sub;
unsigned char *name;
char *name;
off_t size, asize;
unsigned long items;
unsigned char flags;
@ -138,7 +139,14 @@ struct dir {
struct state {
int st; /* SC_x */
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;
/* 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
*/
/* main.c */
int input_handle(int);
/* util.c */
char *cropdir(const char *, int);
char *cropsize(const off_t);
@ -176,7 +186,9 @@ void ncprint(int, int, char *, ...);
struct dir *freedir(struct dir *);
char *getpath(struct dir *, char *);
/* calc.c */
struct dir *showCalc(char *);
void calc_process(void);
int calc_key(int);
int calc_draw(void);
/* browser.c */
void drawBrowser(int);
void showBrowser(void);