X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/agedu/blobdiff_plain/70322ae3751bc07ac749dffad79a5f3420e67b55..56cae6e16d22dfba1aafe91dc3465a684d808124:/html.c diff --git a/html.c b/html.c index 3ce87c0..db6c25b 100644 --- a/html.c +++ b/html.c @@ -2,22 +2,12 @@ * html.c: implementation of html.h. */ -#include -#include -#include -#include -#include -#include -#include -#include - +#include "agedu.h" #include "html.h" -#include "malloc.h" +#include "alloc.h" #include "trie.h" #include "index.h" -#define lenof(x) ( sizeof((x)) / sizeof(*(x)) ) - #define MAXCOLOUR 511 struct html { @@ -37,9 +27,16 @@ static void vhtprintf(struct html *ctx, char *fmt, va_list ap) { va_list ap2; int size, size2; + char testbuf[2]; va_copy(ap2, ap); - size = vsnprintf(NULL, 0, fmt, ap2); + /* + * Some C libraries (Solaris, I'm looking at you) don't like + * an output buffer size of zero in vsnprintf, but will return + * sensible values given any non-zero buffer size. Hence, we + * use testbuf to gauge the length of the string. + */ + size = vsnprintf(testbuf, 1, fmt, ap2); va_end(ap2); if (ctx->buflen + size >= ctx->bufsize) { @@ -164,12 +161,14 @@ static void get_indices(const void *t, char *path, unsigned long *xi1, unsigned long *xi2) { size_t pathlen = strlen(path); + int c1 = path[pathlen], c2 = (pathlen > 0 ? path[pathlen-1] : 0); *xi1 = trie_before(t, path); - path[pathlen] = '\001'; - path[pathlen+1] = '\0'; + make_successor(path); *xi2 = trie_before(t, path); - path[pathlen] = '\0'; + path[pathlen] = c1; + if (pathlen > 0) + path[pathlen-1] = c2; } static unsigned long long fetch_size(const void *t, char *path, @@ -316,17 +315,33 @@ static void print_heading(struct html *ctx, const char *title) #define PIXEL_SIZE 600 /* FIXME: configurability? */ static void write_report_line(struct html *ctx, struct vector *vec) { - unsigned long long size, asize; + unsigned long long size, asize, divisor; int pix, newpix; int i; /* + * A line with literally zero space usage should not be + * printed at all if it's a link to a subdirectory (since it + * probably means the whole thing was excluded by some + * --exclude-path wildcard). If it's [files] or the top-level + * line, though, we must always print _something_, and in that + * case we must fiddle about to prevent divisions by zero in + * the code below. + */ + if (!vec->sizes[MAXCOLOUR] && vec->want_href) + return; + divisor = ctx->totalsize; + if (!divisor) { + divisor = 1; + } + + /* * Find the total size of this subdirectory. */ size = vec->sizes[MAXCOLOUR]; htprintf(ctx, "\n" "%lluMb\n", - ((size + ((1<<11)-1)) >> 11)); /* convert to Mb, rounding up */ + ((size + ((1<<20)-1)) >> 20)); /* convert to Mb, rounding up */ /* * Generate a colour bar. @@ -336,7 +351,7 @@ static void write_report_line(struct html *ctx, struct vector *vec) pix = 0; for (i = 0; i <= MAXCOLOUR; i++) { asize = vec->sizes[i]; - newpix = asize * PIXEL_SIZE / ctx->totalsize; + newpix = asize * PIXEL_SIZE / divisor; add_to_colour_bar(ctx, i, newpix - pix); pix = newpix; } @@ -348,7 +363,7 @@ static void write_report_line(struct html *ctx, struct vector *vec) * Output size as a percentage of totalsize. */ htprintf(ctx, "" - "%.2f%%\n", (double)size / ctx->totalsize * 100.0); + "%.2f%%\n", (double)size / divisor * 100.0); /* * Output a subdirectory marker. @@ -369,12 +384,13 @@ static void write_report_line(struct html *ctx, struct vector *vec) htprintf(ctx, "\n\n"); } -char *html_query(const void *t, unsigned long index, const char *format) +char *html_query(const void *t, unsigned long index, + const struct html_config *cfg) { struct html actx, *ctx = &actx; char *path, *path2, *p, *q, *href; char agebuf1[80], agebuf2[80]; - size_t pathlen, hreflen; + size_t pathlen, subdirpos, hreflen; unsigned long index2; int i; struct vector **vecs; @@ -387,13 +403,13 @@ char *html_query(const void *t, unsigned long index, const char *format) ctx->buf = NULL; ctx->buflen = ctx->bufsize = 0; ctx->t = t; - ctx->format = format; + ctx->format = cfg->format; htprintf(ctx, "\n"); path = snewn(1+trie_maxpathlen(t), char); ctx->path2 = path2 = snewn(1+trie_maxpathlen(t), char); - if (format) { - hreflen = strlen(format) + 100; + if (cfg->format) { + hreflen = strlen(cfg->format) + 100; href = snewn(hreflen, char); } else { hreflen = 0; @@ -407,7 +423,7 @@ char *html_query(const void *t, unsigned long index, const char *format) */ htprintf(ctx, "\n"); trie_getpath(t, index, path); - htprintf(ctx, "agedu: "); + htprintf(ctx, "<title>%s: ", PNAME); htescape(ctx, path, strlen(path), 0); htprintf(ctx, "\n"); htprintf(ctx, "\n"); @@ -425,26 +441,37 @@ char *html_query(const void *t, unsigned long index, const char *format) */ htprintf(ctx, "

