static void dump_line(const char *pathname, const struct trie_file *tf)
{
const char *p;
- printf("%llu %llu ", tf->size, tf->atime);
+ if (printf("%llu %llu ", tf->size, tf->atime) < 0) goto error;
for (p = pathname; *p; p++) {
- if (*p >= ' ' && *p < 127 && *p != '%')
- putchar(*p);
- else
- printf("%%%02x", (unsigned char)*p);
+ if (*p >= ' ' && *p < 127 && *p != '%') {
+ if (putchar(*p) == EOF) goto error;
+ } else {
+ if (printf("%%%02x", (unsigned char)*p) < 0) goto error;
+ }
}
- putchar('\n');
+ if (putchar('\n') == EOF) goto error;
+ return;
+ error:
+ fatal("standard output: %s", strerror(errno));
}
static int gotdata(void *vctx, const char *pathname, const STRUCT_STAT *st)
}
static void text_query(const void *mappedfile, const char *querydir,
- time_t t, int showfiles, int depth)
+ time_t t, int showfiles, int depth, FILE *fp)
{
size_t maxpathlen;
char *pathbuf;
if (size == 0)
return; /* no space taken up => no display */
- if (depth > 0) {
+ if (depth != 0) {
/*
* Now scan for first-level subdirectories and report
* those too.
*/
+ int newdepth = (depth > 0 ? depth - 1 : depth);
xi1++;
while (xi1 < xi2) {
trie_getpath(mappedfile, xi1, pathbuf);
- text_query(mappedfile, pathbuf, t, showfiles, depth-1);
+ text_query(mappedfile, pathbuf, t, showfiles, newdepth, fp);
make_successor(pathbuf);
xi1 = trie_before(mappedfile, pathbuf);
}
}
/* Display in units of 1Kb */
- printf("%-11llu %s\n", (size) / 1024, querydir);
+ fprintf(fp, "%-11llu %s\n", (size) / 1024, querydir);
}
/*
HELPOPT("[--web,--html,--text] list individual files") \
VAL(AGERANGE) SHORT(r) LONG(age_range) LONG(range) LONG(ages) \
HELPARG("age[-age]") HELPOPT("[--web,--html] set limits of colour coding") \
+ VAL(OUTFILE) SHORT(o) LONG(output) \
+ HELPARG("filename") HELPOPT("[--html] specify output file or directory name") \
VAL(SERVERADDR) LONG(address) LONG(addr) LONG(server_address) \
LONG(server_addr) \
HELPARG("addr[:port]") HELPOPT("[--web] specify HTTP server address") \
HELPARG("filename") HELPOPT("[--web] read HTTP Basic user/pass from file") \
VAL(AUTHFD) LONG(auth_fd) \
HELPARG("fd") HELPOPT("[--web] read HTTP Basic user/pass from fd") \
- VAL(TQDEPTH) SHORT(d) LONG(depth) LONG(max_depth) LONG(maximum_depth) \
- HELPARG("levels") HELPOPT("[--text] recurse to this many levels") \
+ VAL(DEPTH) SHORT(d) LONG(depth) LONG(max_depth) LONG(maximum_depth) \
+ HELPARG("levels") HELPOPT("[--text,--html] recurse to this many levels") \
VAL(MINAGE) SHORT(a) LONG(age) LONG(min_age) LONG(minimum_age) \
HELPARG("age") HELPOPT("[--text] include only files older than this") \
HELPPFX("also") \
const char *httpserveraddr = NULL;
int httpserverport = 0;
const char *httpauthdata = NULL;
+ const char *outfile = NULL;
int auth = HTTPD_AUTH_MAGIC | HTTPD_AUTH_BASIC;
int progress = 1;
struct inclusion_exclusion *inex = NULL;
int ninex = 0, inexsize = 0;
int crossfs = 0;
- int tqdepth = 1;
+ int depth = -1, gotdepth = 0;
int fakediratimes = 1;
int mtime = 0;
int showfiles = 0;
case OPT_DATAFILE:
filename = optval;
break;
- case OPT_TQDEPTH:
- tqdepth = atoi(optval);
+ case OPT_DEPTH:
+ if (!strcasecmp(optval, "unlimited") ||
+ !strcasecmp(optval, "infinity") ||
+ !strcasecmp(optval, "infinite") ||
+ !strcasecmp(optval, "inf") ||
+ !strcasecmp(optval, "maximum") ||
+ !strcasecmp(optval, "max"))
+ depth = -1;
+ else
+ depth = atoi(optval);
+ gotdepth = 1;
+ break;
+ case OPT_OUTFILE:
+ outfile = optval;
break;
case OPT_MINAGE:
textcutoff = parse_age(now, optval);
if (pathlen > 0 && querydir[pathlen-1] == pathsep)
querydir[--pathlen] = '\0';
- text_query(mappedfile, querydir, textcutoff, showfiles, tqdepth);
+ if (!gotdepth)
+ depth = 1; /* default for text mode */
+ if (outfile != NULL) {
+ FILE *fp = fopen(outfile, "w");
+ if (!fp) {
+ fprintf(stderr, "%s: %s: open: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ }
+ text_query(mappedfile, querydir, textcutoff, showfiles,
+ depth, fp);
+ fclose(fp);
+ } else {
+ text_query(mappedfile, querydir, textcutoff, showfiles,
+ depth, stdout);
+ }
munmap(mappedfile, totalsize);
} else if (mode == HTML) {
} else if (!index_has_root(mappedfile, xi)) {
fprintf(stderr, "%s: pathname '%s' is"
" a file, not a directory\n", PNAME, querydir);
- } else {
+ } else if (!gotdepth) {
+ /*
+ * Single output file.
+ */
cfg.format = NULL;
+ cfg.rootpage = NULL;
+ cfg.autoage = htmlautoagerange;
+ cfg.oldest = htmloldest;
+ cfg.newest = htmlnewest;
+ cfg.showfiles = showfiles;
+ html = html_query(mappedfile, xi, &cfg, 0);
+ if (outfile != NULL) {
+ FILE *fp = fopen(outfile, "w");
+ if (!fp) {
+ fprintf(stderr, "%s: %s: open: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ } else if (fputs(html, fp) < 0) {
+ fprintf(stderr, "%s: %s: write: %s\n", PNAME,
+ outfile, strerror(errno));
+ fclose(fp);
+ return 1;
+ } else if (fclose(fp) < 0) {
+ fprintf(stderr, "%s: %s: fclose: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ }
+ } else {
+ fputs(html, stdout);
+ }
+ } else {
+ /*
+ * Multiple output files.
+ */
+ int dirlen = outfile ? 2+strlen(outfile) : 3;
+ char prefix[dirlen];
+ if (outfile) {
+ if (mkdir(outfile, 0777) < 0 && errno != EEXIST) {
+ fprintf(stderr, "%s: %s: mkdir: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ }
+ snprintf(prefix, dirlen, "%s/", outfile);
+ } else
+ snprintf(prefix, dirlen, "./");
+
+ unsigned long xi2;
+ make_successor(pathbuf);
+ xi2 = trie_before(mappedfile, pathbuf);
+
+ cfg.format = "%lu.html";
+ cfg.rootpage = "index.html";
cfg.autoage = htmlautoagerange;
cfg.oldest = htmloldest;
cfg.newest = htmlnewest;
cfg.showfiles = showfiles;
- html = html_query(mappedfile, xi, &cfg);
- fputs(html, stdout);
+ if (html_dump(mappedfile, xi, xi2, depth, &cfg, prefix))
+ return 1;
}
munmap(mappedfile, totalsize);
dcfg.port = httpserverport;
dcfg.basicauthdata = httpauthdata;
pcfg.format = NULL;
+ pcfg.rootpage = NULL;
pcfg.autoage = htmlautoagerange;
pcfg.oldest = htmloldest;
pcfg.newest = htmlnewest;