mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-13 01:08:41 -09:00
Backport argument parser from ncdu 2.x + add a few inverted arguments
This makes way for backporting the various new configuration options and config file support from 2.x.
This commit is contained in:
parent
dc78e8db19
commit
9670ca66ed
6 changed files with 211 additions and 373 deletions
|
|
@ -21,7 +21,6 @@ ncdu_SOURCES=\
|
||||||
|
|
||||||
|
|
||||||
noinst_HEADERS=\
|
noinst_HEADERS=\
|
||||||
deps/yopt.h\
|
|
||||||
deps/khashl.h\
|
deps/khashl.h\
|
||||||
deps/strnatcmp.h\
|
deps/strnatcmp.h\
|
||||||
src/browser.h\
|
src/browser.h\
|
||||||
|
|
@ -49,6 +48,5 @@ ncdu.1: $(srcdir)/doc/ncdu.pod
|
||||||
# dependencies have minor ncdu-specific changes.
|
# dependencies have minor ncdu-specific changes.
|
||||||
update-deps:
|
update-deps:
|
||||||
wget -q https://raw.github.com/attractivechaos/klib/master/khashl.h -O "$(srcdir)/deps/khashl.h"
|
wget -q https://raw.github.com/attractivechaos/klib/master/khashl.h -O "$(srcdir)/deps/khashl.h"
|
||||||
wget -q http://g.blicky.net/ylib.git/plain/yopt.h -O "$(srcdir)/deps/yopt.h"
|
|
||||||
wget -q https://raw.githubusercontent.com/sourcefrog/natsort/master/strnatcmp.h -O "$(srcdir)/deps/strnatcmp.h"
|
wget -q https://raw.githubusercontent.com/sourcefrog/natsort/master/strnatcmp.h -O "$(srcdir)/deps/strnatcmp.h"
|
||||||
wget -q https://raw.githubusercontent.com/sourcefrog/natsort/master/strnatcmp.c -O "$(srcdir)/deps/strnatcmp.c"
|
wget -q https://raw.githubusercontent.com/sourcefrog/natsort/master/strnatcmp.c -O "$(srcdir)/deps/strnatcmp.c"
|
||||||
|
|
|
||||||
198
deps/yopt.h
vendored
198
deps/yopt.h
vendored
|
|
@ -1,198 +0,0 @@
|
||||||
/* Copyright (c) 2012-2013 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This is a simple command-line option parser. Operation is similar to
|
|
||||||
* getopt_long(), except with a cleaner API.
|
|
||||||
*
|
|
||||||
* This is implemented in a single header file, as it's pretty small and you
|
|
||||||
* generally only use an option parser in a single .c file in your program.
|
|
||||||
*
|
|
||||||
* Supports (examples from GNU tar(1)):
|
|
||||||
* "--gzip"
|
|
||||||
* "--file <arg>"
|
|
||||||
* "--file=<arg>"
|
|
||||||
* "-z"
|
|
||||||
* "-f <arg>"
|
|
||||||
* "-f<arg>"
|
|
||||||
* "-zf <arg>"
|
|
||||||
* "-zf<arg>"
|
|
||||||
* "--" (To stop looking for further options)
|
|
||||||
* "<arg>" (Non-option arguments)
|
|
||||||
*
|
|
||||||
* Issues/non-features:
|
|
||||||
* - An option either requires an argument or it doesn't.
|
|
||||||
* - No way to specify how often an option can/should be used.
|
|
||||||
* - No way to specify the type of an argument (filename/integer/enum/whatever)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef YOPT_H
|
|
||||||
#define YOPT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* Value yopt_next() will return for this option */
|
|
||||||
int val;
|
|
||||||
/* Whether this option needs an argument */
|
|
||||||
int needarg;
|
|
||||||
/* Name(s) of this option, prefixed with '-' or '--' and separated by a
|
|
||||||
* comma. E.g. "-z", "--gzip", "-z,--gzip".
|
|
||||||
* An option can have any number of aliases.
|
|
||||||
*/
|
|
||||||
const char *name;
|
|
||||||
} yopt_opt_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int argc;
|
|
||||||
int cur;
|
|
||||||
int argsep; /* '--' found */
|
|
||||||
char **argv;
|
|
||||||
char *sh;
|
|
||||||
const yopt_opt_t *opts;
|
|
||||||
char errbuf[128];
|
|
||||||
} yopt_t;
|
|
||||||
|
|
||||||
|
|
||||||
/* opts must be an array of options, terminated with an option with val=0 */
|
|
||||||
static inline void yopt_init(yopt_t *o, int argc, char **argv, const yopt_opt_t *opts) {
|
|
||||||
o->argc = argc;
|
|
||||||
o->argv = argv;
|
|
||||||
o->opts = opts;
|
|
||||||
o->cur = 0;
|
|
||||||
o->argsep = 0;
|
|
||||||
o->sh = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline const yopt_opt_t *_yopt_find(const yopt_opt_t *o, const char *v) {
|
|
||||||
const char *tn, *tv;
|
|
||||||
|
|
||||||
for(; o->val; o++) {
|
|
||||||
tn = o->name;
|
|
||||||
while(*tn) {
|
|
||||||
tv = v;
|
|
||||||
while(*tn && *tn != ',' && *tv && *tv != '=' && *tn == *tv) {
|
|
||||||
tn++;
|
|
||||||
tv++;
|
|
||||||
}
|
|
||||||
if(!(*tn && *tn != ',') && !(*tv && *tv != '='))
|
|
||||||
return o;
|
|
||||||
while(*tn && *tn != ',')
|
|
||||||
tn++;
|
|
||||||
while(*tn == ',')
|
|
||||||
tn++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _yopt_err(yopt_t *o, char **val, const char *fmt, ...) {
|
|
||||||
va_list va;
|
|
||||||
va_start(va, fmt);
|
|
||||||
vsnprintf(o->errbuf, sizeof(o->errbuf), fmt, va);
|
|
||||||
va_end(va);
|
|
||||||
*val = o->errbuf;
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return values:
|
|
||||||
* 0 -> Non-option argument, val is its value
|
|
||||||
* -1 -> Last argument has been processed
|
|
||||||
* -2 -> Error, val will contain the error message.
|
|
||||||
* x -> Option with val = x found. If the option requires an argument, its
|
|
||||||
* value will be in val.
|
|
||||||
*/
|
|
||||||
static inline int yopt_next(yopt_t *o, char **val) {
|
|
||||||
const yopt_opt_t *opt;
|
|
||||||
char sh[3];
|
|
||||||
|
|
||||||
*val = NULL;
|
|
||||||
if(o->sh)
|
|
||||||
goto inshort;
|
|
||||||
|
|
||||||
if(++o->cur >= o->argc)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(!o->argsep && o->argv[o->cur][0] == '-' && o->argv[o->cur][1] == '-' && o->argv[o->cur][2] == 0) {
|
|
||||||
o->argsep = 1;
|
|
||||||
if(++o->cur >= o->argc)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(o->argsep || *o->argv[o->cur] != '-') {
|
|
||||||
*val = o->argv[o->cur];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(o->argv[o->cur][1] != '-') {
|
|
||||||
o->sh = o->argv[o->cur]+1;
|
|
||||||
goto inshort;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we're supposed to have a long option */
|
|
||||||
if(!(opt = _yopt_find(o->opts, o->argv[o->cur])))
|
|
||||||
return _yopt_err(o, val, "Unknown option '%s'", o->argv[o->cur]);
|
|
||||||
if((*val = strchr(o->argv[o->cur], '=')) != NULL)
|
|
||||||
(*val)++;
|
|
||||||
if(!opt->needarg && *val)
|
|
||||||
return _yopt_err(o, val, "Option '%s' does not accept an argument", o->argv[o->cur]);
|
|
||||||
if(opt->needarg && !*val) {
|
|
||||||
if(o->cur+1 >= o->argc)
|
|
||||||
return _yopt_err(o, val, "Option '%s' requires an argument", o->argv[o->cur]);
|
|
||||||
*val = o->argv[++o->cur];
|
|
||||||
}
|
|
||||||
return opt->val;
|
|
||||||
|
|
||||||
/* And here we're supposed to have a short option */
|
|
||||||
inshort:
|
|
||||||
sh[0] = '-';
|
|
||||||
sh[1] = *o->sh;
|
|
||||||
sh[2] = 0;
|
|
||||||
if(!(opt = _yopt_find(o->opts, sh)))
|
|
||||||
return _yopt_err(o, val, "Unknown option '%s'", sh);
|
|
||||||
o->sh++;
|
|
||||||
if(opt->needarg && *o->sh)
|
|
||||||
*val = o->sh;
|
|
||||||
else if(opt->needarg) {
|
|
||||||
if(++o->cur >= o->argc)
|
|
||||||
return _yopt_err(o, val, "Option '%s' requires an argument", sh);
|
|
||||||
*val = o->argv[o->cur];
|
|
||||||
}
|
|
||||||
if(!*o->sh || opt->needarg)
|
|
||||||
o->sh = NULL;
|
|
||||||
return opt->val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* vim: set noet sw=4 ts=4: */
|
|
||||||
65
doc/ncdu.pod
65
doc/ncdu.pod
|
|
@ -54,12 +54,12 @@ directory with many files. 10.000 files will get you an export in the order of
|
||||||
gzip. This scales linearly, so be prepared to handle a few tens of megabytes
|
gzip. This scales linearly, so be prepared to handle a few tens of megabytes
|
||||||
when dealing with millions of files.
|
when dealing with millions of files.
|
||||||
|
|
||||||
=item B<-e>
|
=item B<-e>, B<--extended>, B<--no-extended>
|
||||||
|
|
||||||
Enable extended information mode. This will, in addition to the usual file
|
Enable/disable extended information mode. This will, in addition to the usual
|
||||||
information, also read the ownership, permissions and last modification time
|
file information, also read the ownership, permissions and last modification
|
||||||
for each file. This will result in higher memory usage (by roughly ~30%) and in
|
time for each file. This will result in higher memory usage (by roughly ~30%)
|
||||||
a larger output file when exporting.
|
and in a larger output file when exporting.
|
||||||
|
|
||||||
When using the file export/import function, this flag will need to be added
|
When using the file export/import function, this flag will need to be added
|
||||||
both when exporting (to make sure the information is added to the export), and
|
both when exporting (to make sure the information is added to the export), and
|
||||||
|
|
@ -99,12 +99,13 @@ Provide a full-screen ncurses interface while scanning a directory or importing
|
||||||
a file. This is the only interface that provides feedback on any non-fatal
|
a file. This is the only interface that provides feedback on any non-fatal
|
||||||
errors while scanning.
|
errors while scanning.
|
||||||
|
|
||||||
=item B<-q>
|
=item B<-q>, B<--slow-ui-updates>, B<--fast-ui-updates>
|
||||||
|
|
||||||
Quiet mode. While scanning or importing the directory, ncdu will update the
|
Change the UI update interval while scanning or importing. Ncdu will update the
|
||||||
screen 10 times a second by default, this will be decreased to once every 2
|
screen 10 times a second by default (C<--fast-ui-updates>), this can be
|
||||||
seconds in quiet mode. Use this feature to save bandwidth over remote
|
decreased to once every 2 seconds with C<-q> or C<--slow-ui-updates>. This
|
||||||
connections. This option has no effect when C<-0> is used.
|
feature can be used to save bandwidth over remote connections. This option has
|
||||||
|
no effect when C<-0> is used.
|
||||||
|
|
||||||
=item B<-r>
|
=item B<-r>
|
||||||
|
|
||||||
|
|
@ -123,16 +124,16 @@ C<-rr>).
|
||||||
In addition to C<-r>, this will also disable the shell spawning feature of the
|
In addition to C<-r>, this will also disable the shell spawning feature of the
|
||||||
file browser.
|
file browser.
|
||||||
|
|
||||||
=item B<--si>
|
=item B<--si>, B<--no-si>
|
||||||
|
|
||||||
List sizes using base 10 prefixes, that is, powers of 1000 (KB, MB, etc), as
|
List sizes using base 10 prefixes, that is, powers of 1000 (KB, MB, etc), as
|
||||||
defined in the International System of Units (SI), instead of the usual base 2
|
defined in the International System of Units (SI), instead of the usual base 2
|
||||||
prefixes, that is, powers of 1024 (KiB, MiB, etc).
|
prefixes, that is, powers of 1024 (KiB, MiB, etc).
|
||||||
|
|
||||||
=item B<--confirm-quit>
|
=item B<--confirm-quit>, B<--no-confirm-quit>
|
||||||
|
|
||||||
Requires a confirmation before quitting ncdu. Very helpful when you
|
Require a confirmation before quitting ncdu. Very helpful when you accidentally
|
||||||
accidentally press 'q' during or after a very long scan.
|
press 'q' during or after a very long scan.
|
||||||
|
|
||||||
=item B<--color> I<SCHEME>
|
=item B<--color> I<SCHEME>
|
||||||
|
|
||||||
|
|
@ -152,11 +153,16 @@ directory information from a file.
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
=item B<-x>
|
=item B<-x>, B<--one-file-system>
|
||||||
|
|
||||||
Do not cross filesystem boundaries, i.e. only count files and directories on
|
Do not cross filesystem boundaries, i.e. only count files and directories on
|
||||||
the same filesystem as the directory being scanned.
|
the same filesystem as the directory being scanned.
|
||||||
|
|
||||||
|
=item B<--cross-file-system>
|
||||||
|
|
||||||
|
Do cross filesystem boundaries. This is the default, but can be specified to
|
||||||
|
overrule a previously given C<-x>.
|
||||||
|
|
||||||
=item B<--exclude> I<PATTERN>
|
=item B<--exclude> I<PATTERN>
|
||||||
|
|
||||||
Exclude files that match I<PATTERN>. The files will still be displayed by
|
Exclude files that match I<PATTERN>. The files will still be displayed by
|
||||||
|
|
@ -168,27 +174,28 @@ can be added multiple times to add more patterns.
|
||||||
Exclude files that match any pattern in I<FILE>. Patterns should be separated
|
Exclude files that match any pattern in I<FILE>. Patterns should be separated
|
||||||
by a newline.
|
by a newline.
|
||||||
|
|
||||||
=item B<--exclude-caches>
|
=item B<--include-caches>, B<--exclude-caches>
|
||||||
|
|
||||||
Exclude directories containing CACHEDIR.TAG. The directories will still be
|
Include (default) or exclude directories containing CACHEDIR.TAG. The
|
||||||
displayed, but not their content, and they are not counted towards the disk
|
directories will still be displayed, but their contents will not be scanned or
|
||||||
usage statistics.
|
counted towards the disk usage statistics.
|
||||||
See http://www.brynosaurus.com/cachedir/
|
L<http://www.brynosaurus.com/cachedir/>
|
||||||
|
|
||||||
=item B<-L>, B<--follow-symlinks>
|
=item B<-L>, B<--follow-symlinks>, B<--no-follow-symlinks>
|
||||||
|
|
||||||
Follow symlinks and count the size of the file they point to. As of ncdu 1.14,
|
Follow (or not) symlinks and count the size of the file they point to. As of
|
||||||
this option will not follow symlinks to directories and will count each
|
ncdu 1.14, this option will not follow symlinks to directories and will count
|
||||||
symlinked file as a unique file (i.e. unlike how hard links are handled). This
|
each symlinked file as a unique file (i.e. unlike how hard links are handled).
|
||||||
is subject to change in later versions.
|
This is subject to change in later versions.
|
||||||
|
|
||||||
=item B<--exclude-firmlinks>
|
=item B<--exclude-firmlinks>, B<--follow-firmlinks>
|
||||||
|
|
||||||
(MacOS only) Exclude firmlinks.
|
(MacOS only) Exclude or follow firmlinks.
|
||||||
|
|
||||||
=item B<--exclude-kernfs>
|
=item B<--include-kernfs>, B<--exclude-kernfs>
|
||||||
|
|
||||||
(Linux only) Exclude Linux pseudo filesystems, e.g. /proc (procfs), /sys (sysfs).
|
(Linux only) Include (default) or exclude Linux pseudo filesystems, e.g. /proc
|
||||||
|
(procfs), /sys (sysfs).
|
||||||
|
|
||||||
The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup,
|
The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup,
|
||||||
cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace.
|
cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace.
|
||||||
|
|
|
||||||
307
src/main.c
307
src/main.c
|
|
@ -33,8 +33,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <yopt.h>
|
|
||||||
|
|
||||||
|
|
||||||
int pstate;
|
int pstate;
|
||||||
int read_only = 0;
|
int read_only = 0;
|
||||||
|
|
@ -113,153 +111,184 @@ int input_handle(int wait) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* parse command line */
|
/* This is a backport of the argument parser in the Zig version.
|
||||||
|
* Minor differences in that this implementation can modify argv in-place and has a slightly different API. */
|
||||||
|
struct argparser {
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
char *shortopt;
|
||||||
|
char *last;
|
||||||
|
char *last_arg;
|
||||||
|
char shortbuf[2];
|
||||||
|
char argsep;
|
||||||
|
} argparser_state;
|
||||||
|
|
||||||
|
static char *argparser_pop(struct argparser *p) {
|
||||||
|
char *a;
|
||||||
|
if(p->argc == 0) return NULL;
|
||||||
|
a = *p->argv;
|
||||||
|
p->argv++;
|
||||||
|
p->argc--;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int argparser_shortopt(struct argparser *p, char *buf) {
|
||||||
|
p->shortbuf[0] = '-';
|
||||||
|
p->shortbuf[1] = *buf;
|
||||||
|
p->shortopt = buf[1] ? buf+1 : NULL;
|
||||||
|
p->last = p->shortbuf;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 when done, 1 if there's an option, 2 if there's a positional argument. */
|
||||||
|
static int argparser_next(struct argparser *p) {
|
||||||
|
if(p->last_arg) die("Option '%s' does not expect an argument.\n", p->last);
|
||||||
|
if(p->shortopt) return argparser_shortopt(p, p->shortopt);
|
||||||
|
p->last = argparser_pop(p);
|
||||||
|
if(!p->last) return 0;
|
||||||
|
if(p->argsep || !*p->last || *p->last != '-') return 2;
|
||||||
|
if(!p->last[1]) die("Invalid option '-'.\n");
|
||||||
|
if(p->last[1] == '-' && !p->last[2]) { /* '--' argument separator */
|
||||||
|
p->argsep = 1;
|
||||||
|
return argparser_next(p);
|
||||||
|
}
|
||||||
|
if(p->last[1] == '-') { /* long option */
|
||||||
|
p->last_arg = strchr(p->last, '=');
|
||||||
|
if(p->last_arg) {
|
||||||
|
*p->last_arg = 0;
|
||||||
|
p->last_arg++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* otherwise: short option */
|
||||||
|
return argparser_shortopt(p, p->last+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *argparser_arg(struct argparser *p) {
|
||||||
|
char *tmp;
|
||||||
|
if(p->shortopt) {
|
||||||
|
tmp = p->shortopt;
|
||||||
|
p->shortopt = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
if(p->last_arg) {
|
||||||
|
tmp = p->last_arg;
|
||||||
|
p->last_arg = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
tmp = argparser_pop(p);
|
||||||
|
if(!tmp) die("Option '%s' requires an argument.\n", p->last);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPT(_s) (strcmp(argparser_state.last, (_s)) == 0)
|
||||||
|
#define ARG (argparser_arg(&argparser_state))
|
||||||
|
|
||||||
|
static int arg_option(void) {
|
||||||
|
char *arg;
|
||||||
|
if(OPT("-q") || OPT("--slow-ui-updates")) update_delay = 2000;
|
||||||
|
else if(OPT("--fast-ui-updates")) update_delay = 100;
|
||||||
|
else if(OPT("-x") || OPT("--one-file-system")) dir_scan_smfs = 1;
|
||||||
|
else if(OPT("--cross-file-system")) dir_scan_smfs = 0;
|
||||||
|
else if(OPT("-e") || OPT("--extended")) extended_info = 1;
|
||||||
|
else if(OPT("--no-extended")) extended_info = 0;
|
||||||
|
else if(OPT("-r")) read_only++;
|
||||||
|
else if(OPT("-0")) dir_ui = 0;
|
||||||
|
else if(OPT("-1")) dir_ui = 1;
|
||||||
|
else if(OPT("-2")) dir_ui = 2;
|
||||||
|
else if(OPT("--si")) si = 1;
|
||||||
|
else if(OPT("--no-si")) si = 0;
|
||||||
|
else if(OPT("-L") || OPT("--follow-symlinks")) follow_symlinks = 1;
|
||||||
|
else if(OPT("--no-follow-symlinks")) follow_symlinks = 0;
|
||||||
|
else if(OPT("--exclude")) exclude_add(ARG);
|
||||||
|
else if(OPT("-X") || OPT("--exclude-form")) {
|
||||||
|
arg = ARG;
|
||||||
|
if(exclude_addfile(arg)) die("Can't open %s: %s\n", arg, strerror(errno));
|
||||||
|
} else if(OPT("--exclude-caches")) cachedir_tags = 1;
|
||||||
|
else if(OPT("--include-caches")) cachedir_tags = 0;
|
||||||
|
else if(OPT("--exclude-kernfs")) exclude_kernfs = 1;
|
||||||
|
else if(OPT("--include-kernfs")) exclude_kernfs = 0;
|
||||||
|
else if(OPT("--follow-firmlinks")) follow_firmlinks = 1;
|
||||||
|
else if(OPT("--exclude-firmlinks")) follow_firmlinks = 0;
|
||||||
|
else if(OPT("--confirm-quit")) confirm_quit = 1;
|
||||||
|
else if(OPT("--no-confirm-quit")) confirm_quit = 0;
|
||||||
|
else if(OPT("--color")) {
|
||||||
|
arg = ARG;
|
||||||
|
if(strcmp(arg, "off") == 0) uic_theme = 0;
|
||||||
|
else if(strcmp(arg, "dark") == 0) uic_theme = 1;
|
||||||
|
else if(strcmp(arg, "dark-bg") == 0) uic_theme = 2;
|
||||||
|
else die("Unknown --color option: %s\n", arg);
|
||||||
|
} else return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arg_help(void) {
|
||||||
|
printf("ncdu <options> <directory>\n\n");
|
||||||
|
printf(" -h,--help This help message\n");
|
||||||
|
printf(" -q Quiet mode, refresh interval 2 seconds\n");
|
||||||
|
printf(" -v,-V,--version Print version\n");
|
||||||
|
printf(" -x Same filesystem\n");
|
||||||
|
printf(" -e Enable extended information\n");
|
||||||
|
printf(" -r Read only\n");
|
||||||
|
printf(" -o FILE Export scanned directory to FILE\n");
|
||||||
|
printf(" -f FILE Import scanned directory from FILE\n");
|
||||||
|
printf(" -0,-1,-2 UI to use when scanning (0=none,2=full ncurses)\n");
|
||||||
|
printf(" --si Use base 10 (SI) prefixes instead of base 2\n");
|
||||||
|
printf(" --exclude PATTERN Exclude files that match PATTERN\n");
|
||||||
|
printf(" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n");
|
||||||
|
printf(" -L, --follow-symlinks Follow symbolic links (excluding directories)\n");
|
||||||
|
printf(" --exclude-caches Exclude directories containing CACHEDIR.TAG\n");
|
||||||
|
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
||||||
|
printf(" --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...)\n");
|
||||||
|
#endif
|
||||||
|
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
||||||
|
printf(" --exclude-firmlinks Exclude firmlinks on macOS\n");
|
||||||
|
#endif
|
||||||
|
printf(" --confirm-quit Confirm quitting ncdu\n");
|
||||||
|
printf(" --color SCHEME Set color scheme (off/dark/dark-bg)\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void argv_parse(int argc, char **argv) {
|
static void argv_parse(int argc, char **argv) {
|
||||||
yopt_t yopt;
|
int r;
|
||||||
int v;
|
|
||||||
char *val;
|
|
||||||
char *export = NULL;
|
char *export = NULL;
|
||||||
char *import = NULL;
|
char *import = NULL;
|
||||||
char *dir = NULL;
|
char *dir = NULL;
|
||||||
|
|
||||||
static yopt_opt_t opts[] = {
|
|
||||||
{ 'h', 0, "-h,-?,--help" },
|
|
||||||
{ 'q', 0, "-q" },
|
|
||||||
{ 'v', 0, "-v,-V,--version" },
|
|
||||||
{ 'x', 0, "-x" },
|
|
||||||
{ 'e', 0, "-e" },
|
|
||||||
{ 'r', 0, "-r" },
|
|
||||||
{ 'o', 1, "-o" },
|
|
||||||
{ 'f', 1, "-f" },
|
|
||||||
{ '0', 0, "-0" },
|
|
||||||
{ '1', 0, "-1" },
|
|
||||||
{ '2', 0, "-2" },
|
|
||||||
{ 1, 1, "--exclude" },
|
|
||||||
{ 'X', 1, "-X,--exclude-from" },
|
|
||||||
{ 'L', 0, "-L,--follow-symlinks" },
|
|
||||||
{ 'C', 0, "--exclude-caches" },
|
|
||||||
{ 2, 0, "--exclude-kernfs" },
|
|
||||||
{ 3, 0, "--follow-firmlinks" }, /* undocumented, this behavior is the current default */
|
|
||||||
{ 4, 0, "--exclude-firmlinks" },
|
|
||||||
{ 's', 0, "--si" },
|
|
||||||
{ 'Q', 0, "--confirm-quit" },
|
|
||||||
{ 'c', 1, "--color" },
|
|
||||||
{0,0,NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
uic_theme = getenv("NO_COLOR") ? 0 : 2;
|
uic_theme = getenv("NO_COLOR") ? 0 : 2;
|
||||||
|
|
||||||
dir_ui = -1;
|
dir_ui = -1;
|
||||||
si = 0;
|
si = 0;
|
||||||
|
|
||||||
yopt_init(&yopt, argc, argv, opts);
|
memset(&argparser_state, 0, sizeof(struct argparser));
|
||||||
while((v = yopt_next(&yopt, &val)) != -1) {
|
argparser_state.argv = argv;
|
||||||
switch(v) {
|
argparser_state.argc = argc;
|
||||||
case 0 : dir = val; break;
|
argparser_next(&argparser_state); /* skip program name */
|
||||||
case 'h':
|
|
||||||
printf("ncdu <options> <directory>\n\n");
|
while((r = argparser_next(&argparser_state)) > 0) {
|
||||||
printf(" -h,--help This help message\n");
|
if(r == 2) dir = argparser_state.last;
|
||||||
printf(" -q Quiet mode, refresh interval 2 seconds\n");
|
else if(OPT("-v") || OPT("-V") || OPT("--version")) {
|
||||||
printf(" -v,-V,--version Print version\n");
|
|
||||||
printf(" -x Same filesystem\n");
|
|
||||||
printf(" -e Enable extended information\n");
|
|
||||||
printf(" -r Read only\n");
|
|
||||||
printf(" -o FILE Export scanned directory to FILE\n");
|
|
||||||
printf(" -f FILE Import scanned directory from FILE\n");
|
|
||||||
printf(" -0,-1,-2 UI to use when scanning (0=none,2=full ncurses)\n");
|
|
||||||
printf(" --si Use base 10 (SI) prefixes instead of base 2\n");
|
|
||||||
printf(" --exclude PATTERN Exclude files that match PATTERN\n");
|
|
||||||
printf(" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n");
|
|
||||||
printf(" -L, --follow-symlinks Follow symbolic links (excluding directories)\n");
|
|
||||||
printf(" --exclude-caches Exclude directories containing CACHEDIR.TAG\n");
|
|
||||||
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
|
||||||
printf(" --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...)\n");
|
|
||||||
#endif
|
|
||||||
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
|
||||||
printf(" --exclude-firmlinks Exclude firmlinks on macOS\n");
|
|
||||||
#endif
|
|
||||||
printf(" --confirm-quit Confirm quitting ncdu\n");
|
|
||||||
printf(" --color SCHEME Set color scheme (off/dark/dark-bg)\n");
|
|
||||||
exit(0);
|
|
||||||
case 'q': update_delay = 2000; break;
|
|
||||||
case 'v':
|
|
||||||
printf("ncdu %s\n", PACKAGE_VERSION);
|
printf("ncdu %s\n", PACKAGE_VERSION);
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'x': dir_scan_smfs = 1; break;
|
} else if(OPT("-h") || OPT("-?") || OPT("--help")) arg_help();
|
||||||
case 'e': extended_info = 1; break;
|
else if(OPT("-o")) export = ARG;
|
||||||
case 'r': read_only++; break;
|
else if(OPT("-f")) import = ARG;
|
||||||
case 's': si = 1; break;
|
else if(!arg_option()) die("Unknown option '%s'.\n", argparser_state.last);
|
||||||
case 'o': export = val; break;
|
|
||||||
case 'f': import = val; break;
|
|
||||||
case '0': dir_ui = 0; break;
|
|
||||||
case '1': dir_ui = 1; break;
|
|
||||||
case '2': dir_ui = 2; break;
|
|
||||||
case 'Q': confirm_quit = 1; break;
|
|
||||||
case 1 : exclude_add(val); break; /* --exclude */
|
|
||||||
case 'X':
|
|
||||||
if(exclude_addfile(val)) {
|
|
||||||
fprintf(stderr, "Can't open %s: %s\n", val, strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'L': follow_symlinks = 1; break;
|
|
||||||
case 'C':
|
|
||||||
cachedir_tags = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2 : /* --exclude-kernfs */
|
|
||||||
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
|
||||||
exclude_kernfs = 1; break;
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "This feature is not supported on your platform\n");
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
case 3 : /* --follow-firmlinks */
|
|
||||||
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
|
||||||
follow_firmlinks = 1; break;
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "This feature is not supported on your platform\n");
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
case 4 : /* --exclude-firmlinks */
|
|
||||||
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
|
||||||
follow_firmlinks = 0; break;
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "This feature is not supported on your platform\n");
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
case 'c':
|
|
||||||
if(strcmp(val, "off") == 0) { uic_theme = 0; }
|
|
||||||
else if(strcmp(val, "dark") == 0) { uic_theme = 1; }
|
|
||||||
else if(strcmp(val, "dark-bg") == 0) { uic_theme = 2; }
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Unknown --color option: %s\n", val);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
fprintf(stderr, "ncdu: %s.\n", val);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !(HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS)
|
||||||
|
if(exclude_kernfs) die("The --exclude-kernfs flag is currently only supported on Linux.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(export) {
|
if(export) {
|
||||||
if(dir_export_init(export)) {
|
if(dir_export_init(export)) die("Can't open %s: %s\n", export, strerror(errno));
|
||||||
fprintf(stderr, "Can't open %s: %s\n", export, strerror(errno));
|
if(strcmp(export, "-") == 0) ncurses_tty = 1;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if(strcmp(export, "-") == 0)
|
|
||||||
ncurses_tty = 1;
|
|
||||||
} else
|
} else
|
||||||
dir_mem_init(NULL);
|
dir_mem_init(NULL);
|
||||||
|
|
||||||
if(import) {
|
if(import) {
|
||||||
if(dir_import_init(import)) {
|
if(dir_import_init(import)) die("Can't open %s: %s\n", import, strerror(errno));
|
||||||
fprintf(stderr, "Can't open %s: %s\n", import, strerror(errno));
|
if(strcmp(import, "-") == 0) ncurses_tty = 1;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if(strcmp(import, "-") == 0)
|
|
||||||
ncurses_tty = 1;
|
|
||||||
} else
|
} else
|
||||||
dir_scan_init(dir ? dir : ".");
|
dir_scan_init(dir ? dir : ".");
|
||||||
|
|
||||||
|
|
@ -282,10 +311,7 @@ static void init_nc(void) {
|
||||||
|
|
||||||
if(ncurses_tty) {
|
if(ncurses_tty) {
|
||||||
tty = fopen("/dev/tty", "r+");
|
tty = fopen("/dev/tty", "r+");
|
||||||
if(!tty) {
|
if(!tty) die("Error opening /dev/tty: %s\n", strerror(errno));
|
||||||
fprintf(stderr, "Error opening /dev/tty: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
term = newterm(NULL, tty, tty);
|
term = newterm(NULL, tty, tty);
|
||||||
if(term)
|
if(term)
|
||||||
set_term(term);
|
set_term(term);
|
||||||
|
|
@ -294,17 +320,11 @@ static void init_nc(void) {
|
||||||
/* Make sure the user doesn't accidentally pipe in data to ncdu's standard
|
/* Make sure the user doesn't accidentally pipe in data to ncdu's standard
|
||||||
* input without using "-f -". An annoying input sequence could result in
|
* input without using "-f -". An annoying input sequence could result in
|
||||||
* the deletion of your files, which we want to prevent at all costs. */
|
* the deletion of your files, which we want to prevent at all costs. */
|
||||||
if(!isatty(0)) {
|
if(!isatty(0)) die("Standard input is not a TTY. Did you mean to import a file using '-f -'?\n");
|
||||||
fprintf(stderr, "Standard input is not a TTY. Did you mean to import a file using '-f -'?\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ok = !!initscr();
|
ok = !!initscr();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ok) {
|
if(!ok) die("Error while initializing ncurses.\n");
|
||||||
fprintf(stderr, "Error while initializing ncurses.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uic_init();
|
uic_init();
|
||||||
cbreak();
|
cbreak();
|
||||||
|
|
@ -326,7 +346,6 @@ void close_nc(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* main program */
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
read_locale();
|
read_locale();
|
||||||
argv_parse(argc, argv);
|
argv_parse(argc, argv);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,15 @@ int si;
|
||||||
static char thou_sep;
|
static char thou_sep;
|
||||||
|
|
||||||
|
|
||||||
|
void die(const char *fmt, ...) {
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, fmt);
|
||||||
|
vfprintf(stderr, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *cropstr(const char *from, int s) {
|
char *cropstr(const char *from, int s) {
|
||||||
static char dat[4096];
|
static char dat[4096];
|
||||||
int i, j, o = strlen(from);
|
int i, j, o = strlen(from);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
|
||||||
|
void die(const char *, ...);
|
||||||
|
|
||||||
|
|
||||||
/* UI colors: (foreground, background, attrs)
|
/* UI colors: (foreground, background, attrs)
|
||||||
* NAME OFF DARK DARK-BG */
|
* NAME OFF DARK DARK-BG */
|
||||||
#define UI_COLORS \
|
#define UI_COLORS \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue