mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-13 01:08:41 -09:00
Added -o option to export dir structure to a JSON-encoded file
!WARNING! The export option is experimental, and the file format is not final. I make no promise that a future version of ncdu will be able to read the current format. There's also quite a few TODO's left.
This commit is contained in:
parent
f4fa1f299c
commit
59a9c6b877
4 changed files with 176 additions and 5 deletions
|
|
@ -5,6 +5,7 @@ ncdu_SOURCES=\
|
||||||
src/delete.c\
|
src/delete.c\
|
||||||
src/dirlist.c\
|
src/dirlist.c\
|
||||||
src/dir_common.c\
|
src/dir_common.c\
|
||||||
|
src/dir_export.c\
|
||||||
src/dir_mem.c\
|
src/dir_mem.c\
|
||||||
src/dir_scan.c\
|
src/dir_scan.c\
|
||||||
src/exclude.c\
|
src/exclude.c\
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,9 @@ struct dir_output {
|
||||||
*/
|
*/
|
||||||
void dir_mem_init(struct dir *);
|
void dir_mem_init(struct dir *);
|
||||||
|
|
||||||
|
/* Initializes the SCAN state and dir_output for exporting to a file. */
|
||||||
|
int dir_export_init(const char *fn);
|
||||||
|
|
||||||
|
|
||||||
/* Scanning a live directory */
|
/* Scanning a live directory */
|
||||||
extern int dir_scan_smfs;
|
extern int dir_scan_smfs;
|
||||||
|
|
|
||||||
146
src/dir_export.c
Normal file
146
src/dir_export.c
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
|
Copyright (c) 2007-2012 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 "global.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
static FILE *stream;
|
||||||
|
static int level; /* Current level of nesting */
|
||||||
|
|
||||||
|
|
||||||
|
static void output_string(const char *str) {
|
||||||
|
for(; *str; str++) {
|
||||||
|
switch(*str) {
|
||||||
|
case '\n': fputs("\\n", stream); break;
|
||||||
|
case '\r': fputs("\\r", stream); break;
|
||||||
|
case '\b': fputs("\\b", stream); break;
|
||||||
|
case '\t': fputs("\\t", stream); break;
|
||||||
|
case '\f': fputs("\\f", stream); break;
|
||||||
|
case '\\': fputs("\\\\", stream); break;
|
||||||
|
case '"': fputs("\\\"", stream); break;
|
||||||
|
default:
|
||||||
|
if((unsigned char)*str <= 31 || (unsigned char)*str == 127)
|
||||||
|
fprintf(stream, "\\u00%02x", *str);
|
||||||
|
else
|
||||||
|
fputc(*str, stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void output_int(uint64_t n) {
|
||||||
|
char tmp[20];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
tmp[i++] = n % 10;
|
||||||
|
while((n /= 10) > 0);
|
||||||
|
|
||||||
|
while(i--)
|
||||||
|
fputc(tmp[i]+'0', stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void output_info(struct dir *d) {
|
||||||
|
fputs("{\"name\":\"", stream);
|
||||||
|
output_string(d->name);
|
||||||
|
fputc('"', stream);
|
||||||
|
/* No need for asize/dsize if they're 0 (which happens with excluded or failed-to-stat files) */
|
||||||
|
if(d->asize) {
|
||||||
|
fputs(",\"asize\":", stream);
|
||||||
|
output_int((uint64_t)d->asize);
|
||||||
|
}
|
||||||
|
if(d->size) {
|
||||||
|
fputs(",\"dsize\":", stream);
|
||||||
|
output_int((uint64_t)d->size);
|
||||||
|
}
|
||||||
|
/* TODO: No need to include a dev is it's the same as the parent dir. */
|
||||||
|
fputs(",\"dev\":", stream);
|
||||||
|
output_int(d->dev);
|
||||||
|
fputs(",\"ino\":", stream);
|
||||||
|
output_int(d->ino);
|
||||||
|
if(d->flags & FF_HLNKC) /* TODO: Including the actual number of links would be nicer. */
|
||||||
|
fputs(",\"hlnkc\":true", stream);
|
||||||
|
if(d->flags & FF_ERR)
|
||||||
|
fputs(",\"read_error\":true", stream);
|
||||||
|
if(!(d->flags & (FF_DIR|FF_FILE)))
|
||||||
|
fputs(",\"notreg\":true", stream);
|
||||||
|
if(d->flags & FF_EXL)
|
||||||
|
fputs(",\"excluded\":\"pattern", stream);
|
||||||
|
else if(d->flags & FF_OTHFS)
|
||||||
|
fputs(",\"excluded\":\"othfs", stream);
|
||||||
|
fputc('}', stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: Error handling / reporting! */
|
||||||
|
static void item(struct dir *item) {
|
||||||
|
if(!item) {
|
||||||
|
if(!--level) { /* closing of the root item */
|
||||||
|
fputs("]]", stream);
|
||||||
|
fclose(stream);
|
||||||
|
} else /* closing of a regular directory item */
|
||||||
|
fputs("]", stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_output.items++;
|
||||||
|
|
||||||
|
/* File header.
|
||||||
|
* TODO: Add scan options? */
|
||||||
|
if(item->flags & FF_DIR && !level++)
|
||||||
|
fputs("[1,0,{\"progname\":\""PACKAGE"\",\"progver\":\""PACKAGE_VERSION"\"}", stream);
|
||||||
|
|
||||||
|
fputs(",\n", stream);
|
||||||
|
if(item->flags & FF_DIR)
|
||||||
|
fputc('[', stream);
|
||||||
|
|
||||||
|
output_info(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int final(int fail) {
|
||||||
|
return fail ? 1 : 1; /* Silences -Wunused-parameter */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dir_export_init(const char *fn) {
|
||||||
|
/* TODO: stdout support */
|
||||||
|
if((stream = fopen(fn, "w")) == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
level = 0;
|
||||||
|
pstate = ST_CALC;
|
||||||
|
dir_output.item = item;
|
||||||
|
dir_output.final = final;
|
||||||
|
dir_output.size = 0;
|
||||||
|
dir_output.items = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
31
src/main.c
31
src/main.c
|
|
@ -103,14 +103,16 @@ int input_handle(int wait) {
|
||||||
/* parse command line */
|
/* parse command line */
|
||||||
static char *argv_parse(int argc, char **argv) {
|
static char *argv_parse(int argc, char **argv) {
|
||||||
int i, j, len;
|
int i, j, len;
|
||||||
|
char *export = NULL;
|
||||||
char *dir = NULL;
|
char *dir = NULL;
|
||||||
dir_ui = 2;
|
dir_ui = -1;
|
||||||
|
|
||||||
/* read from commandline */
|
/* read from commandline */
|
||||||
for(i=1; i<argc; i++) {
|
for(i=1; i<argc; i++) {
|
||||||
if(argv[i][0] == '-') {
|
if(argv[i][0] == '-') {
|
||||||
/* flags requiring arguments */
|
/* flags requiring arguments */
|
||||||
if(!strcmp(argv[i], "-X") || !strcmp(argv[i], "-u") || !strcmp(argv[i], "--exclude-from") || !strcmp(argv[i], "--exclude")) {
|
if(!strcmp(argv[i], "-X") || !strcmp(argv[i], "-u") || !strcmp(argv[i], "-o")
|
||||||
|
|| !strcmp(argv[i], "--exclude-from") || !strcmp(argv[i], "--exclude")) {
|
||||||
if(i+1 >= argc) {
|
if(i+1 >= argc) {
|
||||||
printf("Option %s requires an argument\n", argv[i]);
|
printf("Option %s requires an argument\n", argv[i]);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -121,7 +123,9 @@ static char *argv_parse(int argc, char **argv) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
dir_ui = argv[i][0]-'0';
|
dir_ui = argv[i][0]-'0';
|
||||||
} else if(strcmp(argv[i], "--exclude") == 0)
|
} else if(strcmp(argv[i], "-o") == 0)
|
||||||
|
export = argv[++i];
|
||||||
|
else if(strcmp(argv[i], "--exclude") == 0)
|
||||||
exclude_add(argv[++i]);
|
exclude_add(argv[++i]);
|
||||||
else if(exclude_addfile(argv[++i])) {
|
else if(exclude_addfile(argv[++i])) {
|
||||||
printf("Can't open %s: %s\n", argv[i], strerror(errno));
|
printf("Can't open %s: %s\n", argv[i], strerror(errno));
|
||||||
|
|
@ -144,6 +148,7 @@ static char *argv_parse(int argc, char **argv) {
|
||||||
printf(" -v Print version\n");
|
printf(" -v Print version\n");
|
||||||
printf(" -x Same filesystem\n");
|
printf(" -x Same filesystem\n");
|
||||||
printf(" -r Read only\n");
|
printf(" -r Read only\n");
|
||||||
|
printf(" -o FILE Export scanned directory to FILE\n");
|
||||||
printf(" -u <0-2> UI to use when scanning (0=minimal,2=verbose)\n");
|
printf(" -u <0-2> UI to use when scanning (0=minimal,2=verbose)\n");
|
||||||
printf(" --exclude PATTERN Exclude files that match PATTERN\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(" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n");
|
||||||
|
|
@ -158,6 +163,20 @@ static char *argv_parse(int argc, char **argv) {
|
||||||
} else
|
} else
|
||||||
dir = argv[i];
|
dir = argv[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(export) {
|
||||||
|
/* TODO: Support exporting to stdout */
|
||||||
|
if(dir_export_init(export)) {
|
||||||
|
printf("Can't open %s: %s\n", export, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
dir_mem_init(NULL);
|
||||||
|
|
||||||
|
/* Use the single-line scan feedback by default when exporting. */
|
||||||
|
if(dir_ui == -1)
|
||||||
|
dir_ui = export ? 1 : 2;
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,7 +205,6 @@ int main(int argc, char **argv) {
|
||||||
if((dir = argv_parse(argc, argv)) == NULL)
|
if((dir = argv_parse(argc, argv)) == NULL)
|
||||||
dir = ".";
|
dir = ".";
|
||||||
|
|
||||||
dir_mem_init(NULL);
|
|
||||||
dir_scan_init(dir);
|
dir_scan_init(dir);
|
||||||
|
|
||||||
if(dir_ui == 2)
|
if(dir_ui == 2)
|
||||||
|
|
@ -202,8 +220,11 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pstate == ST_CALC) {
|
if(pstate == ST_CALC) {
|
||||||
if(dir_scan_process())
|
if(dir_scan_process()) {
|
||||||
|
if(dir_ui == 1)
|
||||||
|
fputc('\n', stderr);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
} else if(pstate == ST_DEL)
|
} else if(pstate == ST_DEL)
|
||||||
delete_process();
|
delete_process();
|
||||||
else if(input_handle(0))
|
else if(input_handle(0))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue