inline links

This commit is contained in:
Nate Choe
2022-05-01 03:40:46 -05:00
parent 3a5abb2538
commit 0b134cabb2
3 changed files with 157 additions and 0 deletions

View File

@@ -33,5 +33,6 @@ void freestring(struct string *str);
int appendcharstring(struct string *str, char c);
int appendstrstring(struct string *str, char *s);
void resetstring(struct string *str);
int isctrl(int c);
#endif

View File

@@ -1,5 +1,6 @@
#include <string.h>
#include <util.h>
#include <inlines.h>
static const char *punctuation = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
@@ -11,9 +12,11 @@ struct escape escapes[] = {
{'<', "&lt;"},
{'>', "&gt;"},
{'&', "&amp;"},
{'"', "&quot;"},
};
static int writecodespan(char *data, int i, size_t len, FILE *out);
static int writelink(char *data, int i, size_t len, FILE *out);
static void writeescaped(char *data, size_t len, FILE *out);
static void writechescape(char c, FILE *out);
@@ -27,6 +30,8 @@ void writedata(char *data, size_t len, FILE *out) {
int newi;
if ((newi = writecodespan(data, i, len, out)) >= 0)
goto special;
if ((newi = writelink(data, i, len, out)) >= 0)
goto special;
if (data[i] == '\\') {
if (strchr(punctuation, data[i + 1]) == NULL)
writechescape('\\', out);
@@ -69,6 +74,153 @@ static int writecodespan(char *data, int i, size_t len, FILE *out) {
return end + ticklen;
}
static int writelink(char *data, int i, size_t len, FILE *out) {
int textstart, textend, titlestart, titleend, linkstart, linkend;
int count;
enum {
INITIAL,
GETTEXT,
GETDESTSTART,
GETDESTDETERMINE,
GETDESTPOINTY,
GETDESTNORMAL,
GETTITLEDETERMINE,
GETTITLEDOUBLEQUOTE,
GETTITLESINGLEQUOTE,
GETTITLEPAREN,
NEARLYTHERE,
DONE
} state;
state = INITIAL;
for (; i < len; ++i) {
switch (state) {
case INITIAL:
if (data[i] != '[')
return -1;
state = GETTEXT;
count = 1;
textstart = i + 1;
break;
case GETTEXT:
if (data[i] == '[')
++count;
if (data[i] == ']')
--count;
if (count == 0) {
textend = i;
linkstart = i;
state = GETDESTSTART;
}
break;
case GETDESTSTART:
if (data[i] != '(')
return -1;
state = GETDESTDETERMINE;
break;
case GETDESTDETERMINE:
if (data[i] == '<') {
state = GETDESTPOINTY;
linkstart = i + 1;
}
else {
state = GETDESTNORMAL;
linkstart = i--;
count = 0;
}
break;
case GETDESTPOINTY:
if (data[i] == '<' && data[i - 1] != '\\')
return -1;
if (data[i] == '>' && data[i - 1] != '\\') {
linkend = i;
state = GETTITLEDETERMINE;
}
break;
case GETDESTNORMAL:
if (data[i] == '(')
++count;
if (data[i] == ')')
--count;
if (count < 0) {
state = GETTITLEDETERMINE;
linkend = i--;
break;
}
if (count != 0)
break;
if (isctrl(data[i]) || data[i] == ' ') {
state = GETTITLEDETERMINE;
linkend = i;
}
break;
case GETTITLEDETERMINE:
switch (data[i]) {
case '"':
state = GETTITLEDOUBLEQUOTE;
titlestart = i + 1;
break;
case '\'':
state = GETTITLESINGLEQUOTE;
titlestart = i + 1;
break;
case '(':
state = GETTITLEPAREN;
count = 1;
titlestart = i + 1;
break;
default:
--i;
titlestart = titleend = -1;
state = NEARLYTHERE;
}
break;
case GETTITLEDOUBLEQUOTE:
if (data[i] == '"' && data[i - 1] != '\\') {
titleend = i;
state = NEARLYTHERE;
}
break;
case GETTITLESINGLEQUOTE:
if (data[i] == '\'' && data[i - 1] != '\\') {
titleend = i;
state = NEARLYTHERE;
}
break;
case GETTITLEPAREN:
if (data[i] == '(' || data[i] == ')') {
if (data[i - 1] != '\\') {
titleend = i;
state = NEARLYTHERE;
}
}
break;
case NEARLYTHERE:
if (data[i] != ')')
return -1;
state = DONE;
break;
case DONE:
goto done;
}
}
done:
if (state != DONE)
return -1;
fputs("<a", out);
fputs(" href='", out);
writeescaped(data + linkstart, linkend - linkstart, out);
fputc('\'', out);
if (titlestart >= 0) {
fputs(" title='", out);
writeescaped(data + titlestart, titleend - titlestart, out);
fputc('\'', out);
}
fputc('>', out);
writeescaped(data + textstart, textend - textstart, out);
fputs("</a>", out);
return i;
}
static void writeescaped(char *data, size_t len, FILE *out) {
int i;
for (i = 0; i < len; ++i)

View File

@@ -77,3 +77,7 @@ int appendstrstring(struct string *str, char *s) {
void resetstring(struct string *str) {
str->len = 0;
}
int isctrl(int c) {
return (0 <= c && c <= 0x1f) || c == 0x7f;
}