inline links
This commit is contained in:
@@ -33,5 +33,6 @@ void freestring(struct string *str);
|
|||||||
int appendcharstring(struct string *str, char c);
|
int appendcharstring(struct string *str, char c);
|
||||||
int appendstrstring(struct string *str, char *s);
|
int appendstrstring(struct string *str, char *s);
|
||||||
void resetstring(struct string *str);
|
void resetstring(struct string *str);
|
||||||
|
int isctrl(int c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
152
src/inlines.c
152
src/inlines.c
@@ -1,5 +1,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <util.h>
|
||||||
#include <inlines.h>
|
#include <inlines.h>
|
||||||
|
|
||||||
static const char *punctuation = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
|
static const char *punctuation = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
|
||||||
@@ -11,9 +12,11 @@ struct escape escapes[] = {
|
|||||||
{'<', "<"},
|
{'<', "<"},
|
||||||
{'>', ">"},
|
{'>', ">"},
|
||||||
{'&', "&"},
|
{'&', "&"},
|
||||||
|
{'"', """},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int writecodespan(char *data, int i, size_t len, FILE *out);
|
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 writeescaped(char *data, size_t len, FILE *out);
|
||||||
static void writechescape(char c, FILE *out);
|
static void writechescape(char c, FILE *out);
|
||||||
|
|
||||||
@@ -27,6 +30,8 @@ void writedata(char *data, size_t len, FILE *out) {
|
|||||||
int newi;
|
int newi;
|
||||||
if ((newi = writecodespan(data, i, len, out)) >= 0)
|
if ((newi = writecodespan(data, i, len, out)) >= 0)
|
||||||
goto special;
|
goto special;
|
||||||
|
if ((newi = writelink(data, i, len, out)) >= 0)
|
||||||
|
goto special;
|
||||||
if (data[i] == '\\') {
|
if (data[i] == '\\') {
|
||||||
if (strchr(punctuation, data[i + 1]) == NULL)
|
if (strchr(punctuation, data[i + 1]) == NULL)
|
||||||
writechescape('\\', out);
|
writechescape('\\', out);
|
||||||
@@ -69,6 +74,153 @@ static int writecodespan(char *data, int i, size_t len, FILE *out) {
|
|||||||
return end + ticklen;
|
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) {
|
static void writeescaped(char *data, size_t len, FILE *out) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
|
|||||||
@@ -77,3 +77,7 @@ int appendstrstring(struct string *str, char *s) {
|
|||||||
void resetstring(struct string *str) {
|
void resetstring(struct string *str) {
|
||||||
str->len = 0;
|
str->len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int isctrl(int c) {
|
||||||
|
return (0 <= c && c <= 0x1f) || c == 0x7f;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user