diff --git a/src/dir_export.c b/src/dir_export.c index 3d32c1af12d77205c47fdea4c744ae9e0383f3ad..5ac6f2110cc4aae17428695f2aa5e3a8352a792a 100644 --- a/src/dir_export.c +++ b/src/dir_export.c @@ -31,7 +31,12 @@ static FILE *stream; -static int level; /* Current level of nesting */ + +/* Stack of device IDs, also used to determine the */ +struct stack { + uint64_t *list; + int size, top; +} stack; static void output_string(const char *str) { @@ -81,9 +86,10 @@ static void output_info(struct dir *d) { 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); + if(d->dev != nstack_top(&stack, 0)) { + 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. */ @@ -93,9 +99,9 @@ static void output_info(struct dir *d) { if(!(d->flags & (FF_DIR|FF_FILE))) fputs(",\"notreg\":true", stream); if(d->flags & FF_EXL) - fputs(",\"excluded\":\"pattern", stream); + fputs(",\"excluded\":\"pattern\"", stream); else if(d->flags & FF_OTHFS) - fputs(",\"excluded\":\"othfs", stream); + fputs(",\"excluded\":\"othfs\"", stream); fputc('}', stream); } @@ -107,7 +113,8 @@ static void output_info(struct dir *d) { * called with a stream that's in an error state. */ static int item(struct dir *item) { if(!item) { - if(!--level) { /* closing of the root item */ + nstack_pop(&stack); + if(!stack.top) { /* closing of the root item */ fputs("]]", stream); return fclose(stream); } else /* closing of a regular directory item */ @@ -119,7 +126,7 @@ static int item(struct dir *item) { /* File header. * TODO: Add scan options? */ - if(item->flags & FF_DIR && !level++) + if(!stack.top) fputs("[1,0,{\"progname\":\""PACKAGE"\",\"progver\":\""PACKAGE_VERSION"\"}", stream); fputs(",\n", stream); @@ -127,11 +134,16 @@ static int item(struct dir *item) { fputc('[', stream); output_info(item); + + if(item->flags & FF_DIR) + nstack_push(&stack, item->dev); + return ferror(stream); } static int final(int fail) { + nstack_free(&stack); return fail ? 1 : 1; /* Silences -Wunused-parameter */ } @@ -142,7 +154,8 @@ int dir_export_init(const char *fn) { else if((stream = fopen(fn, "w")) == NULL) return 1; - level = 0; + nstack_init(&stack); + pstate = ST_CALC; dir_output.item = item; dir_output.final = final; diff --git a/src/util.h b/src/util.h index ac6b46782b2513581540d194a2d45a1948066bc8..1213f98ad4e2647991cf74b14b12d1b38eef07e9 100644 --- a/src/util.h +++ b/src/util.h @@ -84,5 +84,26 @@ struct dir *getroot(struct dir *); /* Adds a value to the size, asize and items fields of *d and its parents */ void addparentstats(struct dir *, int64_t, int64_t, int); + +/* A simple stack implemented in macros */ +#define nstack_init(_s) do {\ + (_s)->size = 10;\ + (_s)->top = 0;\ + (_s)->list = malloc(10*sizeof(*(_s)->list));\ + } while(0) + +#define nstack_push(_s, _v) do {\ + if((_s)->size <= (_s)->top) {\ + (_s)->size *= 2;\ + (_s)->list = realloc((_s)->list, (_s)->size*sizeof(*(_s)->list));\ + }\ + (_s)->list[(_s)->top++] = _v;\ + } while(0) + +#define nstack_pop(_s) (_s)->top-- +#define nstack_top(_s, _d) ((_s)->top > 0 ? (_s)->list[(_s)->top-1] : (_d)) +#define nstack_free(_s) free((_s)->list) + + #endif