From 39691861000586efaf0f6fdead742f73c7c734a3 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 15 Feb 2018 10:18:59 +0200 Subject: Support for configurable icons in fancy listing mode * src/icon.c: New file. * src/Makefile.am: Add new sources. * src/catfile.c (catfile_n): Compress trailing slashes in dir, and remove such in file. This makes sure that the returned value never ends in slash, which is necessary in particular for lstat to work correctly. * src/config.c: New global keywords: name-icon, type-icon and mime-icon. * src/defidx.html: Update. * src/fileserv.h: Update. * src/idx.c: New expansion command: iconlookup. Rename icon to iconsrc, and alt to iconalt. --- src/Makefile.am | 2 +- src/catfile.c | 31 +++++++++------- src/config.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/defidx.html | 12 +++---- src/fileserv.h | 15 ++++++++ src/icon.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/idx.c | 60 +++++++++++++++++++++---------- 7 files changed, 291 insertions(+), 38 deletions(-) create mode 100644 src/icon.c diff --git a/src/Makefile.am b/src/Makefile.am index 657e47b..b793023 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ bin_PROGRAMS=fileserv fileserv_SOURCES=fileserv.c runas.c fileserv.h logger.c pidfile.c\ wordsplit.c wordsplit.h catfile.c config.c idx.c defidx.h\ - mem.c remoteip.c + mem.c remoteip.c icon.c BUILT_SOURCES=defidx.h if FSRV_WRAP fileserv_SOURCES += wrapacl.c diff --git a/src/catfile.c b/src/catfile.c index 56ee0a9..929e15e 100644 --- a/src/catfile.c +++ b/src/catfile.c @@ -5,21 +5,26 @@ char * catfile_n(char const *dir, size_t len, char const *file) { - size_t sz; - char *p; + size_t flen; + char *res, *p; - sz = len; - if (sz > 0 && dir[sz-1] != '/') - sz++; - if (*file == '/') + while (len > 0 && dir[len-1] == '/') + len--; + while (*file == '/') file++; - sz += strlen(file); - p = xmalloc(sz + 1); - memcpy(p, dir, len); - if (p[len-1] != '/') - p[len++] = '/'; - strcpy(p + len, file); - return p; + flen = strlen(file); + while (flen && file[flen-1] == '/') + --flen; + res = xmalloc(len + flen + 2); + memcpy(res, dir, len); + p = res + len; + if (flen) { + *p++ = '/'; + memcpy(p, file, flen); + p += flen; + } + *p = 0; + return res; } char * diff --git a/src/config.c b/src/config.c index 1cb591d..a7561e7 100644 --- a/src/config.c +++ b/src/config.c @@ -438,6 +438,103 @@ set_mapping(size_t argc, char **argv, CONFIG *conf, return 0; } +/* set-mime-icon icon [ALT=X] mime-type ... + */ +static int +set_mime_icon(size_t argc, char **argv, CONFIG *conf, + char const *file, int line) +{ + size_t i; + char const *icon; + char const *alt = NULL; + + if (argc < 3) { + error("%s:%d: expected two or more arguments", file, line); + return 1; + } + + icon = argv[1]; + + i = 2; + if (strncasecmp(argv[i], "alt=", 4) == 0) { + alt = argv[i] + 4; + i++; + } + + if (i == argc) { + error("%s:%d: expected one or more mime types", file, line); + return 1; + } + + + for (; i < argc; i++) + add_icon_by_mime(argv[i], icon, alt); + + return 0; +} + +static int +set_name_icon(size_t argc, char **argv, CONFIG *conf, + char const *file, int line) +{ + size_t i; + char const *icon; + char const *alt = NULL; + + if (argc < 3) { + error("%s:%d: expected two or more arguments", file, line); + return 1; + } + + icon = argv[1]; + + i = 2; + if (strncasecmp(argv[i], "alt=", 4) == 0) { + alt = argv[i] + 4; + i++; + } + + if (i == argc) { + error("%s:%d: expected one or more mime types", file, line); + return 1; + } + + + for (; i < argc; i++) + add_icon_by_name(argv[i], icon, alt); + + return 0; +} + +static int +set_type_icon(size_t argc, char **argv, CONFIG *conf, + char const *file, int line) +{ + size_t i; + char const *icon; + char const *alt = NULL; + + if (argc < 3) { + error("%s:%d: expected two or three arguments", file, line); + return 1; + } + + icon = argv[1]; + + i = 2; + if (strncasecmp(argv[i], "alt=", 4) == 0) { + alt = argv[i] + 4; + i++; + } + + if (i == argc) { + error("%s:%d: expected file type", file, line); + return 1; + } + + add_icon_by_type(argv[i], icon, alt); + return 0; +} struct config_keyword { @@ -453,6 +550,9 @@ static struct config_keyword keywords[] = { { CTXGLOB, "listen", set_listen }, { CTXGLOB, "index-template", set_index_template }, { CTXGLOB, "index-css", set_index_css }, + { CTXGLOB, "mime-icon", set_mime_icon }, + { CTXGLOB, "name-icon", set_name_icon }, + { CTXGLOB, "type-icon", set_type_icon }, { CTXGLOB, "access-file-name", set_dotfile }, { CTXGLOB, "forwarded-header", set_forwarded_header }, { CTXGLOB, "trusted-proxy", set_trusted_proxy }, diff --git a/src/defidx.html b/src/defidx.html index 12bea9f..385eeec 100644 --- a/src/defidx.html +++ b/src/defidx.html @@ -11,8 +11,8 @@
- {% if $(icon blank) %} - [ICO] + {% if $(iconlookup BLANK) %} + [{% $(iconalt) %}] {% else %} [ICO] {% endif %} @@ -36,8 +36,8 @@ {% if $(updir $URI) %}
- {% if $(icon back) %} - [PARENTDIR] + {% if $(iconlookup "..") %} +  {% $(iconalt) %}] {% else %} [PARENTDIR] {% endif %} @@ -53,8 +53,8 @@ {% loop %}
- {% if $(icon $MIMETYPE) %} - [{% $(alt $MIMETYPE) %}] + {% if $(iconlookup "$FILENAME" "$MIMETYPE" "$FILETYPE") %} + [{% $(iconalt) %}] {% else %} [{% $FILETYPE %}] {% endif %} diff --git a/src/fileserv.h b/src/fileserv.h index 1eda56b..d22d927 100644 --- a/src/fileserv.h +++ b/src/fileserv.h @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef SIZE_T_MAX # define SIZE_T_MAX ((size_t)-1) @@ -127,3 +128,17 @@ void parse_template_file(char const *file_name); void trusted_ip_add(char const *s); struct MHD_Connection; char *get_remote_ip(struct MHD_Connection *conn); + +typedef struct icon { + char *name; + char *src; + char *alt; + TAILQ_ENTRY(icon) link; +} ICON; + +ICON const *icon_by_mime(char const *type); +void add_icon_by_mime(char const *type, char const *src, char const *alt); +ICON const *icon_by_name(char const *name); +void add_icon_by_name(char const *name, char const *src, char const *alt); +ICON const *icon_by_type(char const *type); +void add_icon_by_type(char const *name, char const *src, char const *alt); diff --git a/src/icon.c b/src/icon.c new file mode 100644 index 0000000..cd77968 --- /dev/null +++ b/src/icon.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include "fileserv.h" + +typedef TAILQ_HEAD(icon_list,icon) ICON_LIST; + +static void +add_icon(ICON_LIST *lst, char const *type, char const *src, char const *alt) +{ + ICON *icon; + + icon = xcalloc(1, sizeof(icon[0])); + icon->name = xstrdup(type); + icon->src = xstrdup(src); + icon->alt = alt ? xstrdup(alt) : NULL; + + TAILQ_INSERT_TAIL(lst, icon, link); +} + +static ICON_LIST mime_icon_list = TAILQ_HEAD_INITIALIZER(mime_icon_list); + +ICON const * +icon_by_mime(char const *type) +{ + ICON *icon; + + TAILQ_FOREACH(icon, &mime_icon_list, link) { + if (fnmatch(icon->name, type, 0) == 0) + return icon; + } + return NULL; +} + +void +add_icon_by_mime(char const *type, char const *src, char const *alt) +{ + return add_icon(&mime_icon_list, type, src, alt); +} + +static ICON_LIST suf_icon_list = TAILQ_HEAD_INITIALIZER(suf_icon_list); + +void +add_icon_by_name(char const *name, char const *src, char const *alt) +{ + ICON *icon, *cur; + size_t len, i; + + icon = xcalloc(1, sizeof(icon[0])); + len = strlen(name); + icon->name = xmalloc(len + 1); + for (i = 0; i < len; i++) + icon->name[i] = name[len-i-1]; + icon->name[i] = 0; + icon->src = xstrdup(src); + icon->alt = alt ? xstrdup(alt) : NULL; + + TAILQ_FOREACH(cur, &suf_icon_list, link) { + if (strlen(cur->name) < len) { + TAILQ_INSERT_BEFORE(cur, icon, link); + return; + } + } + TAILQ_INSERT_TAIL(&suf_icon_list, icon, link); +} + +static int +sufcmp(char const *suf, char const *end, char const *beg) +{ + while (*suf) { + if (end == beg || *suf++ != *--end) + return 1; + } + return 0; +} + +ICON const * +icon_by_name(char const *name) +{ + ICON *icon; + char const *end = name + strlen(name); + + TAILQ_FOREACH(icon, &suf_icon_list, link) { + if (sufcmp(icon->name, end, name) == 0) + return icon; + } + return NULL; +} + +static ICON_LIST type_icon_list = TAILQ_HEAD_INITIALIZER(type_icon_list); + +ICON const * +icon_by_type(char const *type) +{ + ICON *icon; + + TAILQ_FOREACH(icon, &type_icon_list, link) { + if (strcmp(icon->name, type) == 0) + return icon; + } + return NULL; +} + +void +add_icon_by_type(char const *name, char const *src, char const *alt) +{ + return add_icon(&type_icon_list, name, src, alt); +} + diff --git a/src/idx.c b/src/idx.c index 8a74754..bd1286f 100644 --- a/src/idx.c +++ b/src/idx.c @@ -436,6 +436,7 @@ typedef struct { int wsflags; INDEX_SORT_COL col; INDEX_SORT_ORD ord; + ICON const *icon; #define expansion ws.ws_wordv[0] } EVAL_ENV; @@ -602,7 +603,7 @@ exp_filetype(char **ret, EVAL_ENV *env) { char const *s = " "; if (env->ent) - s = S_ISDIR(env->ent->st.st_mode) ? "DIR" : "FILE"; + s = S_ISDIR(env->ent->st.st_mode) ? "DIRECTORY" : "FILE"; *ret = xstrdup(s); return WRDSE_OK; } @@ -636,24 +637,43 @@ template_getvar(char **ret, const char *var, size_t len, void *clos) } static int -cmd_alt(char **ret, char **argv, EVAL_ENV *env) -{ - char *s = strdup(argv[1] ? argv[1] : ""); - if (!s) - return WRDSE_NOSPACE; - *ret = s; - for (; *s; s++) - *s = toupper(*s); - return WRDSE_OK; +cmd_iconlookup(char **ret, char **argv, EVAL_ENV *env) +{ + ICON const *icon = NULL; + if (argv[1]) { + icon = icon_by_name(argv[1]); + if (!icon && argv[2]) { + icon = icon_by_mime(argv[2]); + if (!icon && argv[3]) + icon = icon_by_type(argv[3]); + } + } + env->icon = icon; + *ret = strdup(icon ? icon->src : ""); + return *ret ? WRDSE_OK : WRDSE_NOSPACE; } static int -cmd_icon(char **ret, char **argv, EVAL_ENV *env) +cmd_iconsrc(char **ret, char **argv, EVAL_ENV *env) { - /* FIXME */ - *ret = strdup(""); + char const *s = ""; + if (env->icon) + s = env->icon->src; + + *ret = strdup(s); return *ret ? WRDSE_OK : WRDSE_NOSPACE; -} +} + +static int +cmd_iconalt(char **ret, char **argv, EVAL_ENV *env) +{ + char const *s = ""; + if (env->icon && env->icon->alt) + s = env->icon->alt; + + *ret = strdup(s); + return *ret ? WRDSE_OK : WRDSE_NOSPACE; +} static int cmd_updir(char **ret, char **argv, EVAL_ENV *env) @@ -695,12 +715,16 @@ static int template_command(char **ret, const char *cmd, size_t len, char **argv, void *clos) { - if (strcmp(argv[0], "icon") == 0) { - return cmd_icon(ret, argv, clos); + if (strcmp(argv[0], "iconlookup") == 0) { + return cmd_iconlookup(ret, argv, clos); + } + + if (strcmp(argv[0], "iconsrc") == 0) { + return cmd_iconsrc(ret, argv, clos); } - if (strcmp(argv[0], "alt") == 0) { - return cmd_alt(ret, argv, clos); + if (strcmp(argv[0], "iconalt") == 0) { + return cmd_iconalt(ret, argv, clos); } if (strcmp(argv[0], "updir") == 0) { -- cgit v1.2.1