index.c, instead of storing a distinct tree root for every entry in
[sgt/agedu] / html.c
diff --git a/html.c b/html.c
index 76ecd83..db6c25b 100644 (file)
--- a/html.c
+++ b/html.c
@@ -2,22 +2,12 @@
  * html.c: implementation of html.h.
  */
 
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <time.h>
-
+#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,
@@ -321,11 +320,20 @@ static void write_report_line(struct html *ctx, struct vector *vec)
     int i;
 
     /*
-     * Prevent divisions by zero.
+     * 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)
+    if (!divisor) {
        divisor = 1;
+    }
 
     /*
      * Find the total size of this subdirectory.
@@ -333,7 +341,7 @@ static void write_report_line(struct html *ctx, struct vector *vec)
     size = vec->sizes[MAXCOLOUR];
     htprintf(ctx, "<tr>\n"
             "<td style=\"padding: 0.2em; text-align: right\">%lluMb</td>\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.
@@ -376,12 +384,13 @@ static void write_report_line(struct html *ctx, struct vector *vec)
     htprintf(ctx, "</td>\n</tr>\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;
@@ -394,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, "<html>\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;
@@ -414,7 +423,7 @@ char *html_query(const void *t, unsigned long index, const char *format)
      */
     htprintf(ctx, "<head>\n");
     trie_getpath(t, index, path);
-    htprintf(ctx, "<title>agedu: ");
+    htprintf(ctx, "<title>%s: ", PNAME);
     htescape(ctx, path, strlen(path), 0);
     htprintf(ctx, "</title>\n");
     htprintf(ctx, "</head>\n");
@@ -432,26 +441,37 @@ char *html_query(const void *t, unsigned long index, const char *format)
      */
     htprintf(ctx, "<p align=center>\n<code>");
     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, "<a href=\"%s\">", 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, "</a>");
-       htprintf(ctx, "/");
+       htescape(ctx, zp, p - zp, 1);
+       q = p;
     }
     htescape(ctx, q, strlen(q), 1);
     htprintf(ctx, "</code>\n");
@@ -460,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;
@@ -510,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);
@@ -521,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++;