summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-02-16 12:34:53 +0200
committerSergey Poznyakoff <gray@gnu.org>2018-02-16 12:34:53 +0200
commitc93a6c17a2af32dd15c09adb926088d353ff800d (patch)
tree3d99f16caeb62c1a7b9d238031247e01f5a35f6e
parentbbb854527f0b841ffedbc2ba769ad495cd13a34d (diff)
downloadfileserv-c93a6c17a2af32dd15c09adb926088d353ff800d.tar.gz
fileserv-c93a6c17a2af32dd15c09adb926088d353ff800d.tar.bz2
Cleanup
Move the directory listing code into a separate module. Improve error reporting in directory index code. Don't bail out on (most of the) out of memory errors. * src/dirls.c: New file. * src/dirls.h: New file. * src/fileserv.c (errno_to_http_code): Increase resolution. * src/fileserv.h (parse_template_string) (parse_template_file): Change return value.
-rw-r--r--src/Makefile.am2
-rw-r--r--src/config.c5
-rw-r--r--src/dirls.c247
-rw-r--r--src/dirls.h17
-rw-r--r--src/fileserv.c24
-rw-r--r--src/fileserv.h4
-rw-r--r--src/idx.c669
7 files changed, 598 insertions, 370 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index b793023..d812da5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,3 +3,3 @@ 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 icon.c
+ mem.c remoteip.c icon.c dirls.c dirls.h
BUILT_SOURCES=defidx.h
diff --git a/src/config.c b/src/config.c
index a7561e7..adcc677 100644
--- a/src/config.c
+++ b/src/config.c
@@ -319,3 +319,6 @@ set_index_template(size_t argc, char **argv, CONFIG *conf,
}
- parse_template_file(argv[1]);
+ if (parse_template_file(argv[1])) {
+ error("%s:%d: invalid template", file, line);
+ return 1;
+ }
return 0;
diff --git a/src/dirls.c b/src/dirls.c
new file mode 100644
index 0000000..62ce71c
--- /dev/null
+++ b/src/dirls.c
@@ -0,0 +1,247 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/queue.h>
+#include <string.h>
+#include <unistd.h>
+#include "fileserv.h"
+#include "dirls.h"
+#include "mimetypes.h"
+
+void
+dirls_init(DIRLS *lst)
+{
+ lst->count = 0;
+ STAILQ_INIT(&lst->list);
+}
+
+void
+dirls_free(DIRLS *lst)
+{
+ DIRLSENT *ent;
+
+ while ((ent = STAILQ_FIRST(&lst->list))) {
+ STAILQ_REMOVE_HEAD(&lst->list, next);
+ free(ent);
+ }
+ lst->count = 0;
+}
+
+static void
+dirls_append(DIRLS *lst, DIRLSENT *ent)
+{
+ STAILQ_INSERT_TAIL(&lst->list, ent, next);
+ lst->count++;
+}
+
+int
+dirls_scan(DIRLS *dirls, char const *path, CONFIG const *conf)
+{
+ DIR *dir;
+ struct dirent *ent;
+ DIRLSENT *dirlsent;
+ int err = 0;
+
+ dir = opendir(path);
+ if (!dir) {
+ err = errno;
+ error("can't open directory %s: %s",
+ path, strerror(err));
+ return err;
+ }
+ dirls_init(dirls);
+ while (err == 0 && (ent = readdir(dir))) {
+ size_t len;
+ char *name;
+ struct stat st;
+
+ if (filename_is_hidden(ent->d_name, conf))
+ continue;
+
+ name = catfile(path, ent->d_name);
+ if (!name) {
+ err = errno;
+ break;
+ }
+
+ if (stat(name, &st)) {
+ error("can't stat %s: %s", name, strerror(errno));
+ free(name);
+ continue;
+ }
+
+ if (conf->list_unreadable == 0) {
+ if (access(name, R_OK)) {
+ free(name);
+ continue;
+ }
+ }
+
+ len = strlen(ent->d_name);
+ dirlsent = malloc(sizeof(*dirlsent)
+ + len
+ + (S_ISDIR(st.st_mode) ? 1 : 0)
+ + 1);
+ if (!dirlsent)
+ err = errno;
+ else {
+ dirlsent->name = (char*)(dirlsent + 1);
+ memcpy(dirlsent->name, ent->d_name, len);
+ if (S_ISDIR(st.st_mode))
+ dirlsent->name[len++] = '/';
+ dirlsent->name[len] = 0;
+
+ dirlsent->st = st;
+ dirlsent->type = get_file_type(name);
+ dirls_append(dirls, dirlsent);
+ }
+ free(name);
+ }
+ closedir(dir);
+
+ if (err)
+ dirls_free(dirls);
+
+ return err;
+}
+
+static void
+dirls_qsort(DIRLS *list, int cmp (DIRLSENT const *, DIRLSENT const *, void *),
+ void *data)
+{
+ if (list->count < 2)
+ return;
+ else if (list->count == 2) {
+ DIRLSENT *a, *b;
+ a = STAILQ_FIRST(&list->list);
+ b = STAILQ_NEXT(a, next);
+ if (cmp(a, b, data) > 0) {
+ STAILQ_REMOVE_HEAD(&list->list, next);
+ STAILQ_INSERT_TAIL(&list->list, a, next);
+ }
+ } else {
+ DIRLSENT *cur, *middle;
+ DIRLS high, low;
+ int rc;
+
+ cur = middle = STAILQ_FIRST(&list->list);
+ do {
+ cur = STAILQ_NEXT(cur, next);
+ if (!cur)
+ return;
+ } while ((rc = cmp(middle, cur, data)) == 0);
+
+ if (rc > 0)
+ middle = cur;
+
+ dirls_init(&high);
+ dirls_init(&low);
+
+ while ((cur = STAILQ_FIRST(&list->list))) {
+ STAILQ_REMOVE_HEAD(&list->list, next);
+ if (cmp(middle, cur, data) < 0)
+ dirls_append(&high, cur);
+ else
+ dirls_append(&low, cur);
+ }
+
+ /* Sort both lists */
+ dirls_qsort(&low, cmp, data);
+ dirls_qsort(&high, cmp, data);
+
+ /* Join lists in order and return */
+ STAILQ_CONCAT(&low.list, &high.list);
+ list->list = low.list;
+ list->count = low.count + high.count;
+ }
+}
+
+static char ordargs[] = "AD";
+static char colargs[] = "NMSD";
+
+INDEX_SORT_COL
+index_sort_col_from_arg(int c)
+{
+ char const *p;
+ if ((p = strchr(colargs, c)))
+ return p - colargs;
+ return ISC_NAME;
+}
+
+int
+index_sort_col_to_arg(INDEX_SORT_COL c)
+{
+ return colargs[c];
+}
+
+INDEX_SORT_ORD
+index_sort_ord_from_arg(int c)
+{
+ char const *p;
+ if ((p = strchr(ordargs, c)))
+ return p - ordargs;
+ return ISO_ASC;
+}
+
+int
+index_sort_ord_to_arg(INDEX_SORT_ORD c)
+{
+ return ordargs[c];
+}
+
+static inline int
+comp_result(int val, void *data)
+{
+ if (*(INDEX_SORT_ORD*)data == ISO_DESC)
+ val = -val;
+ return val;
+}
+
+static int
+comp_name(DIRLSENT const *a, DIRLSENT const *b, void *data)
+{
+ return comp_result(strcmp(a->name, b->name), data);
+}
+
+static int
+comp_time(DIRLSENT const *a, DIRLSENT const *b, void *data)
+{
+ int r;
+ if (a->st.st_mtime < b->st.st_mtime)
+ r = -1;
+ else if (a->st.st_mtime > b->st.st_mtime)
+ r = 1;
+ else
+ r = 0;
+ return comp_result(r, data);
+}
+
+static int
+comp_size(DIRLSENT const *a, DIRLSENT const *b, void *data)
+{
+ int r;
+ if (a->st.st_size < b->st.st_size)
+ r = -1;
+ else if (a->st.st_size > b->st.st_size)
+ r = 1;
+ else
+ r = 0;
+ return comp_result(r, data);
+}
+
+static int (*comp[])(DIRLSENT const *, DIRLSENT const *, void *) = {
+ comp_name,
+ comp_time,
+ comp_size,
+ comp_name
+};
+
+void
+dirls_sort(DIRLS *dirls, INDEX_SORT_COL col, INDEX_SORT_ORD ord)
+{
+ dirls_qsort(dirls, comp[col], &ord);
+}
+
diff --git a/src/dirls.h b/src/dirls.h
new file mode 100644
index 0000000..0067bff
--- /dev/null
+++ b/src/dirls.h
@@ -0,0 +1,17 @@
+typedef struct dirlsent {
+ char *name;
+ struct stat st;
+ char const *type;
+ STAILQ_ENTRY(dirlsent) next;
+} DIRLSENT;
+
+typedef struct dirls {
+ size_t count;
+ STAILQ_HEAD(, dirlsent) list;
+} DIRLS;
+
+void dirls_init(DIRLS *dirls);
+void dirls_free(DIRLS *dirls);
+int dirls_scan(DIRLS *dirls, char const *path, CONFIG const *conf);
+void dirls_sort(DIRLS *dirls, INDEX_SORT_COL col, INDEX_SORT_ORD ord);
+
diff --git a/src/fileserv.c b/src/fileserv.c
index 98c0c33..ae1599d 100644
--- a/src/fileserv.c
+++ b/src/fileserv.c
@@ -66,2 +66,17 @@ fileserv_panic(void *cls, const char *file, unsigned int line,
+static inline int
+errno_to_http_code(int ec)
+{
+ switch (ec) {
+ case EINVAL:
+ case ENOSYS:
+ case ENOMEM:
+ return MHD_HTTP_INTERNAL_SERVER_ERROR;
+ case ENOENT:
+ return MHD_HTTP_NOT_FOUND;
+ default:
+ return MHD_HTTP_FORBIDDEN;
+ }
+}
+
void
@@ -247,9 +262,2 @@ cfname(char const *fname)
-
-static inline int
-errno_to_http_code(int ec)
-{
- return ec == ENOENT ? MHD_HTTP_NOT_FOUND : MHD_HTTP_FORBIDDEN;
-}
-
static int
@@ -439,3 +447,3 @@ get_file_resp(struct MHD_Connection *conn, char const *url, FILE_RESP *resp)
close(fd);
- return MHD_HTTP_FORBIDDEN;
+ return errno_to_http_code(res);
}
diff --git a/src/fileserv.h b/src/fileserv.h
index d22d927..cf72b39 100644
--- a/src/fileserv.h
+++ b/src/fileserv.h
@@ -124,4 +124,4 @@ int filename_is_valid(char const *name);
-void parse_template_string(char const *str);
-void parse_template_file(char const *file_name);
+int parse_template_string(char const *str);
+int parse_template_file(char const *file_name);
diff --git a/src/idx.c b/src/idx.c
index be5b87c..1db1370 100644
--- a/src/idx.c
+++ b/src/idx.c
@@ -7,4 +7,2 @@
#include <sys/queue.h>
-#include <sys/types.h>
-#include <dirent.h>
#include <unistd.h>
@@ -13,6 +11,6 @@
#include "fileserv.h"
-#include "mimetypes.h"
+#include "dirls.h"
#include "wordsplit.h"
-enum index_node_type {
+enum tmpl_node_type {
NODE_TEXT,
@@ -23,16 +21,16 @@ enum index_node_type {
-typedef STAILQ_HEAD(index_node_list, index_node) INDEX_NODE_LIST;
+typedef STAILQ_HEAD(tmpl_node_list, tmpl_node) TMPL_NODE_LIST;
-struct index_cond {
+struct tmpl_cond {
char *expr;
- INDEX_NODE_LIST branch[2];
+ TMPL_NODE_LIST branch[2];
};
-struct index_node {
+struct tmpl_node {
int type;
- STAILQ_ENTRY(index_node) next;
+ STAILQ_ENTRY(tmpl_node) next;
union {
char *text;
- struct index_node_list loop;
- struct index_cond cond;
+ struct tmpl_node_list loop;
+ struct tmpl_cond cond;
} v;
@@ -40,6 +38,6 @@ struct index_node {
-typedef struct index_node INDEX_NODE;
+typedef struct tmpl_node TMPL_NODE;
struct condition {
- INDEX_NODE *node;
+ TMPL_NODE *node;
int brn;
@@ -49,2 +47,142 @@ typedef STAILQ_HEAD(, condition) COND_LIST;
+struct eval_env;
+
+/* Type-agnostic node functions */
+
+struct node_class {
+ void (*node_init)(TMPL_NODE *);
+ void (*node_free)(TMPL_NODE *);
+ int (*node_eval)(TMPL_NODE *, struct eval_env *);
+};
+
+static int node_text_eval(TMPL_NODE *, struct eval_env *);
+static int node_loop_eval(TMPL_NODE *, struct eval_env *);
+static int node_cond_eval(TMPL_NODE *, struct eval_env *);
+static int node_expr_eval(TMPL_NODE *, struct eval_env *);
+
+static void node_loop_init(TMPL_NODE *);
+static void node_loop_free(TMPL_NODE *);
+
+static void node_cond_init(TMPL_NODE *);
+static void node_cond_free(TMPL_NODE *);
+
+static struct node_class node_class[] = {
+ [NODE_TEXT] = { NULL, NULL, node_text_eval },
+ [NODE_LOOP] = { node_loop_init, node_loop_free, node_loop_eval },
+ [NODE_COND] = { node_cond_init, node_cond_free, node_cond_eval },
+ [NODE_EXPR] = { NULL, NULL, node_expr_eval }
+};
+
+#define ASSERT_NODE_TYPE(n) \
+ assert((n)->type >= 0 && (n)->type <= sizeof(node_class)/sizeof(node_class[0]))
+
+static void
+node_init(TMPL_NODE *node)
+{
+ ASSERT_NODE_TYPE(node);
+ if (node_class[node->type].node_init)
+ return node_class[node->type].node_init(node);
+}
+
+static void
+node_free(TMPL_NODE *node)
+{
+ ASSERT_NODE_TYPE(node);
+ if (node_class[node->type].node_free)
+ node_class[node->type].node_free(node);
+ free(node);
+}
+
+static int
+node_eval(TMPL_NODE *node, struct eval_env *env)
+{
+ ASSERT_NODE_TYPE(node);
+ assert(node_class[node->type].node_eval);
+ return node_class[node->type].node_eval(node, env);
+}
+
+
+/* Node list functions */
+
+static void
+node_list_free(TMPL_NODE_LIST *nlist)
+{
+ TMPL_NODE *node;
+
+ while ((node = STAILQ_FIRST(nlist))) {
+ STAILQ_REMOVE_HEAD(nlist, next);
+ node_free(node);
+ }
+}
+
+static int
+node_list_eval(TMPL_NODE_LIST *nlist, struct eval_env *env)
+{
+ TMPL_NODE *node;
+ int rc = 0;
+
+ STAILQ_FOREACH(node, nlist, next) {
+ rc = node_eval(node, env);
+ if (rc)
+ break;
+ }
+ return rc;
+}
+
+/* Node-specific initialization and deallocation functions */
+static void
+node_loop_init(TMPL_NODE *node)
+{
+ STAILQ_INIT(&node->v.loop);
+}
+
+static void
+node_loop_free(TMPL_NODE *node)
+{
+ node_list_free(&node->v.loop);
+}
+
+static void
+node_cond_init(TMPL_NODE *node)
+{
+ STAILQ_INIT(&node->v.cond.branch[0]);
+ STAILQ_INIT(&node->v.cond.branch[1]);
+}
+
+static void
+node_cond_free(TMPL_NODE *node)
+{
+ node_list_free(&node->v.cond.branch[0]);
+ node_list_free(&node->v.cond.branch[1]);
+}
+
+/* Parser error codes */
+enum {
+ TMPL_NOERR,
+ TMPL_ERR_LOOP_NESTING,
+ TMPL_ERR_ENDLOOP_WITHOUT_LOOP,
+ TMPL_ERR_ENDIF_WITHOUT_IF,
+ TMPL_ERR_ELSE_WITHOUT_IF,
+ TMPL_ERR_DUP_ELSE,
+ TMPL_ERR_ESCAPE_NOT_CLOSED,
+ TMPL_ERR_LOOP_NOT_CLOSED,
+ TMPL_ERR_COND_NOT_CLOSED,
+ TMPL_ERR_NOMEM
+};
+
+/* Corresponding textual descriptions */
+static char const *tmpl_err_str[] = {
+ "no error",
+ "attempt to nest loops",
+ "endloop without loop",
+ "endif without if",
+ "else without if",
+ "duplicate else",
+ "escape not closed",
+ "loop not closed",
+ "conditional not closed",
+ "not enough memory"
+};
+
+/* Template parser state */
struct template_state {
@@ -55,14 +193,30 @@ struct template_state {
char const *cur;
+ int error;
};
-static void parse_template(INDEX_NODE_LIST *nodes, struct template_state *st);
+/* Allocate and initialize single node */
+static inline TMPL_NODE *
+node_alloc(struct template_state *st, int type, size_t extra)
+{
+ TMPL_NODE *np = calloc(1, sizeof(*np) + extra);
+ if (np)
+ np->type = type;
+ else
+ st->error = TMPL_ERR_NOMEM;
+ node_init(np);
+ return np;
+}
+
+/* Template parser */
+static void parse_template(TMPL_NODE_LIST *nodes, struct template_state *st);
-static INDEX_NODE *
-new_text_node(int type, char const *start, size_t len)
+static TMPL_NODE *
+new_text_node(struct template_state *st, int type, size_t len)
{
- INDEX_NODE *np = xmalloc(sizeof(*np));
- np->type = type;
- np->v.text = xmalloc(len + 1);
- memcpy(np->v.text, start, len);
- np->v.text[len] = 0;
+ TMPL_NODE *np = node_alloc(st, type, len + 1);
+ if (np) {
+ np->v.text = (char*)(np + 1);
+ memcpy(np->v.text, st->start, len);
+ np->v.text[len] = 0;
+ }
return np;
@@ -70,3 +224,3 @@ new_text_node(int type, char const *start, size_t len)
-static INDEX_NODE *
+static TMPL_NODE *
next_text_node(struct template_state *st)
@@ -82,6 +236,6 @@ next_text_node(struct template_state *st)
- return new_text_node(NODE_TEXT, st->start, st->cur - st->start);
+ return new_text_node(st, NODE_TEXT, st->cur - st->start);
}
-static INDEX_NODE *
+static TMPL_NODE *
parse_cond(struct template_state *st, int brn, size_t off, size_t len)
@@ -89,3 +243,3 @@ parse_cond(struct template_state *st, int brn, size_t off, size_t len)
struct condition cond;
- INDEX_NODE *np;
+ TMPL_NODE *np;
@@ -93,16 +247,16 @@ parse_cond(struct template_state *st, int brn, size_t off, size_t len)
off++;
-
- np = xmalloc(sizeof(*np));
- np->type = NODE_COND;
len -= off;
- np->v.cond.expr = xmalloc(len + 1);
- memcpy(np->v.cond.expr, st->start + off, len);
- np->v.cond.expr[len] = 0;
- cond.node = np;
- cond.brn = brn;
- STAILQ_INSERT_HEAD(&st->cond, &cond, next);
- STAILQ_INIT(&np->v.cond.branch[!cond.brn]);
- parse_template(&np->v.cond.branch[cond.brn], st);
-
+ np = node_alloc(st, NODE_COND, len + 1);
+ if (np) {
+ np->v.cond.expr = (char*)(np + 1);
+ memcpy(np->v.cond.expr, st->start + off, len);
+ np->v.cond.expr[len] = 0;
+
+ cond.node = np;
+ cond.brn = brn;
+ STAILQ_INSERT_HEAD(&st->cond, &cond, next);
+ STAILQ_INIT(&np->v.cond.branch[!cond.brn]);
+ parse_template(&np->v.cond.branch[cond.brn], st);
+ }
return np;
@@ -110,3 +264,3 @@ parse_cond(struct template_state *st, int brn, size_t off, size_t len)
-static INDEX_NODE *
+static TMPL_NODE *
next_escape_node(struct template_state *st)
@@ -126,4 +280,3 @@ next_escape_node(struct template_state *st)
st->escape = 0;
- return new_text_node(NODE_TEXT, st->start,
- st->cur - st->start);
+ return new_text_node(st, NODE_TEXT, st->cur - st->start);
}
@@ -140,9 +293,12 @@ next_escape_node(struct template_state *st)
if (memcmp(st->start, "loop", len) == 0) {
- INDEX_NODE *np;
+ TMPL_NODE *np;
- assert(st->loop == 0);
+ if (st->loop) {
+ st->error = TMPL_ERR_LOOP_NESTING;
+ return NULL;
+ }
st->loop = 1;
- np = xmalloc(sizeof(*np));
- np->type = NODE_LOOP;
- parse_template(&np->v.loop, st);
+ np = node_alloc(st, NODE_LOOP, 0);
+ if (np)
+ parse_template(&np->v.loop, st);
return np;
@@ -151,3 +307,6 @@ next_escape_node(struct template_state *st)
if (memcmp(st->start, "endloop", len) == 0) {
- assert(st->loop);
+ if (!st->loop) {
+ st->error = TMPL_ERR_ENDLOOP_WITHOUT_LOOP;
+ return NULL;
+ }
st->loop = 0;
@@ -165,3 +324,6 @@ next_escape_node(struct template_state *st)
if (memcmp(st->start, "endif", len) == 0) {
- STAILQ_REMOVE_HEAD(&st->cond, next);
+ if (STAILQ_FIRST(&st->cond))
+ STAILQ_REMOVE_HEAD(&st->cond, next);
+ else
+ st->error = TMPL_ERR_ENDIF_WITHOUT_IF;
return NULL;
@@ -171,7 +333,13 @@ next_escape_node(struct template_state *st)
if (memcmp(st->start, "else", len) == 0) {
- INDEX_NODE *np;
+ TMPL_NODE *np;
struct condition *cond = STAILQ_FIRST(&st->cond);
- assert(cond);
+ if (!cond) {
+ st->error = TMPL_ERR_ELSE_WITHOUT_IF;
+ return NULL;
+ }
np = cond->node;
- assert(STAILQ_FIRST(&np->v.cond.branch[!cond->brn]) == NULL);
+ if (STAILQ_FIRST(&np->v.cond.branch[!cond->brn])) {
+ st->error = TMPL_ERR_DUP_ELSE;
+ return NULL;
+ }
parse_template(&np->v.cond.branch[!cond->brn], st);
@@ -180,8 +348,10 @@ next_escape_node(struct template_state *st)
- return new_text_node(NODE_EXPR, st->start, len);
+ return new_text_node(st, NODE_EXPR, len);
}
-static INDEX_NODE *
+static TMPL_NODE *
next_node(struct template_state *st)
{
+ if (st->error)
+ return NULL;
if (*st->cur == 0)
@@ -192,5 +362,5 @@ next_node(struct template_state *st)
static void
-parse_template(INDEX_NODE_LIST *nodes, struct template_state *st)
+parse_template(TMPL_NODE_LIST *nodes, struct template_state *st)
{
- INDEX_NODE *np;
+ TMPL_NODE *np;
@@ -202,5 +372,5 @@ parse_template(INDEX_NODE_LIST *nodes, struct template_state *st)
-INDEX_NODE_LIST node_list = STAILQ_HEAD_INITIALIZER(node_list);
+TMPL_NODE_LIST node_list = STAILQ_HEAD_INITIALIZER(node_list);
-void
+int
parse_template_string(char const *str)
@@ -214,2 +384,3 @@ parse_template_string(char const *str)
state.cur = str;
+ state.error = TMPL_NOERR;
@@ -217,8 +388,28 @@ parse_template_string(char const *str)
- assert(state.escape == 0);
- assert(state.loop == 0);
- assert(STAILQ_FIRST(&state.cond) == NULL);
+ if (state.error != TMPL_NOERR) {
+ error("error parsing template near character %d: %s",
+ state.start - str,
+ tmpl_err_str[state.error]);
+ node_list_free(&node_list);
+ return -1;
+ }
+
+ if (state.escape)
+ state.error = TMPL_ERR_ESCAPE_NOT_CLOSED;
+ else if (state.loop)
+ state.error = TMPL_ERR_LOOP_NOT_CLOSED;
+ else if (STAILQ_FIRST(&state.cond))
+ state.error = TMPL_ERR_COND_NOT_CLOSED;
+
+ if (state.error != TMPL_NOERR) {
+ error("error parsing template (at end): %s",
+ tmpl_err_str[state.error]);
+ node_list_free(&node_list);
+ return -1;
+ }
+
+ return 0;
}
-void
+int
parse_template_file(char const *file_name)
@@ -229,2 +420,3 @@ parse_template_file(char const *file_name)
ssize_t n;
+ int rc;
@@ -232,3 +424,3 @@ parse_template_file(char const *file_name)
error("can't stat %s: %s", file_name, strerror(errno));
- return;
+ return -1;
}
@@ -237,6 +429,12 @@ parse_template_file(char const *file_name)
error("can't open %s: %s", file_name, strerror(errno));
- return;
+ return -1;
+ }
+
+ buf = malloc(st.st_size + 1);
+ if (!buf) {
+ error("can't open %s: %s", file_name, strerror(errno));
+ fclose(fp);
+ return -1;
}
- buf = xmalloc(st.st_size + 1);
n = fread(buf, st.st_size, 1, fp);
@@ -244,192 +442,19 @@ parse_template_file(char const *file_name)
buf[st.st_size] = 0;
- parse_template_string(buf);
- } else
+ rc = parse_template_string(buf);
+ } else {
error("error reading from %s: %s", file_name, strerror(errno));
+ rc = 1;
+ }
fclose(fp);
free(buf);
+ return rc;
}
-typedef struct idxent {
- char *name;
- struct stat st;
- char const *type;
- STAILQ_ENTRY(idxent) next;
-} IDXENT;
-typedef struct idxlist {
- size_t count;
- STAILQ_HEAD(, idxent) list;
-} IDXLIST;
-
-static void
-idxlist_init(IDXLIST *lst)
-{
- lst->count = 0;
- STAILQ_INIT(&lst->list);
-}
-
-static void
-idxlist_free(IDXLIST *lst)
-{
- IDXENT *ent;
-
- while ((ent = STAILQ_FIRST(&lst->list))) {
- STAILQ_REMOVE_HEAD(&lst->list, next);
- free(ent->name);
- free(ent);
- }
- lst->count = 0;
-}
-
-static void
-idxlist_append(IDXLIST *lst, IDXENT *ent)
-{
- STAILQ_INSERT_TAIL(&lst->list, ent, next);
- lst->count++;
-}
-
-static int
-idxlist_scan(IDXLIST *idx_list, char const *path, CONFIG const *conf)
-{
- DIR *dir;
- struct dirent *ent;
- IDXENT *idxent;
-
- dir = opendir(path);
- if (!dir) {
- int ec = errno;
- error("can't open directory %s: %s",
- path, strerror(ec));
- return ec;
- }
- idxlist_init(idx_list);
- while ((ent = readdir(dir))) {
- char *name;
- struct stat st;
-
- if (filename_is_hidden(ent->d_name, conf))
- continue;
-
- name = catfile(path, ent->d_name);
-
- if (stat(name, &st)) {
- error("can't stat %s: %s", name, strerror(errno));
- free(name);
- continue;
- }
-
- if (conf->list_unreadable == 0) {
- if (access(name, R_OK)) {
- free(name);
- continue;
- }
- }
-
- idxent = xmalloc(sizeof(*idxent));
-
- if (S_ISDIR(st.st_mode)) {
- size_t len = strlen(ent->d_name);
- idxent->name = xmalloc(len + 2);
- memcpy(idxent->name, ent->d_name, len);
- idxent->name[len++] = '/';
- idxent->name[len] = 0;
- } else
- idxent->name = xstrdup(ent->d_name);
- idxent->st = st;
- idxent->type = get_file_type(name);
- idxlist_append(idx_list, idxent);
- free(name);
- }
- closedir(dir);
-
- return 0;
-}
-
-static void
-idxlist_qsort(IDXLIST *list, int cmp (IDXENT const *, IDXENT const *, void *),
- void *data)
-{
- if (list->count < 2)
- return;
- else if (list->count == 2) {
- IDXENT *a, *b;
- a = STAILQ_FIRST(&list->list);
- b = STAILQ_NEXT(a, next);
- if (cmp(a, b, data) > 0) {
- STAILQ_REMOVE_HEAD(&list->list, next);
- STAILQ_INSERT_TAIL(&list->list, a, next);
- }
- } else {
- IDXENT *cur, *middle;
- IDXLIST high, low;
- int rc;
-
- cur = middle = STAILQ_FIRST(&list->list);
- do {
- cur = STAILQ_NEXT(cur, next);
- if (!cur)
- return;
- } while ((rc = cmp(middle, cur, data)) == 0);
-
- if (rc > 0)
- middle = cur;
-
- idxlist_init(&high);
- idxlist_init(&low);
-
- while ((cur = STAILQ_FIRST(&list->list))) {
- STAILQ_REMOVE_HEAD(&list->list, next);
- if (cmp(middle, cur, data) < 0)
- idxlist_append(&high, cur);
- else
- idxlist_append(&low, cur);
- }
-
- /* Sort both lists */
- idxlist_qsort(&low, cmp, data);
- idxlist_qsort(&high, cmp, data);
-
- /* Join lists in order and return */
- STAILQ_CONCAT(&low.list, &high.list);
- list->list = low.list;
- list->count = low.count + high.count;
- }
-}
-
-static char ordargs[] = "AD";
-static char colargs[] = "NMSD";
-
-INDEX_SORT_COL
-index_sort_col_from_arg(int c)
-{
- char const *p;
- if ((p = strchr(colargs, c)))
- return p - colargs;
- return ISC_NAME;
-}
-
-int
-index_sort_col_to_arg(INDEX_SORT_COL c)
-{
- return colargs[c];
-}
-
-INDEX_SORT_ORD
-index_sort_ord_from_arg(int c)
-{
- char const *p;
- if ((p = strchr(ordargs, c)))
- return p - ordargs;
- return ISO_ASC;
-}
-
-int
-index_sort_ord_to_arg(INDEX_SORT_ORD c)
-{
- return ordargs[c];
-}
+/* Directory tmpl scanner */
-typedef struct {
+/* Run-time template evaluator */
+typedef struct eval_env {
int fd;
CONFIG const *conf;
- IDXENT *ent;
+ DIRLSENT *ent;
int n;
@@ -453,3 +478,3 @@ eval_expand(char const *str, EVAL_ENV *env)
static int
-node_text_eval(INDEX_NODE *node, EVAL_ENV *env)
+node_text_eval(TMPL_NODE *node, EVAL_ENV *env)
{
@@ -459,5 +484,5 @@ node_text_eval(INDEX_NODE *node, EVAL_ENV *env)
if (n == -1)
- error("index write error: %s", strerror(errno));
+ error("tmpl write error: %s", strerror(errno));
else
- error("index write error: %s", "disk full?");
+ error("tmpl write error: %s", "disk full?");
return -1;
@@ -468,3 +493,3 @@ node_text_eval(INDEX_NODE *node, EVAL_ENV *env)
static int
-node_expr_eval(INDEX_NODE *node, EVAL_ENV *env)
+node_expr_eval(TMPL_NODE *node, EVAL_ENV *env)
{
@@ -479,5 +504,5 @@ node_expr_eval(INDEX_NODE *node, EVAL_ENV *env)
if (n == -1)
- error("index write error: %s", strerror(errno));
+ error("tmpl write error: %s", strerror(errno));
else
- error("index write error: %s", "disk full?");
+ error("tmpl write error: %s", "disk full?");
return -1;
@@ -487,6 +512,4 @@ node_expr_eval(INDEX_NODE *node, EVAL_ENV *env)
-static int node_list_eval(INDEX_NODE_LIST *nodes, EVAL_ENV *env);
-
static int
-node_cond_eval(INDEX_NODE *node, EVAL_ENV *env)
+node_cond_eval(TMPL_NODE *node, EVAL_ENV *env)
{
@@ -499,3 +522,3 @@ node_cond_eval(INDEX_NODE *node, EVAL_ENV *env)
static int
-node_loop_eval(INDEX_NODE *node, EVAL_ENV *env)
+node_loop_eval(TMPL_NODE *node, EVAL_ENV *env)
{
@@ -509,24 +532,2 @@ node_loop_eval(INDEX_NODE *node, EVAL_ENV *env)
}
-
-static int (*eval[])(INDEX_NODE *node, EVAL_ENV *env) = {
- [NODE_TEXT] = node_text_eval,
- [NODE_LOOP] = node_loop_eval,
- [NODE_COND] = node_cond_eval,
- [NODE_EXPR] = node_expr_eval
-};
-
-static int
-node_list_eval(INDEX_NODE_LIST *nodes, EVAL_ENV *env)
-{
- INDEX_NODE *node;
-
- STAILQ_FOREACH(node, nodes, next) {
- assert(node->type >= 0
- && node->type < sizeof(eval)/sizeof(eval[0])
- && eval[node->type]);
- if (eval[node->type](node, env))
- return -1;
- }
- return 0;
-}
@@ -538,2 +539,9 @@ streq(const char *v, const char *s, size_t l)
+static inline int
+retstr(char **ret, char const *str)
+{
+ *ret = strdup(str);
+ return *ret ? WRDSE_OK : WRDSE_NOSPACE;
+}
+
static int
@@ -541,4 +549,3 @@ exp_rowclass(char **ret, EVAL_ENV *env)
{
- *ret = xstrdup(env->n % 2 ? "odd" : "even");
- return WRDSE_OK;
+ return retstr(ret, env->n % 2 ? "odd" : "even");
}
@@ -548,6 +555,5 @@ exp_filename(char **ret, EVAL_ENV *env)
{
- if (env->ent) {
- *ret = xstrdup(env->ent->name);
- return WRDSE_OK;
- } else
+ if (env->ent)
+ return retstr(ret, env->ent->name);
+ else
return WRDSE_UNDEF;
@@ -571,4 +577,3 @@ exp_filesize(char **ret, EVAL_ENV *env)
snprintf(buf, sizeof(buf), "%.1f%s", s, suf[i]);
- *ret = strdup(buf);
- return WRDSE_OK;
+ return retstr(ret, buf);
} else
@@ -580,6 +585,5 @@ exp_mimetype(char **ret, EVAL_ENV *env)
{
- if (env->ent && env->ent->type) {
- *ret = xstrdup(env->ent->type);
- return WRDSE_OK;
- } else
+ if (env->ent && env->ent->type)
+ return retstr(ret, env->ent->type);
+ else
return WRDSE_UNDEF;
@@ -595,4 +599,3 @@ exp_filetime(char **ret, EVAL_ENV *env)
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", gmtime(&t));
- *ret = xstrdup(buf);
- return WRDSE_OK;
+ return retstr(ret, buf);
} else
@@ -607,4 +610,4 @@ exp_filetype(char **ret, EVAL_ENV *env)
s = S_ISDIR(env->ent->st.st_mode) ? "DIRECTORY" : "FILE";
- *ret = xstrdup(s);
- return WRDSE_OK;
+ return retstr(ret, s);
+ return *ret ? WRDSE_OK : WRDSE_NOSPACE;
}
@@ -652,4 +655,3 @@ cmd_iconlookup(char **ret, char **argv, EVAL_ENV *env)
env->icon = icon;
- *ret = strdup(icon ? icon->src : "");
- return *ret ? WRDSE_OK : WRDSE_NOSPACE;
+ return retstr(ret, icon ? icon->src : "");
}
@@ -662,5 +664,3 @@ cmd_iconsrc(char **ret, char **argv, EVAL_ENV *env)
s = env->icon->src;
-
- *ret = strdup(s);
- return *ret ? WRDSE_OK : WRDSE_NOSPACE;
+ return retstr(ret, s);
}
@@ -673,5 +673,3 @@ cmd_iconalt(char **ret, char **argv, EVAL_ENV *env)
s = env->icon->alt;
-
- *ret = strdup(s);
- return *ret ? WRDSE_OK : WRDSE_NOSPACE;
+ return retstr(ret, s);
}
@@ -745,49 +743,2 @@ static char defidx[] =
-static inline int
-comp_result(int val, void *data)
-{
- if (*(INDEX_SORT_ORD*)data == ISO_DESC)
- val = -val;
- return val;
-}
-
-static int
-comp_name(IDXENT const *a, IDXENT const *b, void *data)
-{
- return comp_result(strcmp(a->name, b->name), data);
-}
-
-static int
-comp_time(IDXENT const *a, IDXENT const *b, void *data)
-{
- int r;
- if (a->st.st_mtime < b->st.st_mtime)
- r = -1;
- else if (a->st.st_mtime > b->st.st_mtime)
- r = 1;
- else
- r = 0;
- return comp_result(r, data);
-}
-
-static int
-comp_size(IDXENT const *a, IDXENT const *b, void *data)
-{
- int r;
- if (a->st.st_size < b->st.st_size)
- r = -1;
- else if (a->st.st_size > b->st.st_size)
- r = 1;
- else
- r = 0;
- return comp_result(r, data);
-}
-
-static int (*comp[])(IDXENT const *, IDXENT const *, void *) = {
- comp_name,
- comp_time,
- comp_size,
- comp_name
-};
-
int
@@ -795,6 +746,6 @@ directory_index(int fd, CONFIG const *conf,
char const *uri, char const *path,
- INDEX_SORT_COL col, INDEX_SORT_ORD ord)
+ INDEX_SORT_COL col, INDEX_SORT_ORD ord)
{
int rc;
- IDXLIST idxlist;
+ DIRLS dirls;
EVAL_ENV env;
@@ -803,11 +754,12 @@ directory_index(int fd, CONFIG const *conf,
if (STAILQ_EMPTY(&node_list)) {
- parse_template_string(defidx);
- assert(!STAILQ_EMPTY(&node_list));
+ if (parse_template_string(defidx) == 0) {
+ error("error compiling built-in template!");
+ return ENOSYS;
+ }
}
- rc = idxlist_scan(&idxlist, path, conf);
+ rc = dirls_scan(&dirls, path, conf);
if (rc)
return rc;
- /* FIXME: sort list */
- idxlist_qsort(&idxlist, comp[col], &ord);
+ dirls_sort(&dirls, col, ord);
@@ -815,3 +767,3 @@ directory_index(int fd, CONFIG const *conf,
env.conf = conf;
- env.ent = STAILQ_FIRST(&idxlist.list);
+ env.ent = STAILQ_FIRST(&dirls.list);
env.n = 0;
@@ -846,6 +798,7 @@ directory_index(int f