From 9670ca66ed8fb2635b7349796486e3c331611456 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Sat, 5 Nov 2022 12:21:28 +0100 Subject: [PATCH] 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. --- Makefile.am | 2 - deps/yopt.h | 198 --------------------------------- doc/ncdu.pod | 65 ++++++----- src/main.c | 307 +++++++++++++++++++++++++++------------------------ src/util.c | 9 ++ src/util.h | 3 + 6 files changed, 211 insertions(+), 373 deletions(-) delete mode 100644 deps/yopt.h diff --git a/Makefile.am b/Makefile.am index f5ef951..71c12d4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,6 @@ ncdu_SOURCES=\ noinst_HEADERS=\ - deps/yopt.h\ deps/khashl.h\ deps/strnatcmp.h\ src/browser.h\ @@ -49,6 +48,5 @@ ncdu.1: $(srcdir)/doc/ncdu.pod # dependencies have minor ncdu-specific changes. update-deps: 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.c -O "$(srcdir)/deps/strnatcmp.c" diff --git a/deps/yopt.h b/deps/yopt.h deleted file mode 100644 index f1a3b7e..0000000 --- a/deps/yopt.h +++ /dev/null @@ -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 " - * "--file=" - * "-z" - * "-f " - * "-f" - * "-zf " - * "-zf" - * "--" (To stop looking for further options) - * "" (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 -#include -#include -#include - - -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: */ diff --git a/doc/ncdu.pod b/doc/ncdu.pod index 3980841..15736ae 100644 --- a/doc/ncdu.pod +++ b/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 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 -information, also read the ownership, permissions and last modification time -for each file. This will result in higher memory usage (by roughly ~30%) and in -a larger output file when exporting. +Enable/disable extended information mode. This will, in addition to the usual +file information, also read the ownership, permissions and last modification +time for each file. This will result in higher memory usage (by roughly ~30%) +and in a larger output file when exporting. 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 @@ -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 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 -screen 10 times a second by default, this will be decreased to once every 2 -seconds in quiet mode. Use this feature to save bandwidth over remote -connections. This option has no effect when C<-0> is used. +Change the UI update interval while scanning or importing. Ncdu will update the +screen 10 times a second by default (C<--fast-ui-updates>), this can be +decreased to once every 2 seconds with C<-q> or C<--slow-ui-updates>. This +feature can be used to save bandwidth over remote connections. This option has +no effect when C<-0> is used. =item B<-r> @@ -123,16 +124,16 @@ C<-rr>). In addition to C<-r>, this will also disable the shell spawning feature of the 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 defined in the International System of Units (SI), instead of the usual base 2 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 -accidentally press 'q' during or after a very long scan. +Require a confirmation before quitting ncdu. Very helpful when you accidentally +press 'q' during or after a very long scan. =item B<--color> I @@ -152,11 +153,16 @@ directory information from a file. =over -=item B<-x> +=item B<-x>, B<--one-file-system> Do not cross filesystem boundaries, i.e. only count files and directories on 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 Exclude files that match I. 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. Patterns should be separated by a newline. -=item B<--exclude-caches> +=item B<--include-caches>, B<--exclude-caches> -Exclude directories containing CACHEDIR.TAG. The directories will still be -displayed, but not their content, and they are not counted towards the disk -usage statistics. -See http://www.brynosaurus.com/cachedir/ +Include (default) or exclude directories containing CACHEDIR.TAG. The +directories will still be displayed, but their contents will not be scanned or +counted towards the disk usage statistics. +L -=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, -this option will not follow symlinks to directories and will count each -symlinked file as a unique file (i.e. unlike how hard links are handled). This -is subject to change in later versions. +Follow (or not) symlinks and count the size of the file they point to. As of +ncdu 1.14, this option will not follow symlinks to directories and will count +each symlinked file as a unique file (i.e. unlike how hard links are handled). +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, cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace. diff --git a/src/main.c b/src/main.c index 220d2cd..f934161 100644 --- a/src/main.c +++ b/src/main.c @@ -33,8 +33,6 @@ #include #include -#include - int pstate; 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 \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) { - yopt_t yopt; - int v; - char *val; + int r; char *export = NULL; char *import = 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; - dir_ui = -1; si = 0; - yopt_init(&yopt, argc, argv, opts); - while((v = yopt_next(&yopt, &val)) != -1) { - switch(v) { - case 0 : dir = val; break; - case 'h': - printf("ncdu \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); - case 'q': update_delay = 2000; break; - case 'v': + memset(&argparser_state, 0, sizeof(struct argparser)); + argparser_state.argv = argv; + argparser_state.argc = argc; + argparser_next(&argparser_state); /* skip program name */ + + while((r = argparser_next(&argparser_state)) > 0) { + if(r == 2) dir = argparser_state.last; + else if(OPT("-v") || OPT("-V") || OPT("--version")) { printf("ncdu %s\n", PACKAGE_VERSION); exit(0); - case 'x': dir_scan_smfs = 1; break; - case 'e': extended_info = 1; break; - case 'r': read_only++; break; - case 's': si = 1; break; - 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); - } + } else if(OPT("-h") || OPT("-?") || OPT("--help")) arg_help(); + else if(OPT("-o")) export = ARG; + else if(OPT("-f")) import = ARG; + else if(!arg_option()) die("Unknown option '%s'.\n", argparser_state.last); } +#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(dir_export_init(export)) { - fprintf(stderr, "Can't open %s: %s\n", export, strerror(errno)); - exit(1); - } - if(strcmp(export, "-") == 0) - ncurses_tty = 1; + if(dir_export_init(export)) die("Can't open %s: %s\n", export, strerror(errno)); + if(strcmp(export, "-") == 0) ncurses_tty = 1; } else dir_mem_init(NULL); if(import) { - if(dir_import_init(import)) { - fprintf(stderr, "Can't open %s: %s\n", import, strerror(errno)); - exit(1); - } - if(strcmp(import, "-") == 0) - ncurses_tty = 1; + if(dir_import_init(import)) die("Can't open %s: %s\n", import, strerror(errno)); + if(strcmp(import, "-") == 0) ncurses_tty = 1; } else dir_scan_init(dir ? dir : "."); @@ -282,10 +311,7 @@ static void init_nc(void) { if(ncurses_tty) { tty = fopen("/dev/tty", "r+"); - if(!tty) { - fprintf(stderr, "Error opening /dev/tty: %s\n", strerror(errno)); - exit(1); - } + if(!tty) die("Error opening /dev/tty: %s\n", strerror(errno)); term = newterm(NULL, tty, tty); if(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 * input without using "-f -". An annoying input sequence could result in * the deletion of your files, which we want to prevent at all costs. */ - if(!isatty(0)) { - fprintf(stderr, "Standard input is not a TTY. Did you mean to import a file using '-f -'?\n"); - exit(1); - } + if(!isatty(0)) die("Standard input is not a TTY. Did you mean to import a file using '-f -'?\n"); ok = !!initscr(); } - if(!ok) { - fprintf(stderr, "Error while initializing ncurses.\n"); - exit(1); - } + if(!ok) die("Error while initializing ncurses.\n"); uic_init(); cbreak(); @@ -326,7 +346,6 @@ void close_nc(void) { } -/* main program */ int main(int argc, char **argv) { read_locale(); argv_parse(argc, argv); diff --git a/src/util.c b/src/util.c index 5264a27..144af82 100644 --- a/src/util.c +++ b/src/util.c @@ -41,6 +41,15 @@ int si; 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) { static char dat[4096]; int i, j, o = strlen(from); diff --git a/src/util.h b/src/util.h index a8b6553..516c5e7 100644 --- a/src/util.h +++ b/src/util.h @@ -30,6 +30,9 @@ #include +void die(const char *, ...); + + /* UI colors: (foreground, background, attrs) * NAME OFF DARK DARK-BG */ #define UI_COLORS \