diff options
Diffstat (limited to 'bin/htagml.c')
-rw-r--r-- | bin/htagml.c | 94 |
1 files changed, 55 insertions, 39 deletions
diff --git a/bin/htagml.c b/bin/htagml.c index eb5128d1..1f547be6 100644 --- a/bin/htagml.c +++ b/bin/htagml.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -16,7 +16,6 @@ #include <ctype.h> #include <err.h> -#include <regex.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -24,13 +23,18 @@ #include <sysexits.h> #include <unistd.h> -static char *nomagic(const char *pattern) { - char *buf = malloc(2 * strlen(pattern) + 1); +static char *deregex(const char *patt) { + char *buf = malloc(strlen(patt) + 1); if (!buf) err(EX_OSERR, "malloc"); char *ptr = buf; - for (const char *ch = pattern; *ch; ++ch) { - if (strchr(".[*", *ch)) *ptr++ = '\\'; - *ptr++ = *ch; + if (*patt == '^') patt++; + for (; *patt; ++patt) { + if (patt[0] == '$' && !patt[1]) { + *ptr++ = '\n'; + break; + } + if (patt[0] == '\\' && patt[1]) patt++; + *ptr++ = *patt; } *ptr = '\0'; return buf; @@ -73,15 +77,21 @@ static char *hstrstr(const char *haystack, const char *needle) { return NULL; } +static int isident(int c) { + return isalnum(c) || c == '_'; +} + int main(int argc, char *argv[]) { bool pre = false; bool pipe = false; + bool main = false; bool index = false; - const char *tagsFile = "tags"; - for (int opt; 0 < (opt = getopt(argc, argv, "f:ipx"));) { + const char *tagsPath = "tags"; + for (int opt; 0 < (opt = getopt(argc, argv, "f:impx"));) { switch (opt) { - break; case 'f': tagsFile = optarg; + break; case 'f': tagsPath = optarg; break; case 'i': pipe = true; + break; case 'm': main = true; break; case 'p': pre = true; break; case 'x': index = true; break; default: return EX_USAGE; @@ -90,21 +100,30 @@ int main(int argc, char *argv[]) { if (optind == argc) errx(EX_USAGE, "name required"); const char *name = argv[optind]; - FILE *file = fopen(tagsFile, "r"); - if (!file) err(EX_NOINPUT, "%s", tagsFile); + FILE *file = fopen(name, "r"); + if (!file) err(EX_NOINPUT, "%s", name); + + FILE *tagsFile = fopen(tagsPath, "r"); + if (!tagsFile) err(EX_NOINPUT, "%s", tagsPath); + +#ifdef __OpenBSD__ + int error = pledge("stdio", NULL); + if (error) err(EX_OSERR, "pledge"); +#endif size_t len = 0; size_t cap = 256; struct Tag { char *tag; int num; - regex_t regex; + char *str; + size_t len; } *tags = malloc(cap * sizeof(*tags)); if (!tags) err(EX_OSERR, "malloc"); char *buf = NULL; size_t bufCap = 0; - while (0 < getline(&buf, &bufCap, file)) { + while (0 < getline(&buf, &bufCap, tagsFile)) { char *line = buf; char *tag = strsep(&line, "\t"); char *file = strsep(&line, "\t"); @@ -123,15 +142,11 @@ int main(int argc, char *argv[]) { if (def[0] == '/' || def[0] == '?') { def++; def[strlen(def)-1] = '\0'; - char *search = nomagic(def); - int error = regcomp( - &tags[len].regex, search, REG_NEWLINE | REG_NOSUB - ); - free(search); - if (error) { - warnx("invalid regex for tag %s: %s", tag, def); - continue; + if (def[0] != '^') { + warnx("unanchored regex for tag %s: %s", tag, def); } + tags[len].str = deregex(def); + tags[len].len = strlen(tags[len].str); } else { tags[len].num = strtol(def, &def, 10); if (*def) { @@ -141,31 +156,28 @@ int main(int argc, char *argv[]) { } len++; } - fclose(file); - - file = fopen(name, "r"); - if (!file) err(EX_NOINPUT, "%s", name); + fclose(tagsFile); int num = 0; printf(pre ? "<pre>" : index ? "<ul class=\"index\">\n" : ""); while (0 < getline(&buf, &bufCap, file) && ++num) { - struct Tag *tag = NULL; + char *tag = NULL; for (size_t i = 0; i < len; ++i) { if (tags[i].num) { if (num != tags[i].num) continue; } else { - if (regexec(&tags[i].regex, buf, 0, NULL, 0)) continue; + if (strncmp(tags[i].str, buf, tags[i].len)) continue; } - tag = &tags[i]; - tag->num = num; + tag = tags[i].tag; + tags[i] = tags[--len]; break; } if (index) { if (!tag) continue; printf("<li><a class=\"tag\" href=\"#"); - id(tag->tag); + id(tag); printf("\">"); - escape(true, tag->tag, strlen(tag->tag)); + escape(true, tag, strlen(tag)); printf("</a></li>\n"); continue; } @@ -180,14 +192,18 @@ int main(int argc, char *argv[]) { continue; } - size_t mlen = strlen(tag->tag); - char *match = (pipe ? hstrstr : strstr)(buf, tag->tag); - while (match > buf && isalnum(match[-1])) { - match = (pipe ? hstrstr : strstr)(&match[mlen], tag->tag); + size_t mlen = strlen(tag); + char *match = (pipe ? hstrstr : strstr)(buf, tag); + while ( + match && + ((match > buf && isident(match[-1])) || isident(match[mlen])) + ) { + match = (pipe ? hstrstr : strstr)(&match[mlen], tag); } - if (!match && tag->tag[0] == 'M') { + if (!match && tag[0] == 'M') { mlen = 4; match = (pipe ? hstrstr : strstr)(buf, "main"); + if (main) tag = "main"; } if (!match) { mlen = strlen(buf) - 1; @@ -195,9 +211,9 @@ int main(int argc, char *argv[]) { } escape(!pipe, buf, match - buf); printf("<a class=\"tag\" id=\""); - id(tag->tag); + id(tag); printf("\" href=\"#"); - id(tag->tag); + id(tag); printf("\">"); match += escape(!pipe, match, mlen); printf("</a>"); |