summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--html.c10
-rw-r--r--xs_mime.h90
-rw-r--r--xs_regex.h10
-rw-r--r--xs_unicode.h51
-rw-r--r--xs_version.h2
5 files changed, 112 insertions, 51 deletions
diff --git a/html.c b/html.c
index 8e45eba..e132f17 100644
--- a/html.c
+++ b/html.c
@@ -1313,6 +1313,16 @@ xs_str *html_entry(snac *user, xs_str *os, const xs_dict *msg, int local,
1313 if (xs_is_null(url)) 1313 if (xs_is_null(url))
1314 continue; 1314 continue;
1315 1315
1316 /* if it's a plain Link, check if it can be "rewritten" */
1317 if (strcmp(t, "Link") == 0) {
1318 const char *mt = xs_mime_by_ext(url);
1319
1320 if (xs_startswith(mt, "image/") ||
1321 xs_startswith(mt, "audio/") ||
1322 xs_startswith(mt, "video/"))
1323 t = mt;
1324 }
1325
1316 const char *name = xs_dict_get(v, "name"); 1326 const char *name = xs_dict_get(v, "name");
1317 if (xs_is_null(name)) 1327 if (xs_is_null(name))
1318 name = xs_dict_get(msg, "name"); 1328 name = xs_dict_get(msg, "name");
diff --git a/xs_mime.h b/xs_mime.h
index ef7affe..2c8eaa9 100644
--- a/xs_mime.h
+++ b/xs_mime.h
@@ -6,57 +6,67 @@
6 6
7const char *xs_mime_by_ext(const char *file); 7const char *xs_mime_by_ext(const char *file);
8 8
9extern const char *xs_mime_types[];
10
9#ifdef XS_IMPLEMENTATION 11#ifdef XS_IMPLEMENTATION
10 12
11/* intentionally brain-dead simple */ 13/* intentionally brain-dead simple */
12struct _mime_info { 14/* CAUTION: sorted */
13 const char *type; 15
14 const char *ext; 16const char *xs_mime_types[] = {
15} mime_info[] = { 17 "3gp", "video/3gpp",
16 { "application/json", ".json" }, 18 "aac", "audio/aac",
17 { "image/gif", ".gif" }, 19 "css", "text/css",
18 { "image/jpeg", ".jpeg" }, 20 "flac", "audio/flac",
19 { "image/jpeg", ".jpg" }, 21 "flv", "video/flv",
20 { "image/png", ".png" }, 22 "gif", "image/gif",
21 { "image/webp", ".webp" }, 23 "gmi", "text/gemini",
22 { "video/mp4", ".mp4" }, 24 "html", "text/html",
23 { "video/mp4", ".mpg4" }, 25 "jpeg", "image/jpeg",
24 { "video/mp4", ".m4v" }, 26 "jpg", "image/jpeg",
25 { "video/webm", ".webm" }, 27 "json", "application/json",
26 { "video/quicktime", ".mov" }, 28 "m4a", "audio/aac",
27 { "video/3gpp", ".3gp" }, 29 "m4v", "video/mp4",
28 { "video/ogg", ".ogv" }, 30 "md", "text/markdown",
29 { "video/flv", ".flv" }, 31 "mov", "video/quicktime",
30 { "audio/mp3", ".mp3" }, 32 "mp3", "audio/mp3",
31 { "audio/ogg", ".ogg" }, 33 "mp4", "video/mp4",
32 { "audio/ogg", ".oga" }, 34 "mpg4", "video/mp4",
33 { "audio/ogg", ".opus" }, 35 "oga", "audio/ogg",
34 { "audio/flac", ".flac" }, 36 "ogg", "audio/ogg",
35 { "audio/wav", ".wav" }, 37 "ogv", "video/ogg",
36 { "audio/wma", ".wma" }, 38 "opus", "audio/ogg",
37 { "audio/aac", ".aac" }, 39 "png", "image/png",
38 { "audio/aac", ".m4a" }, 40 "txt", "text/plain",
39 { "text/css", ".css" }, 41 "wav", "audio/wav",
40 { "text/html", ".html" }, 42 "webm", "video/webm",
41 { "text/plain", ".txt" }, 43 "webp", "image/webp",
42 { "text/xml", ".xml" }, 44 "wma", "audio/wma",
43 { "text/markdown", ".md" }, 45 "xml", "text/xml",
44 { "text/gemini", ".gmi" }, 46 NULL, NULL,
45 { NULL, NULL }
46}; 47};
47 48
48 49
49const char *xs_mime_by_ext(const char *file) 50const char *xs_mime_by_ext(const char *file)
50/* returns the MIME type by file extension */ 51/* returns the MIME type by file extension */
51{ 52{
52 struct _mime_info *mi = mime_info; 53 const char *ext = strrchr(file, '.');
53 xs *lfile = xs_tolower_i(xs_dup(file)); 54
55 if (ext) {
56 const char **p = xs_mime_types;
57 xs *uext = xs_tolower_i(xs_dup(ext + 1));
58
59 while (**p) {
60 int c;
54 61
55 while (mi->type != NULL) { 62 if ((c = strcmp(*p, uext)) == 0)
56 if (xs_endswith(lfile, mi->ext)) 63 return p[1];
57 return mi->type; 64 else
65 if (c > 0)
66 break;
58 67
59 mi++; 68 p += 2;
69 }
60 } 70 }
61 71
62 return "application/octet-stream"; 72 return "application/octet-stream";
diff --git a/xs_regex.h b/xs_regex.h
index 6fb6cca..7e1c80f 100644
--- a/xs_regex.h
+++ b/xs_regex.h
@@ -8,8 +8,10 @@ xs_list *xs_regex_split_n(const char *str, const char *rx, int count);
8#define xs_regex_split(str, rx) xs_regex_split_n(str, rx, XS_ALL) 8#define xs_regex_split(str, rx) xs_regex_split_n(str, rx, XS_ALL)
9xs_list *xs_regex_match_n(const char *str, const char *rx, int count); 9xs_list *xs_regex_match_n(const char *str, const char *rx, int count);
10#define xs_regex_match(str, rx) xs_regex_match_n(str, rx, XS_ALL) 10#define xs_regex_match(str, rx) xs_regex_match_n(str, rx, XS_ALL)
11xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count); 11xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count);
12#define xs_regex_replace(str, rx, rep) xs_regex_replace_n(str, rx, rep, XS_ALL) 12#define xs_regex_replace_i(str, rx, rep) xs_regex_replace_in(str, rx, rep, XS_ALL)
13#define xs_regex_replace_n(str, rx, rep, count) xs_regex_replace_in(xs_dup(str), rx, rep, count)
14#define xs_regex_replace(str, rx, rep) xs_regex_replace_in(xs_dup(str), rx, rep, XS_ALL)
13 15
14#ifdef XS_IMPLEMENTATION 16#ifdef XS_IMPLEMENTATION
15 17
@@ -78,7 +80,7 @@ xs_list *xs_regex_match_n(const char *str, const char *rx, int count)
78} 80}
79 81
80 82
81xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count) 83xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count)
82/* replaces all matches with the rep string. If it contains unescaped &, 84/* replaces all matches with the rep string. If it contains unescaped &,
83 they are replaced with the match */ 85 they are replaced with the match */
84{ 86{
@@ -121,6 +123,8 @@ xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, in
121 n++; 123 n++;
122 } 124 }
123 125
126 xs_free(str);
127
124 return s; 128 return s;
125} 129}
126 130
diff --git a/xs_unicode.h b/xs_unicode.h
index 48cd660..35cd9f7 100644
--- a/xs_unicode.h
+++ b/xs_unicode.h
@@ -4,8 +4,10 @@
4 4
5#define _XS_UNICODE_H 5#define _XS_UNICODE_H
6 6
7 int _xs_utf8_enc(char buf[4], unsigned int cpoint);
7 xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint); 8 xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint);
8 unsigned int xs_utf8_dec(char **str); 9 unsigned int xs_utf8_dec(char **str);
10 int xs_unicode_width(unsigned int cpoint);
9 unsigned int *_xs_unicode_upper_search(unsigned int cpoint); 11 unsigned int *_xs_unicode_upper_search(unsigned int cpoint);
10 unsigned int *_xs_unicode_lower_search(unsigned int cpoint); 12 unsigned int *_xs_unicode_lower_search(unsigned int cpoint);
11 #define xs_unicode_is_upper(cpoint) (!!_xs_unicode_upper_search(cpoint)) 13 #define xs_unicode_is_upper(cpoint) (!!_xs_unicode_upper_search(cpoint))
@@ -18,8 +20,8 @@
18#ifdef XS_IMPLEMENTATION 20#ifdef XS_IMPLEMENTATION
19 21
20 22
21char *_xs_utf8_enc(char buf[4], unsigned int cpoint) 23int _xs_utf8_enc(char buf[4], unsigned int cpoint)
22/* encodes an Unicode codepoint to utf-8 into buf and returns the new position */ 24/* encodes an Unicode codepoint to utf-8 into buf and returns the size in bytes */
23{ 25{
24 unsigned char *p = (unsigned char *)buf; 26 unsigned char *p = (unsigned char *)buf;
25 27
@@ -42,18 +44,18 @@ char *_xs_utf8_enc(char buf[4], unsigned int cpoint)
42 *p++ = 0x80 | (cpoint & 0x3f); 44 *p++ = 0x80 | (cpoint & 0x3f);
43 } 45 }
44 46
45 return (char *)p; 47 return p - (unsigned char *)buf;
46} 48}
47 49
48 50
49xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint) 51xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint)
50/* encodes an Unicode codepoint to utf-8 into str */ 52/* encodes an Unicode codepoint to utf-8 into str */
51{ 53{
52 char tmp[4], *p; 54 char tmp[4];
53 55
54 p = _xs_utf8_enc(tmp, cpoint); 56 int c = _xs_utf8_enc(tmp, cpoint);
55 57
56 return xs_append_m(str, tmp, p - tmp); 58 return xs_append_m(str, tmp, c);
57} 59}
58 60
59 61
@@ -99,9 +101,44 @@ unsigned int xs_utf8_dec(char **str)
99} 101}
100 102
101 103
104/* intentionally dead simple */
105
106static unsigned int xs_unicode_width_table[] = {
107 0x300, 0x36f, 0, /* diacritics */
108 0x1100, 0x11ff, 2, /* Hangul */
109 0x2e80, 0xa4cf, 2, /* CJK */
110 0xac00, 0xd7a3, 2, /* more Hangul */
111 0xe000, 0xf8ff, 0, /* private use */
112 0xf900, 0xfaff, 2, /* CJK compatibility */
113 0xff00, 0xff60, 2, /* full width things */
114 0xffdf, 0xffe6, 2, /* full width things */
115 0x1f200, 0x1ffff, 2, /* emojis */
116 0x20000, 0x2fffd, 2 /* more CJK */
117};
118
119int xs_unicode_width(unsigned int cpoint)
120/* returns the width in columns of a Unicode codepoint (somewhat simplified) */
121{
122 unsigned int *p = xs_unicode_width_table;
123 unsigned int *e = p + sizeof(xs_unicode_width_table) / sizeof(unsigned int);
124
125 while (p < e) {
126 if (cpoint < p[0])
127 return 1;
128
129 if (cpoint >= p[0] && cpoint <= p[1])
130 return p[2];
131
132 p += 3;
133 }
134
135 return 0;
136}
137
138
102#ifdef _XS_UNICODE_TBL_H 139#ifdef _XS_UNICODE_TBL_H
103 140
104/* include xs_unicode_tbl.h before to use these functions */ 141/* include xs_unicode_tbl.h before this one to use these functions */
105 142
106static int int_cmp(const void *p1, const void *p2) 143static int int_cmp(const void *p1, const void *p2)
107{ 144{
diff --git a/xs_version.h b/xs_version.h
index ae43ff4..8b2dea3 100644
--- a/xs_version.h
+++ b/xs_version.h
@@ -1 +1 @@
/* b7e9713d90382d8da0b58023f4c78416e6ca1bc5 */ /* e85f257dd8fcb2980fd21aa37c1594c1461ddf48 */