From 5064b4d6510c2430e06d2819796a279ef8aef4a1 Mon Sep 17 00:00:00 2001 From: Yorhel <git@yorhel.nl> Date: Sun, 26 Aug 2012 16:53:37 +0200 Subject: [PATCH] Re-added scanning UI and improved error handling --- src/dir.h | 12 +++++++ src/dir_common.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ src/dir_mem.c | 10 ++++++ src/dir_scan.c | 70 +++++++++++++++++++++++--------------- src/main.c | 4 +-- 5 files changed, 154 insertions(+), 30 deletions(-) diff --git a/src/dir.h b/src/dir.h index bd50579..b9ef0e1 100644 --- a/src/dir.h +++ b/src/dir.h @@ -76,6 +76,11 @@ struct dir_output { * Return value should be 0 to continue running ncdu, 1 to exit. */ int (*final)(int); + + /* The output code is responsible for updating these stats. Can be 0 when not + * available. */ + off_t size; + long items; }; @@ -108,9 +113,16 @@ void dir_curpath_leave(); /* Sets the path where the last error occured, or reset on NULL. */ void dir_setlasterr(const char *); +/* Error message on fatal error, or NULL if there hasn't been a fatal error yet. */ +extern char *dir_fatalerr; +void dir_seterr(const char *, ...); + /* Return an empty struct dir with the given name, for use with * dir_output.item(). Returned memory may be freed/overwritten on a subsequent * call. */ struct dir *dir_createstruct(const char *); +int dir_key(int); +void dir_draw(); + #endif diff --git a/src/dir_common.c b/src/dir_common.c index dec814b..c4ff819 100644 --- a/src/dir_common.c +++ b/src/dir_common.c @@ -27,10 +27,12 @@ #include <string.h> #include <stdlib.h> +#include <stdarg.h> char *dir_curpath; /* Full path of the last seen item. */ struct dir_output dir_output; +char *dir_fatalerr; /* Error message on a fatal error. (NULL if there was no fatal error) */ static char *lasterr; /* Path where the last error occured. */ static int curpathl; /* Allocated length of dir_curpath */ static int lasterrl; /* ^ of lasterr */ @@ -86,6 +88,21 @@ void dir_setlasterr(const char *path) { } +void dir_seterr(const char *fmt, ...) { + free(dir_fatalerr); + dir_fatalerr = NULL; + if(!fmt) + return; + + va_list va; + va_start(va, fmt); + dir_fatalerr = malloc(1024); /* Should be enough for everything... */ + vsnprintf(dir_fatalerr, 1023, fmt, va); + dir_fatalerr[1023] = 0; + va_end(va); +} + + struct dir *dir_createstruct(const char *name) { static struct dir *d = NULL; static size_t len = 0; @@ -98,3 +115,74 @@ struct dir *dir_createstruct(const char *name) { strcpy(d->name, name); return d; } + + +static void draw_progress() { + static const char antext[] = "Scanning..."; + static int anpos = 0; + char ani[20] = {}; + int i; + int width = wincols-5; + + nccreate(10, width, "Scanning..."); + + ncprint(2, 2, "Total items: %-8d size: %s", dir_output.items, formatsize(dir_output.size)); + ncprint(3, 2, "Current item: %s", cropstr(dir_curpath, width-18)); + ncaddstr(8, width-18, "Press q to abort"); + + /* show warning if we couldn't open a dir */ + if(lasterr) { + attron(A_BOLD); + ncaddstr(5, 2, "Warning:"); + attroff(A_BOLD); + ncprint(5, 11, "error scanning %-32s", cropstr(lasterr, width-28)); + ncaddstr(6, 3, "some directory sizes may not be correct"); + } + + /* animation - but only if the screen refreshes more than or once every second */ + if(update_delay <= 1000) { + if(++anpos == strlen(antext)*2) + anpos = 0; + memset(ani, ' ', strlen(antext)); + if(anpos < strlen(antext)) + for(i=0; i<=anpos; i++) + ani[i] = antext[i]; + else + for(i=strlen(antext)-1; i>anpos-strlen(antext); i--) + ani[i] = antext[i]; + } else + strcpy(ani, antext); + ncaddstr(8, 3, ani); +} + + +static void draw_error(char *cur, char *msg) { + int width = wincols-5; + nccreate(7, width, "Error!"); + + attron(A_BOLD); + ncaddstr(2, 2, "Error:"); + attroff(A_BOLD); + + ncprint(2, 9, "could not open %s", cropstr(cur, width-26)); + ncprint(3, 4, "%s", cropstr(msg, width-8)); + ncaddstr(5, width-30, "press any key to continue..."); +} + + +void dir_draw() { + browse_draw(); + if(dir_fatalerr) + draw_error(dir_curpath, dir_fatalerr); + else + draw_progress(); +} + + +int dir_key(int ch) { + if(dir_fatalerr) + return 1; + if(ch == 'q') + return 1; + return 0; +} diff --git a/src/dir_mem.c b/src/dir_mem.c index 4549b61..ce67525 100644 --- a/src/dir_mem.c +++ b/src/dir_mem.c @@ -144,6 +144,11 @@ static void item(struct dir *item) { if(item->flags & FF_DIR) curdir = item; + /* Special-case the name of the root item to be empty instead of "/". This is + * what getpath() expects. */ + if(item == root && strcmp(item->name, "/") == 0) + item->name[0] = 0; + /* Update stats of parents. Don't update the size/asize fields if this is a * possible hard link, because hlnk_check() will take care of it in that * case. */ @@ -157,6 +162,9 @@ static void item(struct dir *item) { if(item->flags & FF_SERR || item->flags & FF_ERR) for(t=item->parent; t; t=t->parent) t->flags |= FF_SERR; + + dir_output.size = root->size; + dir_output.items = root->items; } @@ -200,6 +208,8 @@ void dir_mem_init(struct dir *_orig) { dir_output.item = item; dir_output.final = final; + dir_output.size = 0; + dir_output.items = 0; /* Init hash table for hard link detection */ links = kh_init(hl); diff --git a/src/dir_scan.c b/src/dir_scan.c index 3ab172f..a511275 100644 --- a/src/dir_scan.c +++ b/src/dir_scan.c @@ -135,7 +135,11 @@ static int dir_scan_recurse(struct dir *d) { d->flags |= FF_ERR; dir_output.item(d); dir_output.item(NULL); - return chdir("..") ? 1 : 0; /* TODO: Error reporting */ + if(chdir("..")) { + dir_seterr("Error going back to parent directory: %s", strerror(errno)); + return 1; + } else + return 0; } /* readdir() failed halfway, not fatal. */ @@ -147,8 +151,10 @@ static int dir_scan_recurse(struct dir *d) { dir_output.item(NULL); /* Not being able to chdir back is fatal */ - if(!fail && chdir("..")) - return 1; /* TODO: Error reporting */ + if(!fail && chdir("..")) { + dir_seterr("Error going back to parent directory: %s", strerror(errno)); + return 1; + } return fail; } @@ -182,14 +188,14 @@ static int dir_scan_item(struct dir *d) { /* Recurse into the dir or output the item */ if(d->flags & FF_DIR && !(d->flags & (FF_ERR|FF_EXL|FF_OTHFS))) - dir_scan_recurse(d); + fail = dir_scan_recurse(d); else if(d->flags & FF_DIR) { dir_output.item(d); dir_output.item(NULL); } else dir_output.item(d); - return fail; /* TODO: UI */ + return fail || input_handle(1); } @@ -222,42 +228,50 @@ int dir_scan_process() { struct stat fs; struct dir *d; - if((path = path_real(dir_curpath)) == NULL) { - /* TODO */ + if((path = path_real(dir_curpath)) == NULL) + dir_seterr("Error obtaining full path: %s", strerror(errno)); + else { + dir_curpath_set(path); + free(path); } - dir_curpath_set(path); - free(path); - if(path_chdir(dir_curpath) < 0) { - /* TODO */ - } + if(!dir_fatalerr && path_chdir(dir_curpath) < 0) + dir_seterr("Error changing directory: %s", strerror(errno)); /* Can these even fail after a chdir? */ - if(lstat(".", &fs) != 0 || !S_ISDIR(fs.st_mode)) { - /* TODO */ - } + if(!dir_fatalerr && lstat(".", &fs) != 0) + dir_seterr("Error obtaining directory information: %s", strerror(errno)); + if(!dir_fatalerr && !S_ISDIR(fs.st_mode)) + dir_seterr("Not a directory"); - dir = dir_read(&fail); - if(!dir) { - /* TODO */ - } + if(!dir_fatalerr && !(dir = dir_read(&fail))) + dir_seterr("Error reading directory: %s", strerror(errno)); - curdev = fs.st_dev; - d = dir_createstruct(dir_curpath); - if(fail) - d->flags |= FF_ERR; - stat_to_dir(d, &fs); + /* Special case: empty directory = error */ + if(!dir_fatalerr && !*dir) + dir_seterr("Directory empty"); - dir_output.item(d); - fail = dir_walk(dir); - dir_output.item(NULL); + if(!dir_fatalerr) { + curdev = fs.st_dev; + d = dir_createstruct(dir_curpath); + if(fail) + d->flags |= FF_ERR; + stat_to_dir(d, &fs); + + dir_output.item(d); + fail = dir_walk(dir); + dir_output.item(NULL); + } - return dir_output.final(fail); + while(dir_fatalerr && !input_handle(0)) + ; + return dir_output.final(dir_fatalerr || fail); } void dir_scan_init(const char *path) { dir_curpath_set(path); dir_setlasterr(NULL); + dir_seterr(NULL); pstate = ST_CALC; } diff --git a/src/main.c b/src/main.c index 81283f3..d2470d2 100644 --- a/src/main.c +++ b/src/main.c @@ -44,7 +44,7 @@ static long lastupdate = 999; static void screen_draw() { switch(pstate) { - case ST_CALC: /* TODO */ break; + case ST_CALC: dir_draw(); break; case ST_BROWSE: browse_draw(); break; case ST_HELP: help_draw(); break; case ST_DEL: delete_draw(); break; @@ -82,7 +82,7 @@ int input_handle(int wait) { continue; } switch(pstate) { - case ST_CALC: return 0; /* TODO */ + case ST_CALC: return dir_key(ch); case ST_BROWSE: return browse_key(ch); case ST_HELP: return help_key(ch); case ST_DEL: return delete_key(ch); -- GitLab