diff --git a/src/browser.c b/src/browser.c index 2eedce9295ae97ec9d3b93a6a71d5b48dbc2fbb3..d9351d098bd64eac0665051b31dc9b49662f159d 100644 --- a/src/browser.c +++ b/src/browser.c @@ -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: diff --git a/src/calc.c b/src/calc.c index 1452407c6a3c7ffaa40e0f1e4b549c858463e3d4..fb69e472a98a80e4a8ed1a82c59c518f66bd8d03 100644 --- a/src/calc.c +++ b/src/calc.c @@ -1,5 +1,5 @@ -/* ncdu - NCurses Disk Usage - +/* ncdu - NCurses Disk Usage + Copyright (c) 2007-2009 Yoran Heling 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 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. @@ -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) { - 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)); - ncaddstr(8, 43, "Press q to quit"); +int calc_item(struct dir *par, char *path, char *name) { + char tmp[PATH_MAX]; + struct dir *t, *d; + struct stat fs; - /* show warning if we couldn't open a dir */ - if(lasterr[0] != '\0') { - attron(A_BOLD); - ncaddstr(5, 2, "Warning:"); - attroff(A_BOLD); - ncprint(5, 11, "could not open %-32s", cropdir(lasterr, 32)); - ncaddstr(6, 3, "some directory sizes may not be correct"); + 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); - /* 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]; - } 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!"); - - attron(A_BOLD); - ncaddstr(5, 2, "Error:"); - attroff(A_BOLD); - - ncprint(5, 9, "could not open %s", cropdir(dir, 34)); - ncaddstr(6, 3, "press any key to continue..."); - - refresh(); -} +#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; + } -/* checks for input and calls drawProgress */ -int updateProgress(char *path) { - 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); + /* 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; } } - nodelay(stdscr, 0); - - /* don't update the screen with shorter intervals than sdelay */ - 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; - } - return(1); + return 0; } -/* recursive */ -int calcDir(struct dir *dest, char *path) { - struct dir *d, *t, *last; - struct stat fs; +/* recursively walk through the directory tree */ +int calc_dir(struct dir *dest, char *path) { + struct dir *t; DIR *dir; struct dirent *dr; - char *f, tmp[PATH_MAX]; - int len, derr = 0, serr = 0; + char tmp[PATH_MAX]; + int len; - if(!updateProgress(path)) - return(0); + if(input_handle(1)) + return 1; - /* open directory */ + /* open directory */ if((dir = opendir(path)) == NULL) { - strcpy(lasterr, path); + strcpy(pstate.calc.lasterr, path); dest->flags |= FF_ERR; t = dest; while((t = t->parent) != NULL) t->flags |= FF_SERR; - return(1); + return 0; } - len = strlen(path); - /* add leading slash */ + /* add leading slash */ + len = strlen(path); 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; - } + /* 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; + } - /* 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; + if(errno) { + if(dest->flags & FF_SERR) + dest->flags -= FF_SERR; + dest->flags |= FF_ERR; + } + closedir(dir); - /* set d->name */ - d->name = malloc(strlen(f)+1); - strcpy(d->name, f); + /* 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; + } -#ifdef __CYGWIN__ - /* /proc/registry names may contain slashes */ - if(strchr(d->name, '/') || strchr(d->name, '\\')) { - serr = 1; - errno = 0; - d->flags |= FF_ERR; - continue; + /* 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; } -#endif - /* get full path */ - strcpy(tmp, path); - strcat(tmp, f); + return 0; +} - /* 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; - } - } +void calc_draw_progress() { + static char antext[15] = "Calculating..."; + char ani[15]; + int i; - /* show status */ - if(!updateProgress(tmp)) - return(0); + nccreate(10, 60, dat == NULL ? "Calculating..." : "Recalculating..."); - 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; - } + ncprint(2, 2, "Total items: %-8d size: %s", + 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"); - 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); - } + /* 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(pstate.calc.lasterr, 32)); + ncaddstr(6, 3, "some directory sizes may not be correct"); } - return(1); + /* animation - but only if the screen refreshes more than or once every second */ + if(sdelay <= 1000) { + 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); +} + + +void calc_draw_error(char *cur, char *msg) { + nccreate(7, 60, "Error!"); + + attron(A_BOLD); + ncaddstr(2, 2, "Error:"); + attroff(A_BOLD); + + 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..."); } -struct dir *showCalc(char *path) { - char tmp[PATH_MAX]; - struct stat fs; - struct dir *t; +int calc_draw() { + struct timeval tv; - /* init/reset global vars */ - *lasterr = '\0'; - anpos = 0; - lastupdate = 999; - memset(tmp, 0, PATH_MAX); - - /* 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); + if(pstate.calc.err) { + calc_draw_error(pstate.calc.cur, pstate.calc.errmsg); + return 0; } - return(parent); + /* 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(pstate.calc.lastupdate != tv.tv_usec) { + calc_draw_progress(); + pstate.calc.lastupdate = tv.tv_usec; + return 0; + } + return 1; } +int calc_key(int ch) { + if(pstate.calc.err) + return 1; + if(ch == 'q') + return 1; + return 0; +} +void calc_process() { + char tmp[PATH_MAX]; + struct stat fs; + struct dir *t; + + /* init/reset global vars */ + pstate.calc.err = 0; + pstate.calc.lastupdate = 999; + pstate.calc.lasterr[0] = 0; + pstate.calc.anpos = 0; + + /* 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; + } + /* 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; +} diff --git a/src/main.c b/src/main.c index 8f6284137523dc1d027c141285e7a896479083fc..329226b4108ec11faf9926df9b67d335796686ff 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); diff --git a/src/ncdu.h b/src/ncdu.h index f07a446f624651c453afbcd32e3bc9ea0b5531bb..61e82ff9f1069caa7ad062359398d0feedfb6dd3 100644 --- a/src/ncdu.h +++ b/src/ncdu.h @@ -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);