2007-07-20 03:15:46 -08:00
|
|
|
/* 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"
|
|
|
|
|
|
|
|
|
|
char cropsizedat[8];
|
2007-08-01 07:01:42 -08:00
|
|
|
char fullsizedat[20]; /* max: 999.999.999.999.999 */
|
2007-07-20 03:15:46 -08:00
|
|
|
char cropdirdat[4096];
|
|
|
|
|
|
|
|
|
|
char *cropdir(const char *from, int s) {
|
|
|
|
|
int i, j, o = strlen(from);
|
|
|
|
|
if(o < s) {
|
|
|
|
|
strcpy(cropdirdat, from);
|
|
|
|
|
return(cropdirdat);
|
|
|
|
|
}
|
|
|
|
|
j=s/2-3;
|
|
|
|
|
for(i=0; i<j; i++)
|
|
|
|
|
cropdirdat[i] = from[i];
|
|
|
|
|
cropdirdat[i] = '.';
|
|
|
|
|
cropdirdat[++i] = '.';
|
|
|
|
|
cropdirdat[++i] = '.';
|
|
|
|
|
j=o-s;
|
|
|
|
|
while(++i<s)
|
|
|
|
|
cropdirdat[i] = from[j+i];
|
|
|
|
|
cropdirdat[s] = '\0';
|
|
|
|
|
return(cropdirdat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* return value is always xxx.xXB = 8 bytes (including \0) */
|
|
|
|
|
char *cropsize(const off_t from) {
|
|
|
|
|
float r = from;
|
|
|
|
|
char c = ' ';
|
|
|
|
|
if(sflags & SF_SI) {
|
|
|
|
|
if(r < 1000.0f) { }
|
|
|
|
|
else if(r < 1000e3f) { c = 'k'; r/=1000.0f; }
|
|
|
|
|
else if(r < 1000e6f) { c = 'M'; r/=1000e3f; }
|
|
|
|
|
else if(r < 1000e9f) { c = 'G'; r/=1000e6f; }
|
|
|
|
|
else { c = 'T'; r/=1000e9f; }
|
|
|
|
|
} else {
|
|
|
|
|
if(r < 1000.0f) { }
|
|
|
|
|
else if(r < 1023e3f) { c = 'k'; r/=1024.0f; }
|
|
|
|
|
else if(r < 1023e6f) { c = 'M'; r/=1048576.0f; }
|
|
|
|
|
else if(r < 1023e9f) { c = 'G'; r/=1073741824.0f; }
|
|
|
|
|
else { c = 'T'; r/=1099511627776.0f; }
|
|
|
|
|
}
|
|
|
|
|
sprintf(cropsizedat, "%5.1f%cB", r, c);
|
|
|
|
|
return(cropsizedat);
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-01 07:01:42 -08:00
|
|
|
/* returns integer as a string with thousand seperators
|
|
|
|
|
BUG: Uses a dot as seperator, ignores current locale */
|
|
|
|
|
char *fullsize(const off_t from) {
|
|
|
|
|
char tmp[20];
|
2007-08-16 00:36:58 -08:00
|
|
|
off_t n = from;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
/* the K&R method - more portable than sprintf with %lld */
|
|
|
|
|
i = 0;
|
|
|
|
|
do {
|
|
|
|
|
tmp[i++] = n % 10 + '0';
|
|
|
|
|
} while((n /= 10) > 0);
|
|
|
|
|
tmp[i] = '\0';
|
|
|
|
|
|
|
|
|
|
/* reverse and add thousand seperators */
|
|
|
|
|
j = 0;
|
|
|
|
|
while(i--) {
|
|
|
|
|
fullsizedat[j++] = tmp[i];
|
|
|
|
|
if(i != 0 && i%3 == 0)
|
|
|
|
|
fullsizedat[j++] = '.';
|
2007-08-01 07:01:42 -08:00
|
|
|
}
|
2007-08-16 00:36:58 -08:00
|
|
|
fullsizedat[j] = '\0';
|
|
|
|
|
|
|
|
|
|
return(fullsizedat);
|
2007-08-01 07:01:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
void ncresize(void) {
|
|
|
|
|
int ch;
|
|
|
|
|
getmaxyx(stdscr, winrows, wincols);
|
|
|
|
|
while(!(sflags & SF_IGNS) && (winrows < 17 || wincols < 60)) {
|
|
|
|
|
erase();
|
|
|
|
|
mvaddstr(0, 0, "Warning: terminal too small,");
|
|
|
|
|
mvaddstr(1, 1, "please either resize your terminal,");
|
|
|
|
|
mvaddstr(2, 1, "press i to ignore, or press q to quit.");
|
|
|
|
|
touchwin(stdscr);
|
|
|
|
|
refresh();
|
|
|
|
|
nodelay(stdscr, 0);
|
|
|
|
|
ch = getch();
|
|
|
|
|
getmaxyx(stdscr, winrows, wincols);
|
|
|
|
|
if(ch == 'q') {
|
|
|
|
|
erase();
|
|
|
|
|
refresh();
|
|
|
|
|
endwin();
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
if(ch == 'i')
|
|
|
|
|
sflags |= SF_IGNS;
|
|
|
|
|
}
|
2007-07-26 04:56:24 -08:00
|
|
|
erase();
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-08-16 00:36:58 -08:00
|
|
|
/* Instead of using several ncurses windows, we only draw to stdscr.
|
|
|
|
|
* the functions nccreate, ncprint and the macros ncaddstr and ncaddch
|
|
|
|
|
* mimic the behaviour of ncurses windows.
|
|
|
|
|
* This works better than using ncurses windows when all windows are
|
|
|
|
|
* created in the correct order: it paints directly on stdscr, so
|
|
|
|
|
* wrefresh, wnoutrefresh and other window-specific functions are not
|
|
|
|
|
* necessary.
|
|
|
|
|
* Also, this method doesn't require any window objects, as you can
|
|
|
|
|
* only create one window at a time.
|
|
|
|
|
*
|
|
|
|
|
* This function creates a new window in the center of the screen
|
|
|
|
|
* with a border and a title.
|
|
|
|
|
*/
|
|
|
|
|
void nccreate(int height, int width, char *title) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
subwinr = winrows/2-height/2;
|
|
|
|
|
subwinc = wincols/2-width/2;
|
|
|
|
|
|
|
|
|
|
/* clear window */
|
|
|
|
|
for(i=0; i<height; i++)
|
|
|
|
|
mvhline(subwinr+i, subwinc, ' ', width);
|
|
|
|
|
|
|
|
|
|
/* box() only works around curses windows, so create our own */
|
|
|
|
|
move(subwinr, subwinc);
|
|
|
|
|
addch(ACS_ULCORNER);
|
|
|
|
|
for(i=0; i<width-2; i++)
|
|
|
|
|
addch(ACS_HLINE);
|
|
|
|
|
addch(ACS_URCORNER);
|
|
|
|
|
|
|
|
|
|
move(subwinr+height-1, subwinc);
|
|
|
|
|
addch(ACS_LLCORNER);
|
|
|
|
|
for(i=0; i<width-2; i++)
|
|
|
|
|
addch(ACS_HLINE);
|
|
|
|
|
addch(ACS_LRCORNER);
|
|
|
|
|
|
|
|
|
|
mvvline(subwinr+1, subwinc, ACS_VLINE, height-2);
|
|
|
|
|
mvvline(subwinr+1, subwinc+width-1, ACS_VLINE, height-2);
|
|
|
|
|
|
|
|
|
|
/* title */
|
|
|
|
|
attron(A_BOLD);
|
|
|
|
|
mvaddstr(subwinr, subwinc+4, title);
|
|
|
|
|
attroff(A_BOLD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ncprint(int r, int c, char *fmt, ...) {
|
|
|
|
|
va_list arg;
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
|
move(subwinr+r, subwinc+c);
|
|
|
|
|
vw_printw(stdscr, fmt, arg);
|
|
|
|
|
va_end(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
|
|
|
|
|
void freedir_rec(struct dir *dr) {
|
|
|
|
|
struct dir *tmp, *tmp2;
|
|
|
|
|
tmp2 = dr;
|
|
|
|
|
while((tmp = tmp2) != NULL) {
|
|
|
|
|
if(tmp->sub) freedir_rec(tmp->sub);
|
|
|
|
|
free(tmp->name);
|
|
|
|
|
tmp2 = tmp->next;
|
|
|
|
|
free(tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* remove a file/directory from the in-memory map */
|
|
|
|
|
struct dir *freedir(struct dir *dr) {
|
|
|
|
|
struct dir *tmp, *cur;
|
|
|
|
|
|
|
|
|
|
/* update sizes of parent directories */
|
|
|
|
|
tmp = dr;
|
|
|
|
|
while((tmp = tmp->parent) != NULL) {
|
|
|
|
|
tmp->size -= dr->size;
|
2007-08-12 01:52:24 -08:00
|
|
|
tmp->asize -= dr->asize;
|
2007-08-01 05:17:26 -08:00
|
|
|
tmp->items -= dr->items+1;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* free dr->sub recursive */
|
|
|
|
|
if(dr->sub) freedir_rec(dr->sub);
|
|
|
|
|
|
|
|
|
|
/* update references */
|
|
|
|
|
cur = NULL;
|
2007-07-26 08:37:33 -08:00
|
|
|
if(dr->parent) {
|
|
|
|
|
/* item is at the top of the dir, refer to next item */
|
|
|
|
|
if(dr->parent->sub == dr) {
|
2007-07-20 03:15:46 -08:00
|
|
|
dr->parent->sub = dr->next;
|
2007-07-26 08:37:33 -08:00
|
|
|
cur = dr->next;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2007-07-26 08:37:33 -08:00
|
|
|
/* else, get the previous item and update it's "next"-reference */
|
|
|
|
|
else
|
|
|
|
|
for(tmp = dr->parent->sub; tmp != NULL; tmp = tmp->next)
|
|
|
|
|
if(tmp->next == dr) {
|
|
|
|
|
tmp->next = dr->next;
|
|
|
|
|
cur = tmp;
|
|
|
|
|
}
|
2007-08-12 01:52:24 -08:00
|
|
|
/* no previous item, refer to parent dir */
|
|
|
|
|
if(cur == NULL && dr->parent->parent)
|
|
|
|
|
cur = dr->parent;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2007-07-26 08:37:33 -08:00
|
|
|
if(cur != NULL)
|
|
|
|
|
cur->flags |= FF_BSEL;
|
2007-07-20 03:15:46 -08:00
|
|
|
|
|
|
|
|
free(dr->name);
|
|
|
|
|
free(dr);
|
|
|
|
|
|
|
|
|
|
return(cur);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *getpath(struct dir *cur, char *to) {
|
2007-07-26 08:37:33 -08:00
|
|
|
struct dir *d, *list[100];
|
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
|
|
for(d = cur; (d = d->parent) != NULL; )
|
|
|
|
|
list[c++] = d;
|
|
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
to[0] = '\0';
|
2007-07-26 08:37:33 -08:00
|
|
|
while(c--) {
|
2007-08-05 03:12:40 -08:00
|
|
|
if(list[c]->parent && list[c]->parent->name[strlen(list[c]->parent->name)-1] != '/')
|
2007-07-20 03:15:46 -08:00
|
|
|
strcat(to, "/");
|
2007-07-26 08:37:33 -08:00
|
|
|
strcat(to, list[c]->name);
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2007-07-26 08:37:33 -08:00
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
return to;
|
|
|
|
|
}
|