summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/Makefile.in405
-rw-r--r--src/browser.c612
-rw-r--r--src/calc.c326
-rw-r--r--src/main.c59
-rw-r--r--src/ncdu.h145
-rw-r--r--src/settings.c232
-rw-r--r--src/util.c166
8 files changed, 1950 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..1def5a6
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,5 @@
+bin_PROGRAMS = ncdu
+
+ncdu_SOURCES = browser.c calc.c main.c settings.c util.c
+
+noinst_HEADERS = ncdu.h
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..224fab4
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,405 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+bin_PROGRAMS = ncdu$(EXEEXT)
+subdir = src
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am_ncdu_OBJECTS = browser.$(OBJEXT) calc.$(OBJEXT) main.$(OBJEXT) \
+ settings.$(OBJEXT) util.$(OBJEXT)
+ncdu_OBJECTS = $(am_ncdu_OBJECTS)
+ncdu_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(ncdu_SOURCES)
+DIST_SOURCES = $(ncdu_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+ncdu_SOURCES = browser.c calc.c main.c settings.c util.c
+noinst_HEADERS = ncdu.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+ncdu$(EXEEXT): $(ncdu_OBJECTS) $(ncdu_DEPENDENCIES)
+ @rm -f ncdu$(EXEEXT)
+ $(LINK) $(ncdu_LDFLAGS) $(ncdu_OBJECTS) $(ncdu_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/browser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/calc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settings.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/browser.c b/src/browser.c
new file mode 100644
index 0000000..0740002
--- /dev/null
+++ b/src/browser.c
@@ -0,0 +1,612 @@
+/* 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"
+
+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));
+}
+
+
+
+int cmp(struct dir *x, struct dir *y) {
+ struct dir *a, *b;
+ int r = 0;
+ if(bflags & BF_DESC) {
+ a = y; b = x;
+ } else {
+ b = y; a = x;
+ }
+ if(!(bflags & BF_NDIRF) && y->flags & FF_DIR && !(x->flags & FF_DIR))
+ r = 1;
+ else if(!(bflags & BF_NDIRF) && !(y->flags & FF_DIR) && x->flags & FF_DIR)
+ r = -1;
+ else if(bflags & BF_NAME)
+ r = strcmp(a->name, b->name);
+ else if(bflags & BF_FILES)
+ r = (a->files - b->files);
+ if(r == 0)
+ r = a->size > b->size ? 1 : (a->size == b->size ? 0 : -1);
+ return(r);
+}
+
+/* Mergesort algorithm, many thanks to
+ http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
+*/
+struct dir *sortFiles(struct dir *list) {
+ struct dir *p, *q, *e, *tail;
+ int insize, nmerges, psize, qsize, i;
+
+ while(list->prev != NULL)
+ list = list->prev;
+ insize = 1;
+ while(1) {
+ p = list;
+ list = NULL;
+ tail = NULL;
+ nmerges = 0;
+ while(p) {
+ nmerges++;
+ q = p;
+ psize = 0;
+ for(i=0; i<insize; i++) {
+ psize++;
+ q = q->next;
+ if(!q) break;
+ }
+ qsize = insize;
+ while(psize > 0 || (qsize > 0 && q)) {
+ if(psize == 0) {
+ e = q; q = q->next; qsize--;
+ } else if(qsize == 0 || !q) {
+ e = p; p = p->next; psize--;
+ } else if(cmp(p,q) <= 0) {
+ e = p; p = p->next; psize--;
+ } else {
+ e = q; q = q->next; qsize--;
+ }
+ if(tail) tail->next = e;
+ else list = e;
+ e->prev = tail;
+ tail = e;
+ }
+ p = q;
+ }
+ tail->next = NULL;
+ if(nmerges <= 1)
+ return list;
+ insize *= 2;
+ }
+}
+
+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, '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, "Directory was on an other filesystem");
+ mvwaddstr(hlp, 9, 7, "This is not a file nor a dir (symlink, socket, ...)");
+ mvwaddstr(hlp,10, 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 <projects@yorhel.nl>");
+ 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) {
+ int i, c = (int) (((float) size / (float) max) * 10.0f);
+ for(i=0; i<10; i++)
+ graphdat[i] = i < c ? '#' : ' ';
+ graphdat[10] = '\0';
+ return graphdat;
+}
+
+
+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;
+
+ if(bcur->parent == NULL) {
+ if(bcur->sub == NULL) {
+ erase();
+ refresh();
+ endwin();
+ printf("No items to display...\n");
+ exit(0);
+ } else
+ bcur = bcur->sub;
+ }
+
+
+ erase();
+ attron(A_REVERSE);
+ for(i=0; i<wincols;i++) {
+ mvaddch(0, i, ' ');
+ mvaddch(winrows-1, i, ' ');
+ }
+ mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ? for help", PACKAGE_NAME, PACKAGE_VERSION);
+ mvprintw(winrows-1, 0, " Total size: %s Files: %-6d Dirs: %-6d",
+ cropsize(bcur->parent->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;
+ }
+
+ 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; i<fls; i++)
+ itrows[i] = itrows[0] + i*wincols;
+
+ 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; i<s; i++)
+ tmp2[i] = ' ';
+ tmp2[i++] = '\0';
+ strcat(tmp2, "/..");
+ items[0] = new_item(tmp2, 0);
+ set_item_userptr(items[0], NULL);
+ i = 1;
+ } else
+ i = 0;
+
+ d = bcur; s=-1;
+ while(d != NULL) {
+ if(bflags & BF_HIDE && d->name[0] == '.') {
+ d = d->next;
+ continue;
+ }
+ ct = d->flags & FF_ERR ? '!' : d->flags & FF_SERR ? '.' : d->flags & FF_OTHFS ? '>' :
+ d->flags & FF_OTHER ? '@' : d->flags & FF_DIR && d->sub == NULL ? 'e' : ' ';
+ switch(bgraph) {
+ case 0:
+ sprintf(itrows[i], tmp, ct, cropsize(d->size),
+ d->flags & FF_DIR ? '/' : ' ', cropdir(d->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));
+ 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));
+ 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));
+ }
+
+ 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++;
+ }
+ 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; i<s; i++)
+ menu_driver(menu, REQ_DOWN_ITEM);
+
+ d = bcur; bf = bflags;
+ refresh();
+
+ if(helpwin > 0 && helpScreen() == 1) goto endbrowse;
+ while((ch = getch())) {
+ 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;
+ 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;
+ break;
+ case KEY_RESIZE:
+ ncresize();
+ goto endbrowse;
+ case KEY_LEFT:
+ if(bcur->parent->parent != NULL)
+ bcur = bcur->parent;
+ else
+ bcur = d;
+ goto endbrowse;
+ case 'n':
+ if(bflags & BF_NAME)
+ toggle(bflags, BF_DESC);
+ else
+ bflags = (bflags & BF_HIDE) + (bflags & BF_NDIRF) + BF_NAME;
+ goto endbrowse;
+ case 's':
+ if(bflags & BF_SIZE)
+ toggle(bflags, BF_DESC);
+ else
+ bflags = (bflags & BF_HIDE) + (bflags & BF_NDIRF) + BF_SIZE;
+ goto endbrowse;
+ case 'p':
+ toggle(sflags, SF_SI);
+ goto endbrowse;
+ case 'h':
+ toggle(bflags, BF_HIDE);
+ goto endbrowse;
+ case 't':
+ toggle(bflags, BF_NDIRF);
+ goto endbrowse;
+ case 'g':
+ if(++bgraph > 3) bgraph = 0;
+ goto endbrowse;
+ 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;
+ }
+ 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);
+ 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
new file mode 100644
index 0000000..6bca13a
--- /dev/null
+++ b/src/calc.c
@@ -0,0 +1,326 @@
+/* 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"
+
+
+/* My own implementation of realpath()
+ - assumes that *every* possible path fits in PATH_MAX bytes
+ - does not set errno on error
+ - has not yet been fully tested
+*/
+char *rpath(const char *from, char *to) {
+ char tmp[PATH_MAX], cwd[PATH_MAX], cur[PATH_MAX], app[PATH_MAX];
+ int i, j, l, k, last, ll = 0;
+ struct stat st;
+
+ getcwd(cwd, PATH_MAX);
+ strcpy(cur, from);
+ app[0] = 0;
+
+ loop:
+ /* not an absolute path, add current directory */
+ if(cur[0] != '/') {
+ if(!(cwd[0] == '/' && cwd[1] == 0))
+ strcpy(tmp, cwd);
+ else
+ tmp[0] = 0;
+ strcat(tmp, "/");
+ strcat(tmp, cur);
+ } else
+ strcpy(tmp, cur);
+
+ /* now fix things like '.' and '..' */
+ i = j = last = 0;
+ l = strlen(tmp);
+ while(1) {
+ if(tmp[i] == 0)
+ break;
+ /* . */
+ if(l >= i+2 && tmp[i] == '/' && tmp[i+1] == '.' && (tmp[i+2] == 0 || tmp[i+2] == '/')) {
+ i+= 2;
+ continue;
+ }
+ /* .. */
+ if(l >= i+3 && tmp[i] == '/' && tmp[i+1] == '.' && tmp[i+2] == '.' && (tmp[i+3] == 0 || tmp[i+3] == '/')) {
+ for(k=j; --k>0;)
+ if(to[k] == '/' && k != j-1)
+ break;
+ j -= j-k;
+ if(j < 1) j = 1;
+ i += 3;
+ continue;
+ }
+ /* remove double slashes */
+ if(tmp[i] == '/' && i>0 && tmp[i-1] == '/') {
+ i++;
+ continue;
+ }
+ to[j++] = tmp[i++];
+ }
+ /* remove leading slashes */
+ while(--j > 0) {
+ if(to[j] != '/')
+ break;
+ }
+ to[j+1] = 0;
+ /* append 'app' */
+ if(app[0] != 0)
+ strcat(to, app);
+
+ j = strlen(to);
+ /* check for symlinks */
+ for(i=1; i<=j; i++) {
+ if(to[i] == '/' || to[i] == 0) {
+ strncpy(tmp, to, i);
+ tmp[i] = 0;
+ if(lstat(tmp, &st) < 0)
+ return(NULL);
+ if(S_ISLNK(st.st_mode)) {
+ if(++ll > LINK_MAX || (k = readlink(tmp, cur, PATH_MAX)) < 0)
+ return(NULL);
+ cur[k] = 0;
+ if(to[i] != 0)
+ strcpy(app, &to[i]);
+ strcpy(cwd, tmp);
+ for(k=strlen(cwd); --k>0;)
+ if(cwd[k] == '/')
+ break;
+ cwd[k] = 0;
+ goto loop;
+ }
+ if(!S_ISDIR(st.st_mode))
+ return(NULL);
+ }
+ }
+
+ return(to);
+}
+
+
+WINDOW* calcWin() {
+ WINDOW *calc;
+ calc = newwin(10, 60, winrows/2 - 5, wincols/2 - 30);
+ keypad(calc, TRUE);
+ box(calc, 0, 0);
+ wattron(calc, A_BOLD);
+ mvwaddstr(calc, 0, 4, "Calculating...");
+ wattroff(calc, A_BOLD);
+ mvwaddstr(calc, 2, 2, "Total files:");
+ mvwaddstr(calc, 2, 24, "dirs:");
+ mvwaddstr(calc, 2, 39, "size:");
+ mvwaddstr(calc, 3, 2, "Current dir:");
+ mvwaddstr(calc, 8, 43, "Press q to quit");
+ return(calc);
+}
+
+int calcUsage() {
+ WINDOW *calc;
+ DIR *dir;
+ char antext[15] = "Calculating...";
+ int ch, anpos = 0, level = 0, i;
+ char cdir[PATH_MAX], emsg[PATH_MAX], tmp[PATH_MAX], err = 0, *f;
+ dev_t dev;
+ 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);
+ tv.tv_usec = (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);
+
+ memset(dirs, 0, sizeof(struct dir *)*512);
+ level = 0;
+ dirs[level] = &dat;
+ memset(&dat, 0, sizeof(dat));
+
+ if(rpath(sdir, tmp) == NULL || stat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
+ mvwaddstr(calc, 8, 1, " ");
+ wattron(calc, A_BOLD);
+ mvwaddstr(calc, 5, 2, "Error:");
+ wattroff(calc, A_BOLD);
+ mvwprintw(calc, 5, 9, "could not open %s", cropdir(tmp, 34));
+ mvwaddstr(calc, 6, 3, "press any key to continue...");
+ wrefresh(calc);
+ wgetch(calc);
+ delwin(calc);
+ return(1);
+ }
+ if(sflags & SF_AS) dat.size = fs.st_size;
+ else dat.size = fs.st_blocks * 512;
+ if(sflags & SF_SMFS) dev = fs.st_dev;
+ dat.name = malloc(strlen(tmp)+1);
+ strcpy(dat.name, tmp);
+
+ nodelay(calc, 1);
+ /* main loop */
+ while((ch = wgetch(calc)) != 'q') {
+ if(ch == KEY_RESIZE) {
+ delwin(calc);
+ ncresize();
+ calc = calcWin();
+ nodelay(calc, 1);
+ erase();
+ refresh();
+ }
+
+ /* calculate full path of the dir */
+ cdir[0] = '\0';
+ for(i=0; i<=level; i++) {
+ if(i > 0 && !(i == 1 && dat.name[strlen(dat.name)-1] == '/')) strcat(cdir, "/");
+ strcat(cdir, dirs[i]->name);
+ }
+ /* opendir */
+ if((dir = opendir(cdir)) == NULL) {
+ dirs[level]->flags |= FF_ERR;
+ for(i=level; i-->0;)
+ dirs[i]->flags |= FF_SERR;
+ err = 1;
+ strcpy(emsg, cdir);
+ dirs[++level] = NULL;
+ goto showstatus;
+ }
+ dirs[++level] = NULL;
+ /* readdir */
+ errno = 0;
+ while((dr = readdir(dir)) != NULL) {
+ f = dr->d_name;
+ if(f[0] == '.' && (f[1] == '\0' || (f[1] == '.' && f[2] == '\0')))
+ continue;
+ d = calloc(sizeof(struct dir), 1);
+ d->name = malloc(strlen(f)+1);
+ strcpy(d->name, f);
+ if(dirs[level] != NULL) dirs[level]->next = d;
+ d->prev = dirs[level];
+ d->parent = dirs[level-1];
+ dirs[level-1]->sub = d;
+ dirs[level] = d;
+ sprintf(tmp, "%s/%s", cdir, d->name);
+ lstat(tmp, &fs);
+ /* 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++;
+ } else if(S_ISDIR(fs.st_mode)) {
+ d->flags |= FF_DIR;
+ for(i=level; i-->0;)
+ dirs[i]->dirs++;
+ } else
+ d->flags |= FF_OTHER;
+ /* count size */
+ if(sflags & SF_AS)
+ d->size = fs.st_size;
+ else
+ d->size = fs.st_blocks * 512;
+ if(d->flags & FF_OTHFS) d->size = 0;
+ for(i=level; i-->0;)
+ dirs[i]->size += d->size;
+ }
+ closedir(dir);
+ if(errno) {
+ dirs[level-1]->flags |= FF_ERR;
+ for(i=level-1; i-->0;)
+ dirs[i]->flags |= FF_SERR;
+ }
+
+ /* 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);
+ mvwaddstr(calc, 2, 45, cropsize(dat.size));
+
+ if(err == 1) {
+ wattron(calc, A_BOLD);
+ mvwaddstr(calc, 5, 2, "Warning:");
+ wattroff(calc, A_BOLD);
+ mvwprintw(calc, 5, 11, "could not open %-32s", cropdir(emsg, 32));
+ mvwaddstr(calc, 6, 3, "some directory sizes may not be correct");
+ }
+
+ /* animation */
+ if(sdelay < 1000) {
+ if(++anpos == 28) anpos = 0;
+ mvwaddstr(calc, 8, 3, " ");
+ if(anpos < 14)
+ for(i=0; i<=anpos; i++)
+ mvwaddch(calc, 8, i+3, antext[i]);
+ else
+ for(i=13; i>anpos-14; i--)
+ mvwaddch(calc, 8, i+3, antext[i]);
+ } else
+ mvwaddstr(calc, 8, 3, antext);
+ wmove(calc, 8, 58);
+ wrefresh(calc);
+
+ /* select new directory */
+ newdir:
+#ifdef HAVE_GETTIMEOFDAY
+ l = tv.tv_usec;
+#else
+ l = tv;
+#endif
+ while(dirs[level] == NULL || !(dirs[level]->flags & FF_DIR) || dirs[level]->flags & FF_OTHFS) {
+ if(dirs[level] != NULL && dirs[level]->prev != NULL)
+ dirs[level] = dirs[level]->prev;
+ else {
+ while(level-- > 0) {
+ if(dirs[level]->prev != NULL) {
+ dirs[level] = dirs[level]->prev;
+ break;
+ }
+ }
+ if(level < 1) goto endloop;
+ }
+ }
+ }
+ endloop:
+ nodelay(calc, 0);
+ delwin(calc);
+ erase();
+ refresh();
+ if(ch == 'q')
+ return(2);
+ return(0);
+}
+
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..6ed98b7
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,59 @@
+/* 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"
+
+/* check ncdu.h what these are for */
+struct dir dat;
+int winrows, wincols;
+char sdir[PATH_MAX];
+int sflags, bflags, sdelay, bgraph;
+
+/* main program */
+int main(int argc, char **argv) {
+ int r, gd;
+ gd = settingsCli(argc, argv);
+ initscr();
+ cbreak();
+ noecho();
+ curs_set(0);
+ keypad(stdscr, TRUE);
+ ncresize();
+
+ bgraph = 0;
+ if(gd && settingsWin()) goto mainend;
+ while((r = calcUsage()) != 0) {
+ if(r == 1 && settingsWin()) goto mainend;
+ else if(r == 2) goto mainend;
+ }
+ showBrowser();
+
+ mainend:
+ erase();
+ refresh();
+ endwin();
+
+ return(0);
+}
diff --git a/src/ncdu.h b/src/ncdu.h
new file mode 100644
index 0000000..1960877
--- /dev/null
+++ b/src/ncdu.h
@@ -0,0 +1,145 @@
+/* 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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <curses.h>
+#include <form.h>
+#include <menu.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+#include <dirent.h>
+
+/* get PATH_MAX */
+#ifndef PATH_MAX
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# define PATH_MAX 4096
+# endif
+#endif
+/* and LINK_MAX */
+#ifndef LINK_MAX
+# ifdef _POSIX_LINK_MAX
+# define LINK_MAX _POSIX_LINK_MAX
+# else
+# define LINK_MAX 32
+# endif
+#endif
+/* check for S_ISLNK */
+#ifndef S_ISLNK
+# ifndef S_IFLNK
+# define S_IFLNK 0120000
+# endif
+# define S_ISLNK(x) (x & S_IFLNK)
+#endif
+
+/*
+ * G L O B A L F L A G S
+ */
+/* File Flags (struct dir -> flags) */
+#define FF_DIR 1
+#define FF_FILE 2
+#define FF_OTHER 4
+#define FF_ERR 8
+#define FF_OTHFS 16
+#define FF_SERR 32 /* error in subdirectory */
+#define FF_BSEL 64 /* selected */
+
+/* Settings Flags (int sflags) */
+#define SF_SMFS 1 /* same filesystem */
+#define SF_AS 2 /* apparent sizes */
+#define SF_SI 4 /* use powers of 1000 instead of 1024 */
+#define SF_IGNS 8 /* ignore too small terminal sizes */
+#define SF_NOCFM 16 /* don't confirm file deletion */
+#define SF_IGNE 32 /* ignore errors when deleting */
+
+/* Browse Flags (int bflags) */
+#define BF_NAME 1
+#define BF_SIZE 2
+#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 */
+
+
+/*
+ * S T R U C T U R E S
+ */
+struct dir {
+ struct dir *parent, *next, *prev, *sub;
+ char *name;
+ off_t size;
+ unsigned int files, dirs;
+ unsigned char flags;
+};
+
+
+/*
+ * G L O B A L V A R I A B L E S
+ *
+ * (all defined in main.c)
+ */
+/* main directory data */
+extern struct dir dat;
+/* updated when window is resized */
+extern int winrows, wincols;
+/* global settings */
+extern char sdir[PATH_MAX];
+extern int sflags, bflags, sdelay, bgraph;
+
+
+/*
+ * G L O B A L F U N C T I O N S
+ */
+/* util.c */
+extern char *cropdir(const char *, int);
+extern char *cropsize(const off_t);
+extern void ncresize(void);
+extern struct dir * freedir(struct dir *);
+extern char *getpath(struct dir *, char *);
+/* settings.c */
+extern int settingsCli(int, char **);
+extern int settingsWin(void);
+/* calc.c */
+extern int calcUsage();
+/* browser.c */
+extern void showBrowser(void);
+
diff --git a/src/settings.c b/src/settings.c
new file mode 100644
index 0000000..472ef39
--- /dev/null
+++ b/src/settings.c
@@ -0,0 +1,232 @@
+/* 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"
+
+
+int settingsCli(int argc, char **argv) {
+ int i, j;
+ char gotdir = 0;
+
+ /* load defaults */
+ memset(sdir, 0, PATH_MAX);
+ getcwd(sdir, PATH_MAX);
+ sflags = 0;
+ sdelay = 100;
+ bflags = BF_SIZE | BF_DESC;
+
+ /* read from commandline */
+ for(i=1; i<argc;i++) {
+ if(argv[i][0] == '-') {
+ for(j=1; j < strlen(argv[i]); j++)
+ switch(argv[i][j]) {
+ case 'a': sflags |= SF_AS; break;
+ case 'x': sflags |= SF_SMFS; break;
+ case 'q': sdelay = 2000; break;
+ case '?':
+ case 'h':
+ printf("ncdu [-ahvx] [dir]\n\n");
+ printf(" -a Apparent sizes\n");
+ printf(" -h This help message\n");
+ printf(" -q x Set the refresh interval in seconds\n");
+ printf(" -v Print version\n");
+ printf(" -x Same filesystem\n");
+ exit(0);
+ case 'v':
+ printf("ncdu %s\n", PACKAGE_VERSION);
+ exit(0);
+ default:
+ printf("Unknown option: -%c\n", argv[i][j]);
+ exit(1);
+ }
+ } else {
+ strcpy(sdir, argv[i]);
+ gotdir = 1;
+ }
+ }
+ return(gotdir ? 0 : 1);
+}
+
+int settingsGet(void) {
+ WINDOW *set;
+ FORM *setf;
+ FIELD *fields[11];
+ int w, h, cx, cy, i, j, ch;
+ int fw, fh, fy, fx, fnrow, fnbuf;
+ char tmp[10], *buf = "", rst = 0;
+ erase();
+ refresh();
+ /* h, w, y, x */
+ fields[0] = new_field(1, 10, 0, 0, 0, 0);
+ fields[1] = new_field(1, 43, 0, 11, 0, 0);
+ fields[2] = new_field(1, 16, 1, 11, 0, 0);
+ fields[3] = new_field(1, 1, 1, 27, 0, 0);
+ fields[4] = new_field(1, 1, 1, 28, 0, 0);
+ fields[5] = new_field(1, 16, 2, 12, 0, 0);
+ fields[6] = new_field(1, 1, 2, 27, 0, 0);
+ fields[7] = new_field(1, 1, 2, 28, 0, 0);
+ fields[8] = new_field(1, 6, 3, 11, 0, 0);
+ fields[9] = new_field(1, 9, 3, 19, 0, 0);
+ fields[10] = NULL;
+
+ /* Directory */
+ field_opts_off(fields[0], O_ACTIVE);
+ set_field_buffer(fields[0], 0, "Directory:");
+ set_field_back(fields[1], A_UNDERLINE);
+ field_opts_off(fields[1], O_STATIC);
+ field_opts_off(fields[1], O_AUTOSKIP);
+ set_max_field(fields[1], PATH_MAX);
+ set_field_buffer(fields[1], 0, sdir);
+ /* One filesystem */
+ field_opts_off(fields[2], O_ACTIVE);
+ set_field_buffer(fields[2], 0, "One filesystem [");
+ field_opts_off(fields[3], O_AUTOSKIP);
+ set_field_back(fields[3], A_UNDERLINE);
+ set_field_buffer(fields[3], 0, sflags & SF_SMFS ? "X" : " ");
+ field_opts_off(fields[4], O_ACTIVE);
+ set_field_buffer(fields[4], 0, "]");
+ /* Apparent sizes */
+ field_opts_off(fields[5], O_ACTIVE);
+ set_field_buffer(fields[5], 0, "Apparent size [");
+ field_opts_off(fields[6], O_AUTOSKIP);
+ set_field_back(fields[6], A_UNDERLINE);
+ set_field_buffer(fields[6], 0, sflags & SF_AS ? "X" : " ");
+ field_opts_off(fields[7], O_ACTIVE);
+ set_field_buffer(fields[7], 0, "]");
+ /* buttons */
+ set_field_buffer(fields[8], 0, "[OK]");
+ set_field_buffer(fields[9], 0, "[CLOSE]");
+
+ setf = new_form(fields);
+ h=8;w=60;
+
+ set = newwin(h, w, winrows/2 - h/2, wincols/2 - w/2);
+ keypad(stdscr, TRUE);
+ keypad(set, TRUE);
+ box(set, 0, 0);
+ curs_set(1);
+
+ set_form_win(setf, set);
+ set_form_sub(setf, derwin(set, h-3, w-4, 2, 2));
+
+ wattron(set, A_BOLD);
+ mvwaddstr(set, 0, 4, "Calculate disk space usage...");
+ wattroff(set, A_BOLD);
+ post_form(setf);
+ refresh();
+ wrefresh(set);
+
+ while((ch = wgetch(set))) {
+ getyx(set, cy, cx);
+ cy-=2; cx-=2;
+ for(i=field_count(setf); --i>=0; ) {
+ field_info(fields[i], &fh, &fw, &fy, &fx, &fnrow, &fnbuf);
+ if(cy >= fy && cy < fy+fh && cx >= fx && cx < fx+fw) {
+ buf = field_buffer(fields[i], 0);
+ break;
+ }
+ }
+ switch(ch) {
+ case KEY_BACKSPACE:
+ case 127: form_driver(setf, REQ_DEL_PREV); break;
+ case KEY_LL:
+ case KEY_END: form_driver(setf, REQ_END_LINE); break;
+ case KEY_HOME: form_driver(setf, REQ_BEG_LINE); break;
+ case KEY_LEFT: form_driver(setf, REQ_LEFT_CHAR); break;
+ case KEY_RIGHT:
+ if(i == 1) {
+ for(j=strlen(buf);--j>i;)
+ if(buf[j] != ' ')
+ break;
+ if(j < fw && cx > fx+j)
+ break;
+ }
+ form_driver(setf, REQ_RIGHT_CHAR);
+ break;
+ case KEY_DC: form_driver(setf, REQ_DEL_CHAR); break;
+ case KEY_DOWN: form_driver(setf, REQ_NEXT_FIELD); break;
+ case KEY_UP: form_driver(setf, REQ_PREV_FIELD); break;
+ case '\t': form_driver(setf, REQ_NEXT_FIELD); break;
+ case KEY_RESIZE: rst = 1; goto setend; break;
+ default:
+ if(i == 9) {
+ rst = 2;
+ goto setend;
+ }
+ if(i == 8 || ch == '\n')
+ goto setend;
+ if(i == 3 || i == 6)
+ set_field_buffer(fields[i], 0, buf[0] == ' ' ? "X" : " ");
+ else if(!isprint(ch)) break;
+ else if(i == 9) {
+ if(!isdigit(ch)) strcpy(tmp, " 0");
+ else if(buf[0] != ' ' || buf[1] == ' ' || buf[1] == '0') sprintf(tmp, " %c", ch);
+ else sprintf(tmp, "%c%c", buf[1], ch);
+ set_field_buffer(fields[i], 0, tmp);
+ } else
+ form_driver(setf, ch);
+ break;
+ }
+ wrefresh(set);
+ }
+ setend:
+ /* !!!WARNING!!! ugly hack !!!WARNING!!! */
+ set_current_field(setf, fields[1]);
+ form_driver(setf, REQ_END_LINE);
+ for(i=0; i<40; i++)
+ form_driver(setf, ' ');
+ dynamic_field_info(fields[1], &fh, &fw, &fx);
+ memcpy(sdir, field_buffer(fields[1], 0), fw);
+ for(i=strlen(sdir); --i>=0;)
+ if(sdir[i] != ' ' && (sdir[i] != '/' || i == 0)) {
+ sdir[i+1] = 0;
+ break;
+ }
+ /* EOW */
+ sflags = sflags & SF_IGNS;
+ buf = field_buffer(fields[3], 0);
+ if(buf[0] != ' ') sflags |= SF_SMFS;
+ buf = field_buffer(fields[6], 0);
+ if(buf[0] != ' ') sflags |= SF_AS;
+
+ unpost_form(setf);
+ for(i=10;--i>=0;)
+ free_field(fields[i]);
+ werase(set);
+ delwin(set);
+ erase();
+ refresh();
+ curs_set(0);
+ return(rst);
+}
+
+int settingsWin(void) {
+ int r;
+ while((r = settingsGet()) == 1) {
+ ncresize();
+ return(settingsWin());
+ }
+ return(r);
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..605a330
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,166 @@
+/* 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];
+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);
+}
+
+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;
+ }
+}
+
+
+
+void freedir_rec(struct dir *dr) {
+ struct dir *tmp, *tmp2;
+ tmp2 = dr;
+ while(tmp2->prev != NULL)
+ tmp2 = tmp2->prev;
+ 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;
+ if(dr->flags & FF_FILE) dr->files++;
+ if(dr->flags & FF_DIR) dr->dirs++;
+ while((tmp = tmp->parent) != NULL) {
+ tmp->size -= dr->size;
+ tmp->files -= dr->files;
+ tmp->dirs -= dr->dirs;
+ }
+
+ /* free dr->sub recursive */
+ if(dr->sub) freedir_rec(dr->sub);
+
+ /* update references */
+ cur = NULL;
+ if(dr->next != NULL) { dr->next->prev = dr->prev; cur = dr->next; }
+ if(dr->prev != NULL) { dr->prev->next = dr->next; cur = dr->prev; }
+ if(cur != NULL)
+ cur->flags |= FF_BSEL;
+
+ if(dr->parent->sub == dr) {
+ if(dr->prev != NULL)
+ dr->parent->sub = dr->prev;
+ else if(dr->next != NULL)
+ dr->parent->sub = dr->next;
+ else {
+ dr->parent->sub = NULL;
+ cur = dr->parent;
+ }
+ }
+
+ free(dr->name);
+ free(dr);
+
+ return(cur);
+}
+
+char *getpath(struct dir *cur, char *to) {
+ struct dir *d;
+ d = cur;
+ while(d->parent != NULL) {
+ d->parent->sub = d;
+ d = d->parent;
+ }
+ to[0] = '\0';
+ while(d->parent != cur->parent) {
+ if(d->parent != NULL && d->parent->name[strlen(d->parent->name)-1] != '/')
+ strcat(to, "/");
+ strcat(to, d->name);
+ d = d->sub;
+ }
+ return to;
+}