helper.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Copyright (c) 2018 Markus Hennecke <markus-hennecke@markus-hennecke.de>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <sys/mman.h>
  17. #include <sys/queue.h>
  18. #include <sys/stat.h>
  19. #include <ctype.h>
  20. #include <err.h>
  21. #include <fcntl.h>
  22. #include <stdbool.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #include <lowdown.h>
  28. #include "helper.h"
  29. static struct memmap *_map_fd(int);
  30. static char decode_hexdigit(const char *);
  31. static bool ishexdigit(const int);
  32. static const char *_get_file_extension(const char *);
  33. const char *
  34. rx_get_errormsg(int _rc, regex_t *_rx)
  35. {
  36. static char errmsg[512];
  37. regerror(_rc, _rx, errmsg, sizeof(errmsg));
  38. return errmsg;
  39. }
  40. const char *
  41. _get_file_extension(const char *_filename)
  42. {
  43. const char *dot = strchr(_filename, '.');
  44. if (dot == NULL || dot == _filename)
  45. return "";
  46. return dot + 1;
  47. }
  48. struct memmap *
  49. _map_fd(int _fd)
  50. {
  51. struct stat sb;
  52. if (-1 == fstat(_fd, &sb))
  53. err(1, NULL);
  54. struct memmap *mm = malloc(sizeof(struct memmap));
  55. if (NULL == mm)
  56. err(1, NULL);
  57. mm->size = sb.st_size;
  58. mm->data = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, _fd, 0);
  59. close(_fd);
  60. return mm;
  61. }
  62. struct memmap *
  63. memmap_new(const char *_filename)
  64. {
  65. int fd = open(_filename, O_RDONLY);
  66. if (-1 == fd) {
  67. warn(NULL);
  68. return NULL;
  69. }
  70. return _map_fd(fd);
  71. }
  72. struct memmap *
  73. memmap_new_at(int _fd, const char *_filename)
  74. {
  75. int fd = openat(_fd, _filename, O_RDONLY);
  76. if (-1 == fd) {
  77. warn(NULL);
  78. return NULL;
  79. }
  80. return _map_fd(fd);
  81. }
  82. void
  83. memmap_free(struct memmap *_map)
  84. {
  85. if (_map && _map->data)
  86. munmap(_map->data, _map->size);
  87. free(_map);
  88. }
  89. size_t
  90. memmap_chomp(struct memmap *_m)
  91. {
  92. size_t s = _m->size;
  93. if (_m && _m->data) {
  94. while ((s > 0) && isspace(((char *)_m->data)[s-1]))
  95. s--;
  96. }
  97. return s;
  98. }
  99. struct md_mmap *
  100. md_mmap_new(const char *_filename)
  101. {
  102. struct memmap *mmap = memmap_new(_filename);
  103. if (mmap == NULL)
  104. return NULL;
  105. struct md_mmap *mdbuf = calloc(1, sizeof(struct md_mmap));
  106. if (mdbuf == NULL)
  107. err(1, NULL);
  108. mdbuf->mmap = mmap;
  109. mdbuf->md = (strcmp("md", _get_file_extension(_filename)) == 0);
  110. return mdbuf;
  111. }
  112. struct md_mmap *
  113. md_mmap_new_at(int _fd, const char *_filename)
  114. {
  115. int fd = openat(_fd, _filename, O_RDONLY);
  116. if (-1 == fd) {
  117. warn(NULL);
  118. return NULL;
  119. }
  120. struct memmap *mmap = _map_fd(fd);
  121. if (mmap == NULL)
  122. return NULL;
  123. struct md_mmap *mdbuf = calloc(1, sizeof(struct md_mmap));
  124. if (mdbuf == NULL)
  125. err(1, NULL);
  126. mdbuf->mmap = mmap;
  127. mdbuf->md = (strcmp("md", _get_file_extension(_filename)) == 0);
  128. return mdbuf;
  129. }
  130. struct md_mmap *
  131. md_mmap_new_from_memmap(struct memmap *_mmap)
  132. {
  133. struct md_mmap *mdbuf = calloc(1, sizeof(struct md_mmap));
  134. if (mdbuf == NULL)
  135. err(1, NULL);
  136. mdbuf->mmap = _mmap;
  137. return mdbuf;
  138. }
  139. void
  140. md_mmap_free(struct md_mmap *_md)
  141. {
  142. if (_md) {
  143. memmap_free(_md->mmap);
  144. free(_md->html);
  145. }
  146. }
  147. static const struct lowdown_opts ldopts = {
  148. .type = LOWDOWN_HTML,
  149. .feat = LOWDOWN_STRIKE | LOWDOWN_AUTOLINK | LOWDOWN_FENCED
  150. | LOWDOWN_TABLES,
  151. .oflags = LOWDOWN_HTML_HEAD_IDS | LOWDOWN_HTML_NUM_ENT
  152. };
  153. void
  154. md_mmap_parse(struct md_mmap *_md)
  155. {
  156. if (_md && _md->md)
  157. lowdown_buf(&ldopts, _md->mmap->data, _md->mmap->size,
  158. &(_md->html), &(_md->htmlsz), NULL);
  159. }
  160. void
  161. md_mmap_content(struct md_mmap *_md, void **_data, size_t *_size)
  162. {
  163. if (_md) {
  164. *_data = _md->md ? _md->html : _md->mmap->data;
  165. *_size = _md->md ? _md->htmlsz : _md->mmap->size;
  166. } else {
  167. *_data = NULL;
  168. *_size = 0;
  169. }
  170. }
  171. bool
  172. ishexdigit(const int _c)
  173. {
  174. int c = tolower(_c);
  175. return (isdigit(c) || ((c >= 'a') && (c <= 'f')));
  176. }
  177. char
  178. decode_hexdigit(const char *_s)
  179. {
  180. _s++;
  181. int highnibble = tolower(*_s++);
  182. if (isdigit(highnibble))
  183. highnibble -= '0';
  184. else
  185. highnibble -= 'a';
  186. int lownibble = tolower(*_s);
  187. if (isdigit(lownibble))
  188. lownibble -= '0';
  189. else
  190. lownibble -= 'a';
  191. return ((highnibble << 4) | (lownibble));
  192. }
  193. void
  194. decode_string(char *_s)
  195. {
  196. if (_s == NULL)
  197. return;
  198. char *s = _s;
  199. char *d = s;
  200. while (*s != '\0') {
  201. if (*s == '+') {
  202. *d = ' ';
  203. } else {
  204. if (*s == '%' && s[1] != '\0' && ishexdigit(s[1])
  205. && s[2] != '\0' && ishexdigit(s[2])) {
  206. *d = decode_hexdigit(s);
  207. s += 2;
  208. } else {
  209. *d = *s;
  210. }
  211. }
  212. s++;
  213. d++;
  214. }
  215. *d = *s;
  216. }