\n"); q = path; - for (p = strchr(path, '/'); p; p = strchr(p+1, '/')) { + for (p = strchr(path, pathsep); p && p[1]; p = strchr(p, pathsep)) { int doing_href = 0; + char c, *zp; + /* * See if this path prefix exists in the trie. If so, * generate a hyperlink. */ - *p = '\0'; + zp = p; + if (p == path) /* special case for "/" at start */ + zp++; + + p++; + + c = *zp; + *zp = '\0'; index2 = trie_before(t, path); trie_getpath(t, index2, path2); - if (!strcmp(path, path2) && format) { - snprintf(href, hreflen, format, index2); + if (!strcmp(path, path2) && cfg->format) { + snprintf(href, hreflen, cfg->format, index2); + if (!*href) /* special case that we understand */ + strcpy(href, "./"); htprintf(ctx, "", href); doing_href = 1; } - *p = '/'; - htescape(ctx, q, p - q, 1); - q = p + 1; + *zp = c; + htescape(ctx, q, zp - q, 1); if (doing_href) htprintf(ctx, ""); - htprintf(ctx, "/"); + htescape(ctx, zp, p - zp, 1); + q = p; } htescape(ctx, q, strlen(q), 1); htprintf(ctx, "\n"); @@ -453,11 +480,18 @@ char *html_query(const void *t, unsigned long index, const char *format) * Decide on the age limit of our colour coding, establish the * colour thresholds, and write out a key. */ - ctx->oldest = index_order_stat(t, 0.05); /* FIXME: configurability? */ - ctx->newest = index_order_stat(t, 1.0); ctx->now = time(NULL); - ctx->oldest = round_and_format_age(ctx, ctx->oldest, agebuf1, -1); - ctx->newest = round_and_format_age(ctx, ctx->newest, agebuf2, +1); + if (cfg->autoage) { + ctx->oldest = index_order_stat(t, 0.05); + ctx->newest = index_order_stat(t, 1.0); + ctx->oldest = round_and_format_age(ctx, ctx->oldest, agebuf1, -1); + ctx->newest = round_and_format_age(ctx, ctx->newest, agebuf2, +1); + } else { + ctx->oldest = cfg->oldest; + ctx->newest = cfg->newest; + ctx->oldest = round_and_format_age(ctx, ctx->oldest, agebuf1, 0); + ctx->newest = round_and_format_age(ctx, ctx->newest, agebuf2, 0); + } for (i = 0; i < MAXCOLOUR-1; i++) { ctx->thresholds[i] = ctx->oldest + (ctx->newest - ctx->oldest) * i / MAXCOLOUR; @@ -503,6 +537,9 @@ char *html_query(const void *t, unsigned long index, const char *format) get_indices(t, path, &xi1, &xi2); xi1++; pathlen = strlen(path); + subdirpos = pathlen + 1; + if (pathlen > 0 && path[pathlen-1] == pathsep) + subdirpos--; while (xi1 < xi2) { trie_getpath(t, xi1, path2); get_indices(t, ctx->path2, &xj1, &xj2); @@ -514,7 +551,7 @@ char *html_query(const void *t, unsigned long index, const char *format) vecs = sresize(vecs, vecsize, struct vector *); } assert(strlen(path2) > pathlen); - vecs[nvecs] = make_vector(ctx, path2, 1, path2 + pathlen + 1); + vecs[nvecs] = make_vector(ctx, path2, 1, path2 + subdirpos); for (i = 0; i <= MAXCOLOUR; i++) vecs[0]->sizes[i] -= vecs[nvecs]->sizes[i]; nvecs++;