Mercurial > blahgd > experimental
changeset 773:07a2baf4ff17
lisplint: a tool to check post and comment metadata
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sat, 24 Oct 2015 15:50:30 -0400 |
parents | 7a8b77cb99f5 |
children | e08f7f99e789 |
files | .gitignore CMakeLists.txt lisplint.c |
diffstat | 3 files changed, 266 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/.gitignore Sat Oct 24 15:49:19 2015 -0400 +++ b/.gitignore Sat Oct 24 15:50:30 2015 -0400 @@ -1,6 +1,7 @@ blahg blahgd mathd +lisplint nvdump test_fmt3 test_qstring
--- a/CMakeLists.txt Sat Oct 24 15:49:19 2015 -0400 +++ b/CMakeLists.txt Sat Oct 24 15:50:30 2015 -0400 @@ -158,6 +158,26 @@ /usr/lib/libavl.so.1 ) +add_executable(lisplint + lisplint.c + val.c + str.c + error.c + mangle.c + utils.c + + nvl.c + nvl_convert.c + ${FLEX_lisp_OUTPUTS} ${BISON_lisp_OUTPUTS} + lisp.c +) + +target_link_libraries(lisplint + umem + nvpair + /usr/lib/libavl.so.1 +) + add_executable(nvdump nvdump.c utils.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisplint.c Sat Oct 24 15:50:30 2015 -0400 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> + +#include "error.h" +#include "utils.h" +#include "lisp.h" +#include "str.h" +#include "val.h" + +static char *prog; + +static bool (*checker)(const char *fname, struct val *); +static bool verbose = false; + +#define error(fname, ...) \ + do { \ + fprintf(stderr, "%s: ", (fname)); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) + +static bool check_type(const char *fname, struct val *lv, + const char *varname, enum val_type type, + bool mandatory) +{ + struct val *v; + + v = lisp_alist_lookup_val(lv, varname); + if (!v) { + if (mandatory) + error(fname, "missing '%s'\n", varname); + return !mandatory; + } + + if (v->type != type) { + error(fname, "'%s' has wrong type: got %u, expected %u\n", + varname, v->type, type); + val_putref(v); + return false; + } + + val_putref(v); + return true; +} + +static bool check_post(const char *fname, struct val *lv) +{ + struct val *fmtval; + uint64_t fmt; + bool ret; + + /* + * check fmt presence & correctness + */ + fmtval = lisp_alist_lookup_val(lv, "fmt"); + if (!fmtval) { + error(fname, "missing 'fmt'"); + return false; + } + + if (fmtval->type != VT_INT) { + error(fname, "fmt is not an int"); + val_putref(fmtval); + return false; + } + + fmt = fmtval->i; + + val_putref(fmtval); + + /* + * Depending on the fmt, check other parts of the metadata + */ + switch (fmt) { + case 1: + case 2: + case 3: + ret = check_type(fname, lv, "time", VT_STR, true); + ret = check_type(fname, lv, "title", VT_STR, true) && ret; + ret = check_type(fname, lv, "tags", VT_CONS, false) && ret; + ret = check_type(fname, lv, "cats", VT_CONS, false) && ret; + ret = check_type(fname, lv, "comments", VT_CONS, false) && ret; + ret = check_type(fname, lv, "listed", VT_BOOL, false) && ret; + return ret; + case 4: + return true; + default: + error(fname, "invalid format version"); + return false; + } +} + +static bool check_comment(const char *fname, struct val *lv) +{ + bool ret; + + ret = check_type(fname, lv, "author", VT_STR, true); + ret = check_type(fname, lv, "email", VT_STR, true) && ret; + ret = check_type(fname, lv, "time", VT_STR, true) && ret; + ret = check_type(fname, lv, "ip", VT_STR, false) && ret; + ret = check_type(fname, lv, "url", VT_STR, false) && ret; + ret = check_type(fname, lv, "moderated", VT_BOOL, true) && ret; + + return ret; +} + +static bool check_config(const char *fname, struct val *lv) +{ + bool ret; + + ret = check_type(fname, lv, CONFIG_SCGI_PORT, VT_INT, false); + ret = check_type(fname, lv, CONFIG_SCGI_THREADS, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_HTML_INDEX_STORIES, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_FEED_INDEX_STORIES, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_COMMENT_MAX_THINK, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_COMMENT_MIN_THINK, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_COMMENT_CAPTCHA_A, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_COMMENT_CAPTCHA_B, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_DATA_DIR, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_WEB_DIR, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_BASE_URL, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_BUG_BASE_URL, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_WIKI_BASE_URL, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_PHOTO_BASE_URL, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_TAGCLOUD_MIN_SIZE, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_TAGCLOUD_MAX_SIZE, VT_INT, false) && ret; + ret = check_type(fname, lv, CONFIG_LATEX_BIN, VT_STR, false) && ret; + ret = check_type(fname, lv, CONFIG_DVIPNG_BIN, VT_STR, false) && ret; + + return ret; +} + +static bool onefile(const char *fname, char *ibuf, size_t len) +{ + struct val *lv; + bool ret; + + lv = parse_lisp(ibuf, len); + + if (verbose) { + lisp_dump_file(stderr, lv, false); + fprintf(stderr, "\n"); + } + + ret = checker(fname, lv); + + val_putref(lv); + + return ret; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: %s {-p | -c | -C} [-v] <filename> ...\n", prog); + exit(2); +} + +int main(int argc, char **argv) +{ + char *in; + int i; + int result; + char opt; + + prog = argv[0]; + + result = 0; + + ASSERT0(putenv("UMEM_DEBUG=default,verbose")); + ASSERT0(putenv("BLAHG_DISABLE_SYSLOG=1")); + + init_str_subsys(); + init_val_subsys(); + + while ((opt = getopt(argc, argv, "pcCv")) != -1) { + switch (opt) { + case 'p': + /* post */ + checker = check_post; + break; + case 'c': + /* comment */ + checker = check_comment; + break; + case 'C': + /* config */ + checker = check_config; + break; + case 'v': + verbose = true; + break; + default: + usage(); + break; + } + } + + if (optind == argc) + usage(); + + if (checker == NULL) + usage(); + + for (i = optind; i < argc; i++) { + in = read_file(argv[i]); + if (IS_ERR(in)) { + fprintf(stderr, "%s: cannot read: %s\n", + argv[i], strerror(PTR_ERR(in))); + result++; + continue; + } + + if (!onefile(argv[i], in, strlen(in))) + result++; + + free(in); + } + + if (!result) + printf("OK.\n"); + else + fprintf(stderr, "%d failed files\n", result); + + return !!result; +}