From 87a7925b991bac76d2f2746c24e2d267f76868c3 Mon Sep 17 00:00:00 2001 From: yorhel Date: Tue, 24 Jul 2007 07:58:22 +0000 Subject: [PATCH] * Rewrote the file browser, help window, and delete windows * Split browser.c into delete.c and help.c * Added "reference to parent directory"-hack * File browser doesn't use the ncurses menu lib anymore * Fixed bug #1758403: large directories work fine now * Fixed bug with wide characters in the browser * Performance improvements when browsing large directories * Required (instead of recommended) gettimeofday() git-svn-id: svn://blicky.net/ncdu/trunk@6 ce56bc8d-f834-0410-b703-f827bd498a76 --- configure.in | 1 - src/Makefile.am | 2 +- src/browser.c | 612 +++++++++++++++--------------------------------- src/calc.c | 49 ++-- src/delete.c | 242 +++++++++++++++++++ src/help.c | 193 +++++++++++++++ src/main.c | 2 +- src/ncdu.h | 16 +- 8 files changed, 657 insertions(+), 460 deletions(-) create mode 100644 src/delete.c create mode 100644 src/help.c diff --git a/configure.in b/configure.in index 4be58fd..bc7f2a3 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,6 @@ AC_PROG_RANLIB # Checks for libraries. AC_CHECK_LIB(ncurses, initscr) AC_CHECK_LIB(form, new_form) -AC_CHECK_LIB(menu, new_menu) # Checks for header files. AC_HEADER_DIRENT diff --git a/src/Makefile.am b/src/Makefile.am index 5fc4338..5f180c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS = ncdu -ncdu_SOURCES = browser.c calc.c main.c settings.c util.c exclude.c +ncdu_SOURCES = browser.c calc.c main.c settings.c util.c exclude.c help.c delete.c noinst_HEADERS = ncdu.h diff --git a/src/browser.c b/src/browser.c index 8be5d41..2cca4b2 100644 --- a/src/browser.c +++ b/src/browser.c @@ -29,129 +29,19 @@ struct dir *bcur; int helpwin; -/* somewhat lazy form of removing a file/directory - BUG: does not handle terminal resizing */ -WINDOW *rm_win; -char rm_main[PATH_MAX]; -struct dir *rm_dr; - -struct dir *removedir(struct dir *dr) { - struct dir *nxt, *cur; - char cd[PATH_MAX], fl[PATH_MAX], par = 0; - int ch; - - getpath(dr, cd); - strcpy(fl, cd); - strcat(fl, "/"); - strcat(fl, dr->name); - - if(rm_win == NULL) { - par = 1; - strcpy(rm_main, fl); - rm_dr = dr; - rm_win = newwin(6, 60, winrows/2 - 3, wincols/2 - 30); - keypad(rm_win, TRUE); - box(rm_win, 0, 0); - if(sflags & SF_NOCFM) - goto doit; - - wattron(rm_win, A_BOLD); - mvwaddstr(rm_win, 0, 4, "Confirm..."); - wattroff(rm_win, A_BOLD); - mvwprintw(rm_win, 2, 2, "Are you sure you want to delete the selected %s?", dr->flags & FF_DIR ? "directory" : "file"); -/* mvwaddstr(rm_win, 3, 3, cropdir(fl, 56));*/ - wattron(rm_win, A_BOLD); - mvwaddstr(rm_win, 4, 8, "y:"); - mvwaddstr(rm_win, 4,20, "n:"); - mvwaddstr(rm_win, 4,31, "a:"); - wattroff(rm_win, A_BOLD); - mvwaddstr(rm_win, 4,11, "yes"); - mvwaddstr(rm_win, 4,23, "no"); - mvwaddstr(rm_win, 4,34, "don't ask me again"); - wrefresh(rm_win); - ch = wgetch(rm_win); - if(ch != 'y' && ch != 'a') { - delwin(rm_win); - rm_win = NULL; - return(dr); - } - if(ch == 'a') - sflags |= SF_NOCFM; - - doit: - werase(rm_win); - box(rm_win, 0, 0); - wattron(rm_win, A_BOLD); - mvwaddstr(rm_win, 0, 4, "Deleting..."); - wattroff(rm_win, A_BOLD); - mvwprintw(rm_win, 2, 2, "Deleting %s...", cropdir(rm_main, 44)); - wrefresh(rm_win); - } - - if(dr->flags & FF_DIR) { - if(dr->sub != NULL) { - nxt = dr->sub; - while(nxt->prev != NULL) - nxt = nxt->prev; - while(nxt != NULL) { - cur = nxt; - nxt = cur->next; - if(removedir(cur) == rm_dr) { - if(rm_dr == dr) - break; - if(rm_win != NULL) - delwin(rm_win); - rm_win = NULL; - return(rm_dr); - } - } - } - ch = rmdir(fl); - } else - ch = unlink(fl); - - if(ch == -1 && !(sflags & SF_IGNE)) { - mvwaddstr(rm_win, 2, 2, " "); - mvwprintw(rm_win, 1, 2, "Error deleting %s", cropdir(fl, 42)); - mvwaddstr(rm_win, 2, 3, cropdir(strerror(errno), 55)); - wattron(rm_win, A_BOLD); - mvwaddstr(rm_win, 4, 8, "a:"); - mvwaddstr(rm_win, 4,21, "i:"); - mvwaddstr(rm_win, 4,35, "I:"); - wattroff(rm_win, A_BOLD); - mvwaddstr(rm_win, 4,11, "abort"); - mvwaddstr(rm_win, 4,24, "ignore"); - mvwaddstr(rm_win, 4,38, "ignore all"); - wrefresh(rm_win); - ch = wgetch(rm_win); - if((ch != 'i' && ch != 'I') || dr == rm_dr) { - delwin(rm_win); - rm_win = NULL; - return(rm_dr); - } - if(ch == 'I') - sflags |= SF_IGNE; - - mvwaddstr(rm_win, 1, 2, " "); - mvwaddstr(rm_win, 2, 2, " "); - mvwaddstr(rm_win, 4, 2, " "); - mvwprintw(rm_win, 2, 2, "Deleting %s...", cropdir(rm_main, 44)); - wrefresh(rm_win); - return(dr); - } - - if(par == 1) { - delwin(rm_win); - rm_win = NULL; - } - return(freedir(dr)); +struct dir * removedir(struct dir *dr) { + return(dr); } - - int cmp(struct dir *x, struct dir *y) { struct dir *a, *b; int r = 0; + + if(y->flags & FF_PAR) + return(1); + if(x->flags & FF_PAR) + return(-1); + if(bflags & BF_DESC) { a = y; b = x; } else { @@ -219,160 +109,6 @@ struct dir *sortFiles(struct dir *list) { } } -int helpScreen(void) { - WINDOW *hlp; - int ch=0, x, y; - - hlp = newwin(15, 60, winrows/2-7, wincols/2-30); - curs_set(0); - if(!helpwin) helpwin = 1; - do { - if(ch == ERR) - continue; - if(ch && ch != '1' && ch != '2' && ch != '3' && ch != '4') - break; - if(ch) - helpwin = ch - 48; - - werase(hlp); - box(hlp, 0, 0); - wattron(hlp, A_BOLD); - mvwaddstr(hlp, 0, 4, "ncdu help"); - wattroff(hlp, A_BOLD); - mvwaddstr(hlp, 13, 32, "Press any key to continue"); - switch(helpwin) { - case 1: - wattron(hlp, A_BOLD); - mvwaddstr(hlp, 1, 30, "1:Keys"); - wattroff(hlp, A_BOLD); - mvwaddstr(hlp, 1, 39, "2:Format"); - mvwaddstr(hlp, 1, 50, "3:About"); - wattron(hlp, A_BOLD); - mvwaddstr(hlp, 3, 7, "up/down"); - mvwaddstr(hlp, 4, 3, "right/enter"); - mvwaddstr(hlp, 5, 10, "left"); - mvwaddstr(hlp, 6, 11, "n/s"); - mvwaddch( hlp, 7, 13, 'd'); - mvwaddch( hlp, 8, 13, 't'); - mvwaddch( hlp, 9, 13, 'g'); - mvwaddch( hlp,10, 13, 'p'); - mvwaddch( hlp,11, 13, 'h'); - mvwaddch( hlp,12, 13, 'q'); - wattroff(hlp, A_BOLD); - mvwaddstr(hlp, 3, 16, "Cycle through the items"); - mvwaddstr(hlp, 4, 16, "Open directory"); - mvwaddstr(hlp, 5, 16, "Previous directory"); - mvwaddstr(hlp, 6, 16, "Sort by name or size (asc/desc)"); - mvwaddstr(hlp, 7, 16, "Delete selected file or directory"); - mvwaddstr(hlp, 8, 16, "Toggle dirs before files when sorting"); - mvwaddstr(hlp, 9, 16, "Show percentage and/or graph"); - mvwaddstr(hlp,10, 16, "Toggle between powers of 1000 and 1024"); - mvwaddstr(hlp,11, 16, "Show/hide hidden files"); - mvwaddstr(hlp,12, 16, "Quit ncdu"); - break; - case 2: - mvwaddstr(hlp, 1, 30, "1:Keys"); - wattron(hlp, A_BOLD); - mvwaddstr(hlp, 1, 39, "2:Format"); - wattroff(hlp, A_BOLD); - mvwaddstr(hlp, 1, 50, "3:About"); - wattron(hlp, A_BOLD); - mvwaddstr(hlp, 3, 3, "X [size] [file or directory]"); - wattroff(hlp, A_BOLD); - mvwaddstr(hlp, 5, 4, "The X is only present in the following cases:"); - wattron(hlp, A_BOLD); - mvwaddch(hlp, 6, 4, '!'); - mvwaddch(hlp, 7, 4, '.'); - mvwaddch(hlp, 8, 4, '>'); - mvwaddch(hlp, 9, 4, '<'); - mvwaddch(hlp,10, 4, '@'); - mvwaddch(hlp,11, 4, 'e'); - wattroff(hlp, A_BOLD); - mvwaddstr(hlp, 6, 7, "An error occured while reading this directory"); - mvwaddstr(hlp, 7, 7, "An error occured while reading a subdirectory"); - mvwaddstr(hlp, 8, 7, "File or directory is excluded from the statistics"); - mvwaddstr(hlp, 9, 7, "Directory was on an other filesystem"); - mvwaddstr(hlp,10, 7, "This is not a file nor a dir (symlink, socket, ...)"); - mvwaddstr(hlp,11, 7, "Empty directory"); - break; - case 3: - /* Indeed, too much spare time */ - mvwaddstr(hlp, 1, 30, "1:Keys"); - mvwaddstr(hlp, 1, 39, "2:Format"); - wattron(hlp, A_BOLD); - mvwaddstr(hlp, 1, 50, "3:About"); - wattroff(hlp, A_BOLD); - wattron(hlp, A_REVERSE); - x=12;y=4; - /* N */ - mvwaddstr(hlp, y+0, x+0, " "); - mvwaddstr(hlp, y+1, x+0, " "); - mvwaddstr(hlp, y+2, x+0, " "); - mvwaddstr(hlp, y+3, x+0, " "); - mvwaddstr(hlp, y+4, x+0, " "); - mvwaddstr(hlp, y+1, x+4, " "); - mvwaddstr(hlp, y+2, x+4, " "); - mvwaddstr(hlp, y+3, x+4, " "); - mvwaddstr(hlp, y+4, x+4, " "); - /* C */ - mvwaddstr(hlp, y+0, x+8, " "); - mvwaddstr(hlp, y+1, x+8, " "); - mvwaddstr(hlp, y+2, x+8, " "); - mvwaddstr(hlp, y+3, x+8, " "); - mvwaddstr(hlp, y+4, x+8, " "); - /* D */ - mvwaddstr(hlp, y+0, x+19, " "); - mvwaddstr(hlp, y+1, x+19, " "); - mvwaddstr(hlp, y+2, x+15, " "); - mvwaddstr(hlp, y+3, x+15, " "); - mvwaddstr(hlp, y+3, x+19, " "); - mvwaddstr(hlp, y+4, x+15, " "); - /* U */ - mvwaddstr(hlp, y+0, x+23, " "); - mvwaddstr(hlp, y+1, x+23, " "); - mvwaddstr(hlp, y+2, x+23, " "); - mvwaddstr(hlp, y+3, x+23, " "); - mvwaddstr(hlp, y+0, x+27, " "); - mvwaddstr(hlp, y+1, x+27, " "); - mvwaddstr(hlp, y+2, x+27, " "); - mvwaddstr(hlp, y+3, x+27, " "); - mvwaddstr(hlp, y+4, x+23, " "); - wattroff(hlp, A_REVERSE); - mvwaddstr(hlp, y+0, x+30, "NCurses"); - mvwaddstr(hlp, y+1, x+30, "Disk"); - mvwaddstr(hlp, y+2, x+30, "Usage"); - mvwprintw(hlp, y+4, x+30, "%s", PACKAGE_VERSION); - - mvwaddstr(hlp,10, 7, "Written by Yoran Heling "); - mvwaddstr(hlp,11, 16, "http://dev.yorhel.nl/ncdu/"); - break; - case 4: - mvwaddstr(hlp, 1, 30, "1:Keys"); - mvwaddstr(hlp, 1, 39, "2:Format"); - mvwaddstr(hlp, 1, 50, "3:About"); - mvwaddstr(hlp, 3, 3, "There is no fourth window, baka~~"); - } - wrefresh(hlp); - } while((ch = getch())); - delwin(hlp); - touchwin(stdscr); - refresh(); - if(ch == KEY_RESIZE) { - ncresize(); - return(1); - } - helpwin = 0; - return(0); -} - -#define toggle(x,y) if(x & y) x -=y; else x |= y - -/* bgraph: - 0 -> none - 1 -> graph - 2 -> percentage - 3 -> percentage + graph -*/ char graphdat[11]; char *graph(off_t max, off_t size) { @@ -384,14 +120,17 @@ char *graph(off_t max, off_t size) { } -void browseDir(void) { - ITEM **items; - char **itrows, tmp[PATH_MAX], tmp2[PATH_MAX], ct; - MENU *menu; - struct dir *d; - off_t max; - int i, fls, ch, bf, s; +#define exlhid(x) if(bflags & BF_HIDE && !(x->flags & FF_PAR) && x->name[0] == '.') { i--; continue; } +void drawBrowser(int change) { + struct dir *n; + char tmp[PATH_MAX], ct, dt; + int selected, i, o; + off_t max; + + erase(); + + /* exit if there are no items to display */ if(bcur->parent == NULL) { if(bcur->sub == NULL) { erase(); @@ -402,220 +141,239 @@ void browseDir(void) { } else bcur = bcur->sub; } - - erase(); + /* create header and status bar */ attron(A_REVERSE); - for(i=0; iparent->size), bcur->parent->files, bcur->parent->dirs); attroff(A_REVERSE); - for(i=wincols; i>=0; i--) - mvaddch(1,i,'-'); - - bcur = sortFiles(bcur); - fls = 1; d = bcur; max = 0; - while(d != NULL) { - if(!(bflags & BF_HIDE) || d->name[0] != '.') { - if(d->size > max) - max = d->size; - fls++; - } - d = d->next; - } + mvhline(1, 0, '-', wincols); mvaddstr(1, 3, cropdir(getpath(bcur, tmp), wincols-5)); - items = calloc(fls+2, sizeof(ITEM *)); - itrows = malloc((fls+1) * sizeof(char *)); - itrows[0] = malloc((fls+1) * wincols * sizeof(char)); - for(i=1; iprev != NULL) + bcur = bcur->prev; - s = 0; + /* get maximum size and selected item */ + for(n = bcur, selected = i = 0; n != NULL; n = n->next, i++) { + exlhid(n) + if(n->flags & FF_BSEL) + selected = i; + if(n->size > max) + max = n->size; + } + + if(selected+change < 0) + change -= selected+change; + if(selected+change > --i) + change -= (selected+change)-i; + for(n = bcur, i = 0; n != NULL; n = n->next, i++) { + exlhid(n) + if(i == selected && n->flags & FF_BSEL) + n->flags -= FF_BSEL; + if(i == selected+change) + n->flags |= FF_BSEL; + } + selected += change; + + /* determine the listing format */ switch(bgraph) { case 0: sprintf(tmp, "%%c %%7s %%c%%-%ds", wincols-12); - s = 0; break; case 1: - s = 12; sprintf(tmp, "%%c %%7s [%%10s] %%c%%-%ds", wincols-24); break; case 2: - s = 7; sprintf(tmp, "%%c %%7s [%%4.1f%%%%] %%c%%-%ds", wincols-19); break; case 3: - s = 18; sprintf(tmp, "%%c %%7s [%%4.1f%%%% %%10s] %%c%%-%ds", wincols-30); } - if(bcur->parent->parent != NULL) { - s += 11; - for(i=0; iname[0] == '.') { - d = d->next; + /* determine start position */ + for(n = bcur, i = 0; n != NULL; n = n->next, i++) { + exlhid(n) + if(i == (selected / (winrows-3)) * (winrows-3)) + break; + } + selected -= i; + + /* print the list to the screen */ + for(i=0; n != NULL && i < winrows-3; n = n->next, i++) { + exlhid(n) + if(i == selected) + attron(A_REVERSE); + + /* reference to parent dir has a different format */ + if(n->flags & FF_PAR) { + mvhline(i+2, 0, ' ', wincols); + o = bgraph == 0 ? 11 : + bgraph == 1 ? 23 : + bgraph == 2 ? 18 : + 29 ; + mvaddstr(i+2, o, "/.."); + if(i == selected) + attroff(A_REVERSE); continue; } - ct = d->flags & FF_ERR ? '!' : - d->flags & FF_SERR ? '.' : - d->flags & FF_OTHFS ? '>' : - d->flags & FF_EXL ? '<' : - d->flags & FF_OTHER ? '@' : - d->flags & FF_DIR - && d->sub == NULL ? 'e' : + + /* determine indication character */ + ct = n->flags & FF_EXL ? '<' : + n->flags & FF_ERR ? '!' : + n->flags & FF_SERR ? '.' : + n->flags & FF_OTHFS ? '>' : + n->flags & FF_OTHER ? '@' : + n->flags & FF_DIR + && n->sub == NULL ? 'e' : ' ' ; + dt = n->flags & FF_DIR ? '/' : ' '; + + /* format and add item to the list */ switch(bgraph) { case 0: - sprintf(itrows[i], tmp, ct, cropsize(d->size), - d->flags & FF_DIR ? '/' : ' ', cropdir(d->name, wincols-12)); + mvprintw(i+2, 0, tmp, ct, cropsize(n->size), + dt, cropdir(n->name, wincols-12) + ); break; case 1: - sprintf(itrows[i], tmp, ct, cropsize(d->size), graph(max, d->size), - d->flags & FF_DIR ? '/' : ' ', cropdir(d->name, wincols-24)); + mvprintw(i+2, 0, tmp, ct, cropsize(n->size), + graph(max, n->size), + dt, cropdir(n->name, wincols-24) + ); break; case 2: - sprintf(itrows[i], tmp, ct, cropsize(d->size), ((float) d->size / (float) d->parent->size) * 100.0f, - d->flags & FF_DIR ? '/' : ' ', cropdir(d->name, wincols-19)); + mvprintw(i+2, 0, tmp, ct, cropsize(n->size), + ((float) n->size / (float) n->parent->size) * 100.0f, + dt, cropdir(n->name, wincols-19) + ); break; case 3: - sprintf(itrows[i], tmp, ct, cropsize(d->size), ((float) d->size / (float) d->parent->size) * 100.0f, graph(max, d->size), - d->flags & FF_DIR ? '/' : ' ', cropdir(d->name, wincols-30)); + mvprintw(i+2, 0, tmp, ct, cropsize(n->size), + ((float) n->size / (float) n->parent->size) * 100.0f, graph(max, n->size), + dt, cropdir(n->name, wincols-30) + ); } - - items[i] = new_item(itrows[i], 0); - set_item_userptr(items[i], d); - if(d->flags & FF_BSEL) { - s = i; - d->flags -= FF_BSEL; - } - d = d->next; - i++; + + if(i == selected) + attroff(A_REVERSE); } - items[i] = NULL; - menu = new_menu(items); - set_menu_format(menu, winrows-3, 1); - set_menu_sub(menu, derwin(stdscr, winrows-3, wincols, 2, 0)); - set_menu_mark(menu, ""); - post_menu(menu); - if(s >= 0) - for(i=0; iflags & FF_BSEL) + return n; + } while((n = n->next) != NULL); +} + + +#define toggle(x,y) if(x & y) x -=y; else x |= y + +void showBrowser(void) { + int ch, change; + struct dir *n; - d = bcur; bf = bflags; + bcur = dat.sub; + bgraph = 1; + nodelay(stdscr, 0); + bflags = BF_SIZE; + + drawBrowser(0); refresh(); - - if(helpwin > 0 && helpScreen() == 1) goto endbrowse; + while((ch = getch())) { + change = 0; switch(ch) { - case KEY_UP: menu_driver(menu, REQ_UP_ITEM); break; - case KEY_DOWN: menu_driver(menu, REQ_DOWN_ITEM); break; - case KEY_HOME: menu_driver(menu, REQ_FIRST_ITEM); break; - case KEY_LL: - case KEY_END: menu_driver(menu, REQ_LAST_ITEM); break; - case KEY_PPAGE: menu_driver(menu, REQ_SCR_UPAGE); break; - case KEY_NPAGE: menu_driver(menu, REQ_SCR_DPAGE); break; - case '?': - if(helpScreen() == 1) - goto endbrowse; + /* selecting items */ + case KEY_UP: + change = -1; break; - case 'q': - bcur = NULL; - goto endbrowse; - case 10: case KEY_RIGHT: - bcur = item_userptr(current_item(menu)); - if(bcur == NULL) { - bcur = d->parent; - goto endbrowse; - } else if(bcur->sub != NULL) { - bcur->flags |= FF_BSEL; - bcur = bcur->sub; - goto endbrowse; - } else - bcur = d; + case KEY_DOWN: + change = 1; break; - case KEY_RESIZE: - ncresize(); - goto endbrowse; - case KEY_LEFT: - if(bcur->parent->parent != NULL) - bcur = bcur->parent; - else - bcur = d; - goto endbrowse; + case KEY_HOME: + change = -16777216; + break; + case KEY_LL: + case KEY_END: + change = 16777216; + break; + case KEY_PPAGE: + change = -1*(winrows-3); + break; + case KEY_NPAGE: + change = winrows-3; + break; + + /* sorting items */ case 'n': if(bflags & BF_NAME) toggle(bflags, BF_DESC); else bflags = (bflags & BF_HIDE) + (bflags & BF_NDIRF) + BF_NAME; - goto endbrowse; + break; case 's': if(bflags & BF_SIZE) toggle(bflags, BF_DESC); else bflags = (bflags & BF_HIDE) + (bflags & BF_NDIRF) + BF_SIZE; - goto endbrowse; + break; case 'p': toggle(sflags, SF_SI); - goto endbrowse; + break; case 'h': toggle(bflags, BF_HIDE); - goto endbrowse; + break; case 't': toggle(bflags, BF_NDIRF); - goto endbrowse; + break; + + /* browsing */ + case 10: + case KEY_RIGHT: + n = selected(); + if(n->flags & FF_PAR) + bcur = bcur->parent; + else if(n->sub != NULL) + bcur = n->sub; + break; + case KEY_LEFT: + if(bcur->parent->parent != NULL) { + bcur = bcur->parent; + } + break; + + /* and other stuff */ + case KEY_RESIZE: + ncresize(); + break; case 'g': if(++bgraph > 3) bgraph = 0; - goto endbrowse; + break; + case '?': + showHelp(); + break; case 'd': - bcur = item_userptr(current_item(menu)); - if(bcur == NULL) { - bcur = d; - break; - } - set_item_userptr(current_item(menu), NULL); - bcur->flags |= FF_BSEL; - bcur = removedir(bcur); - goto endbrowse; + n = selected(); + if(!(n->flags & FF_PAR)) + bcur = showDelete(n); + break; + case 'q': + goto endloop; } + drawBrowser(change); refresh(); } - endbrowse: - if(bcur == d && (d = item_userptr(current_item(menu))) != NULL) - d->flags |= FF_BSEL; - unpost_menu(menu); - for(i=fls-3;i>=0;i--) - free_item(items[i]); - free(items); - free(itrows[0]); - free(itrows); + endloop: erase(); } -void showBrowser(void) { - bcur = dat.sub; - bgraph = 1; - helpwin = 0; - while(bcur != NULL) - browseDir(); -} - - - diff --git a/src/calc.c b/src/calc.c index dcdd8a0..8bcd6d8 100644 --- a/src/calc.c +++ b/src/calc.c @@ -147,14 +147,9 @@ int calcUsage() { struct dirent *dr; struct stat fs; struct dir *d, *dirs[512]; /* 512 recursive directories should be enough for everyone! */ -#ifdef HAVE_GETTIMEOFDAY struct timeval tv; suseconds_t l; gettimeofday(&tv, (void *)NULL); l = (1000*(tv.tv_sec % 1000) + (tv.tv_usec / 1000)) / sdelay - 1; -#else - time_t tv; time_t l; - l = time(NULL) - 1; -#endif calc = calcWin(); wrefresh(calc); @@ -222,7 +217,9 @@ int calcUsage() { errno = 0; while((dr = readdir(dir)) != NULL) { f = dr->d_name; - if(f[0] == '.' && (f[1] == '\0' || (f[1] == '.' && f[2] == '\0'))) + if(f[0] == '.' && f[1] == '\0') + continue; + if(f[0] == '.' && f[1] == '.' && f[2] == '\0' && level == 1) continue; namelen = strlen(f); if(cdir1len+namelen+1 >= PATH_MAX) { @@ -238,12 +235,12 @@ int calcUsage() { d->parent = dirs[level-1]; dirs[level-1]->sub = d; dirs[level] = d; - sprintf(tmp, "%s/%s", cdir1, d->name); - /* check if file/dir is excluded */ - if(matchExclude(tmp)) { - d->flags = FF_EXL; + /* reference to parent directory, no need to stat */ + if(f[0] == '.' && f[1] == '.' && f[2] == '\0') { + d->flags = FF_PAR; continue; } + sprintf(tmp, "%s/%s", cdir1, d->name); /* stat */ if(lstat(tmp, &fs)) { staterr = 1; @@ -251,19 +248,26 @@ int calcUsage() { errno = 0; continue; } + /* check if file/dir is excluded */ + if(matchExclude(tmp)) + d->flags = FF_EXL; /* check filetype */ if(sflags & SF_SMFS && dev != fs.st_dev) d->flags |= FF_OTHFS; if(S_ISREG(fs.st_mode)) { d->flags |= FF_FILE; - for(i=level; i-->0;) - dirs[i]->files++; + if(!(d->flags & FF_EXL)) + for(i=level; i-->0;) + dirs[i]->files++; } else if(S_ISDIR(fs.st_mode)) { d->flags |= FF_DIR; - for(i=level; i-->0;) - dirs[i]->dirs++; + if(!(d->flags & FF_EXL)) + for(i=level; i-->0;) + dirs[i]->dirs++; } else d->flags |= FF_OTHER; + if(d->flags & FF_EXL) + continue; /* count size */ if(sflags & SF_AS) d->size = fs.st_size; @@ -274,6 +278,14 @@ int calcUsage() { dirs[i]->size += d->size; errno = 0; } + /* empty dir - remove the reference to the parent dir */ + if(dirs[level]->next == NULL && dirs[level]->prev == NULL) { + dirs[level]->parent->sub = NULL; + free(dirs[level]->name); + free(dirs[level]); + dirs[level] = NULL; + } + /* check for errors */ if(errno) direrr = 1; closedir(dir); @@ -285,14 +297,9 @@ int calcUsage() { /* show progress status */ showstatus: -#ifdef HAVE_GETTIMEOFDAY gettimeofday(&tv, (void *)NULL); tv.tv_usec = (1000*(tv.tv_sec % 1000) + (tv.tv_usec / 1000)) / sdelay; if(l == tv.tv_usec) goto newdir; -#else - time(&tv); - if(l == tv) goto newdir; -#endif mvwprintw(calc, 3, 15, "%-43s", cropdir(cdir, 43)); mvwprintw(calc, 2, 15, "%d", dat.files); mvwprintw(calc, 2, 30, "%d", dat.dirs); @@ -323,11 +330,7 @@ int calcUsage() { newdir: -#ifdef HAVE_GETTIMEOFDAY l = tv.tv_usec; -#else - l = tv; -#endif /* select new directory */ while(dirs[level] == NULL || !(dirs[level]->flags & FF_DIR) || dirs[level]->flags & FF_OTHFS || dirs[level]->flags & FF_EXL) { if(dirs[level] != NULL && dirs[level]->prev != NULL) diff --git a/src/delete.c b/src/delete.c new file mode 100644 index 0000000..ce62951 --- /dev/null +++ b/src/delete.c @@ -0,0 +1,242 @@ +/* ncdu - NCurses Disk Usage + + Copyright (c) 2007 Yoran Heling + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include "ncdu.h" + +suseconds_t lastupdate; + + +void drawConfirm(struct dir *del, int sel) { + WINDOW *cfm; + + cfm = newwin(6, 60, winrows/2-3, wincols/2-30); + box(cfm, 0, 0); + wattron(cfm, A_BOLD); + mvwaddstr(cfm, 0, 4, "Confirm delete"); + wattroff(cfm, A_BOLD); + + mvwprintw(cfm, 1, 2, "Are you sure you want to delete \"%s\"%c", + cropdir(del->name, 21), del->flags & FF_DIR ? ' ' : '?'); + if(del->flags & FF_DIR) + mvwprintw(cfm, 2, 18, "and all of its contents?"); + + if(sel == 0) + wattron(cfm, A_REVERSE); + mvwaddstr(cfm, 4, 15, "yes"); + wattroff(cfm, A_REVERSE); + if(sel == 1) + wattron(cfm, A_REVERSE); + mvwaddstr(cfm, 4, 24, "no"); + wattroff(cfm, A_REVERSE); + if(sel == 2) + wattron(cfm, A_REVERSE); + mvwaddstr(cfm, 4, 31, "don't ask me again"); + wattroff(cfm, A_REVERSE); + + wrefresh(cfm); + delwin(cfm); +} + + +/* show progress */ +void drawProgress(char *file) { + WINDOW *prg; + + prg = newwin(6, 60, winrows/2-3, wincols/2-30); + nodelay(prg, 1); + box(prg, 0, 0); + wattron(prg, A_BOLD); + mvwaddstr(prg, 0, 4, "Deleting..."); + wattroff(prg, A_BOLD); + + mvwaddstr(prg, 1, 2, cropdir(file, 47)); + mvwaddstr(prg, 5, 41, "Press q to abort"); + + wrefresh(prg); + delwin(prg); +} + + +/* show error dialog */ +void drawError(int sel, char *file) { + WINDOW *err; + + err = newwin(6, 60, winrows/2-3, wincols/2-30); + box(err, 0, 0); + wattron(err, A_BOLD); + mvwaddstr(err, 0, 4, "Error!"); + wattroff(err, A_BOLD); + + mvwprintw(err, 1, 2, "Can't delete %s:", cropdir(file, 42)); + mvwaddstr(err, 2, 4, strerror(errno)); + + if(sel == 0) + wattron(err, A_REVERSE); + mvwaddstr(err, 4, 14, "abort"); + wattroff(err, A_REVERSE); + if(sel == 1) + wattron(err, A_REVERSE); + mvwaddstr(err, 4, 23, "ignore"); + wattroff(err, A_REVERSE); + if(sel == 2) + wattron(err, A_REVERSE); + mvwaddstr(err, 4, 33, "ignore all"); + wattroff(err, A_REVERSE); + + wrefresh(err); + delwin(err); +} + + +struct dir *deleteDir(struct dir *dr) { + struct dir *nxt, *cur; + int ch, sel = 0; + char file[PATH_MAX]; + struct timeval tv; + + getpath(dr, file); + strcat(file, "/"); + strcat(file, dr->name); + + /* check for input or screen resizes */ + nodelay(stdscr, 1); + while((ch = getch()) != ERR) { + if(ch == 'q') + return(NULL); + if(ch == KEY_RESIZE) { + ncresize(); + drawBrowser(0); + drawProgress(file); + } + } + 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(file); + lastupdate = tv.tv_usec; + } + + /* do the actual deleting */ + if(dr->flags & FF_DIR) { + if(dr->sub != NULL) { + nxt = dr->sub; + while(nxt->prev != NULL) + nxt = nxt->prev; + while(nxt != NULL) { + cur = nxt; + nxt = cur->next; + if(cur->flags & FF_PAR) { + freedir(cur); + continue; + } + if(deleteDir(cur) == NULL) + return(NULL); + } + } + ch = rmdir(file); + } else + ch = unlink(file); + + /* error occured, ask user what to do */ + if(ch == -1 && !(sflags & SF_IGNE)) { + drawError(sel, file); + while((ch = getch())) { + switch(ch) { + case KEY_LEFT: + if(--sel < 0) + sel = 0; + break; + case KEY_RIGHT: + if(++sel > 2) + sel = 2; + break; + case 10: + if(sel == 0) + return(NULL); + if(sel == 2) + sflags |= SF_IGNE; + goto ignore; + case 'q': + return(NULL); + case KEY_RESIZE: + ncresize(); + drawBrowser(0); + break; + } + drawError(sel, file); + } + }; + ignore: + + return(freedir(dr)); +} + + +struct dir *showDelete(struct dir *dr) { + int ch, sel = 1; + struct dir *ret; + + /* confirm */ + if(sflags & SF_NOCFM) + goto doit; + + drawConfirm(dr, sel); + while((ch = getch())) { + switch(ch) { + case KEY_LEFT: + if(--sel < 0) + sel = 0; + break; + case KEY_RIGHT: + if(++sel > 2) + sel = 2; + break; + case 10: + if(sel == 1) + return(dr); + if(sel == 2) + sflags |= SF_NOCFM; + goto doit; + case 'q': + return(dr); + case KEY_RESIZE: + ncresize(); + drawBrowser(0); + break; + } + drawConfirm(dr, sel); + } + + doit: + lastupdate = 999; /* just some random high value as initialisation */ + + ret = deleteDir(dr); + + return(ret == NULL ? dr : ret); +} + diff --git a/src/help.c b/src/help.c new file mode 100644 index 0000000..98331f0 --- /dev/null +++ b/src/help.c @@ -0,0 +1,193 @@ +/* ncdu - NCurses Disk Usage + + Copyright (c) 2007 Yoran Heling + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include "ncdu.h" + + +void drawHelp(int page) { + WINDOW *hlp; + + hlp = newwin(15, 60, winrows/2-7, wincols/2-30); + box(hlp, 0, 0); + wattron(hlp, A_BOLD); + mvwaddstr(hlp, 0, 4, "ncdu help"); + wattroff(hlp, A_BOLD); + mvwaddstr(hlp, 13, 32, "Press any key to continue"); + + switch(page) { + case 1: + wattron(hlp, A_BOLD); + mvwaddstr(hlp, 1, 30, "1:Keys"); + wattroff(hlp, A_BOLD); + mvwaddstr(hlp, 1, 39, "2:Format"); + mvwaddstr(hlp, 1, 50, "3:About"); + wattron(hlp, A_BOLD); + mvwaddstr(hlp, 3, 7, "up/down"); + mvwaddstr(hlp, 4, 3, "right/enter"); + mvwaddstr(hlp, 5, 10, "left"); + mvwaddstr(hlp, 6, 11, "n/s"); + mvwaddch( hlp, 7, 13, 'd'); + mvwaddch( hlp, 8, 13, 't'); + mvwaddch( hlp, 9, 13, 'g'); + mvwaddch( hlp,10, 13, 'p'); + mvwaddch( hlp,11, 13, 'h'); + mvwaddch( hlp,12, 13, 'q'); + wattroff(hlp, A_BOLD); + mvwaddstr(hlp, 3, 16, "Cycle through the items"); + mvwaddstr(hlp, 4, 16, "Open directory"); + mvwaddstr(hlp, 5, 16, "Previous directory"); + mvwaddstr(hlp, 6, 16, "Sort by name or size (asc/desc)"); + mvwaddstr(hlp, 7, 16, "Delete selected file or directory"); + mvwaddstr(hlp, 8, 16, "Toggle dirs before files when sorting"); + mvwaddstr(hlp, 9, 16, "Show percentage and/or graph"); + mvwaddstr(hlp,10, 16, "Toggle between powers of 1000 and 1024"); + mvwaddstr(hlp,11, 16, "Show/hide hidden files"); + mvwaddstr(hlp,12, 16, "Quit ncdu"); + break; + case 2: + mvwaddstr(hlp, 1, 30, "1:Keys"); + wattron(hlp, A_BOLD); + mvwaddstr(hlp, 1, 39, "2:Format"); + wattroff(hlp, A_BOLD); + mvwaddstr(hlp, 1, 50, "3:About"); + wattron(hlp, A_BOLD); + mvwaddstr(hlp, 3, 3, "X [size] [file or directory]"); + wattroff(hlp, A_BOLD); + mvwaddstr(hlp, 5, 4, "The X is only present in the following cases:"); + wattron(hlp, A_BOLD); + mvwaddch(hlp, 6, 4, '!'); + mvwaddch(hlp, 7, 4, '.'); + mvwaddch(hlp, 8, 4, '>'); + mvwaddch(hlp, 9, 4, '<'); + mvwaddch(hlp,10, 4, '@'); + mvwaddch(hlp,11, 4, 'e'); + wattroff(hlp, A_BOLD); + mvwaddstr(hlp, 6, 7, "An error occured while reading this directory"); + mvwaddstr(hlp, 7, 7, "An error occured while reading a subdirectory"); + mvwaddstr(hlp, 8, 7, "File or directory is excluded from the statistics"); + mvwaddstr(hlp, 9, 7, "Directory was on an other filesystem"); + mvwaddstr(hlp,10, 7, "This is not a file nor a dir (symlink, socket, ...)"); + mvwaddstr(hlp,11, 7, "Empty directory"); + break; + case 3: + /* Indeed, too much spare time */ + mvwaddstr(hlp, 1, 30, "1:Keys"); + mvwaddstr(hlp, 1, 39, "2:Format"); + wattron(hlp, A_BOLD); + mvwaddstr(hlp, 1, 50, "3:About"); + wattroff(hlp, A_BOLD); + wattron(hlp, A_REVERSE); +#define x 12 +#define y 4 + /* N */ + mvwaddstr(hlp, y+0, x+0, " "); + mvwaddstr(hlp, y+1, x+0, " "); + mvwaddstr(hlp, y+2, x+0, " "); + mvwaddstr(hlp, y+3, x+0, " "); + mvwaddstr(hlp, y+4, x+0, " "); + mvwaddstr(hlp, y+1, x+4, " "); + mvwaddstr(hlp, y+2, x+4, " "); + mvwaddstr(hlp, y+3, x+4, " "); + mvwaddstr(hlp, y+4, x+4, " "); + /* C */ + mvwaddstr(hlp, y+0, x+8, " "); + mvwaddstr(hlp, y+1, x+8, " "); + mvwaddstr(hlp, y+2, x+8, " "); + mvwaddstr(hlp, y+3, x+8, " "); + mvwaddstr(hlp, y+4, x+8, " "); + /* D */ + mvwaddstr(hlp, y+0, x+19, " "); + mvwaddstr(hlp, y+1, x+19, " "); + mvwaddstr(hlp, y+2, x+15, " "); + mvwaddstr(hlp, y+3, x+15, " "); + mvwaddstr(hlp, y+3, x+19, " "); + mvwaddstr(hlp, y+4, x+15, " "); + /* U */ + mvwaddstr(hlp, y+0, x+23, " "); + mvwaddstr(hlp, y+1, x+23, " "); + mvwaddstr(hlp, y+2, x+23, " "); + mvwaddstr(hlp, y+3, x+23, " "); + mvwaddstr(hlp, y+0, x+27, " "); + mvwaddstr(hlp, y+1, x+27, " "); + mvwaddstr(hlp, y+2, x+27, " "); + mvwaddstr(hlp, y+3, x+27, " "); + mvwaddstr(hlp, y+4, x+23, " "); + wattroff(hlp, A_REVERSE); + mvwaddstr(hlp, y+0, x+30, "NCurses"); + mvwaddstr(hlp, y+1, x+30, "Disk"); + mvwaddstr(hlp, y+2, x+30, "Usage"); + mvwprintw(hlp, y+4, x+30, "%s", PACKAGE_VERSION); + mvwaddstr(hlp,10, 7, "Written by Yoran Heling "); + mvwaddstr(hlp,11, 16, "http://dev.yorhel.nl/ncdu/"); + break; + case 4: + mvwaddstr(hlp, 1, 30, "1:Keys"); + mvwaddstr(hlp, 1, 39, "2:Format"); + mvwaddstr(hlp, 1, 50, "3:About"); + mvwaddstr(hlp, 3, 3, "There is no fourth window, baka~~"); + } + wrefresh(hlp); + delwin(hlp); /* no need to use it anymore - free it */ +} + + +void showHelp(void) { + int p = 1, ch; + + drawHelp(p); + while((ch = getch())) { + switch(ch) { + case '1': + p = 1; + break; + case '2': + p = 2; + break; + case '3': + p = 3; + break; + case '4': + p = 4; + break; + case KEY_RIGHT: + if(++p > 4) + p = 4; + break; + case KEY_LEFT: + if(--p < 1) + p = 1; + break; + case KEY_RESIZE: + ncresize(); + drawBrowser(0); + break; + default: + return; + } + drawHelp(p); + } +} + + diff --git a/src/main.c b/src/main.c index 6ed98b7..0bf11bb 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,6 @@ int main(int argc, char **argv) { keypad(stdscr, TRUE); ncresize(); - bgraph = 0; if(gd && settingsWin()) goto mainend; while((r = calcUsage()) != 0) { if(r == 1 && settingsWin()) goto mainend; @@ -57,3 +56,4 @@ int main(int argc, char **argv) { return(0); } + diff --git a/src/ncdu.h b/src/ncdu.h index f4ccbed..f1ad29d 100644 --- a/src/ncdu.h +++ b/src/ncdu.h @@ -41,11 +41,7 @@ #include #include #include -#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY) -# include -#else -# include -#endif +#include #include /* PATH_MAX 260 on Cygwin is too small for /proc/registry */ @@ -92,6 +88,7 @@ #define FF_SERR 32 /* error in subdirectory */ #define FF_BSEL 64 /* selected */ #define FF_EXL 128 /* excluded using exlude patterns */ +#define FF_PAR 256 /* reference to parent directory (hack) */ /* Settings Flags (int sflags) */ #define SF_SMFS 1 /* same filesystem */ @@ -107,7 +104,7 @@ #define BF_FILES 4 #define BF_NDIRF 32 /* Normally, dirs before files, setting this disables it */ #define BF_DESC 64 -#define BF_HIDE 128 /* don't show hidden files... doesn't have anything to do with sorting though */ +#define BF_HIDE 128 /* don't show hidden files... */ /* @@ -118,7 +115,7 @@ struct dir { char *name; off_t size; unsigned int files, dirs; - unsigned char flags; + unsigned short flags; }; @@ -151,7 +148,12 @@ extern int settingsWin(void); /* calc.c */ extern int calcUsage(); /* browser.c */ +extern void drawBrowser(int); extern void showBrowser(void); +/* help.c */ +extern void showHelp(void); +/* delete.c */ +extern struct dir *showDelete(struct dir *); /* exclude.c */ extern void addExclude(char *); extern int addExcludeFile(char *);