arcnyxx.net.git
snail.c
/* snail - markdown compiler
* Copyright (C) 2024 ArcNyxx <me@arcnyxx.net>
* see LICENCE file for licensing information */
#include <stdio.h>
#include <string.h>
static void enc(char *str);
static int link(char *str);
static int info(char *str);
static int code(char *str);
static int nochange(char *str);
static void
enc(char *str)
{
for (int i = 0; str[i] != '\0'; ++i)
switch (str[i]) {
case '&':
fputs("&", stdout);
break;
case '<':
fputs("<", stdout);
break;
case '>':
fputs(">", stdout);
break;
default:
putchar(str[i]);
}
}
static int
link(char *str)
{
if (str[1] != '{') {
putchar('@');
return 0;
}
char *first = strchr(str, '}');
if (first == NULL || first[1] != '{') {
putchar('@');
return 0;
}
char *second = strchr(&first[1], '}');
if (second == NULL) {
putchar('@');
return 0;
}
first[0] = '\0';
second[0] = '\0';
const char *target = "";
if (!strstr(&str[2], "arcnyxx.net"))
target = " target='_blank'";
fputs("<a href='", stdout);
enc(&str[2]);
printf("'%s>", target);
enc(&first[2]);
fputs("</a>", stdout);
return second - str;
}
static int
info(char *str)
{
if (str[1] != '{') {
putchar('%');
return 0;
}
char *first = strchr(str, '}');
if (first == NULL || first[1] != '{') {
putchar('%');
return 0;
}
char *second = strchr(&first[1], '}');
if (second == NULL) {
putchar('%');
return 0;
}
first[0] = '\0';
second[0] = '\0';
fputs("<span class='n' title='", stdout);
enc(&str[2]);
fputs("'>", stdout);
enc(&first[2]);
fputs("</span>", stdout);
return second - str;
}
static int
code(char *str)
{
char *end;
if ((end = strchr(&str[1], '`')) == NULL) {
putchar('`');
return 0;
}
end[0] = '\0';
size_t ret = end - str;
char class[11] = "";
if (str[1] == '\\') {
if (str[2] == '\\') {
++str;
} else {
str += 2;
snprintf(class, sizeof(class), " class='%c'", str[0]);
}
}
fprintf(stdout, "<code%s>", class);
enc(str + 1);
fputs("</code>", stdout);
return ret;
}
static int
nochange(char *str)
{
char *end;
if ((end = strchr(&str[1], '|')) == NULL || &str[1] == end) {
putchar('|');
return &str[1] == end;
}
end[0] = '\0';
fputs(&str[1], stdout);
return end - str;
}
int
main(int argc, char **argv)
{
if (argc != 2)
return 1;
for (int i = 0; argv[1][i] != '\0'; ++i) {
switch (argv[1][i]) {
case '@':
i += link(&argv[1][i]);
break;
case '%':
i += info(&argv[1][i]);
break;
case '`':
i += code(&argv[1][i]);
break;
case '|':
i += nochange(&argv[1][i]);
break;
case '&':
fputs("&", stdout);
break;
case '<':
fputs("<", stdout);
break;
case '>':
fputs(">", stdout);
break;
default:
putchar(argv[1][i]);
}
}
}