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.
Этот коммит содержится в:
родитель
f4fa1f299c
Коммит
59a9c6b877
@ -5,6 +5,7 @@ ncdu_SOURCES=\
|
||||
src/delete.c\
|
||||
src/dirlist.c\
|
||||
src/dir_common.c\
|
||||
src/dir_export.c\
|
||||
src/dir_mem.c\
|
||||
src/dir_scan.c\
|
||||
src/exclude.c\
|
||||
|
@ -94,6 +94,9 @@ struct dir_output {
|
||||
*/
|
||||
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 */
|
||||
extern int dir_scan_smfs;
|
||||
|
146
src/dir_export.c
Обычный файл
146
src/dir_export.c
Обычный файл
@ -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 */
|
||||
static char *argv_parse(int argc, char **argv) {
|
||||
int i, j, len;
|
||||
char *export = NULL;
|
||||
char *dir = NULL;
|
||||
dir_ui = 2;
|
||||
dir_ui = -1;
|
||||
|
||||
/* read from commandline */
|
||||
for(i=1; i<argc; i++) {
|
||||
if(argv[i][0] == '-') {
|
||||
/* 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) {
|
||||
printf("Option %s requires an argument\n", argv[i]);
|
||||
exit(1);
|
||||
@ -121,7 +123,9 @@ static char *argv_parse(int argc, char **argv) {
|
||||
exit(1);
|
||||
}
|
||||
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]);
|
||||
else if(exclude_addfile(argv[++i])) {
|
||||
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(" -x Same filesystem\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(" --exclude PATTERN Exclude files that match PATTERN\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
|
||||
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;
|
||||
}
|
||||
|
||||
@ -186,7 +205,6 @@ int main(int argc, char **argv) {
|
||||
if((dir = argv_parse(argc, argv)) == NULL)
|
||||
dir = ".";
|
||||
|
||||
dir_mem_init(NULL);
|
||||
dir_scan_init(dir);
|
||||
|
||||
if(dir_ui == 2)
|
||||
@ -202,8 +220,11 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
if(pstate == ST_CALC) {
|
||||
if(dir_scan_process())
|
||||
if(dir_scan_process()) {
|
||||
if(dir_ui == 1)
|
||||
fputc('\n', stderr);
|
||||
break;
|
||||
}
|
||||
} else if(pstate == ST_DEL)
|
||||
delete_process();
|
||||
else if(input_handle(0))
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user