aboutsummaryrefslogtreecommitdiff
path: root/src/node.c
blob: fd92fdc6db78943ef4ee78bb82914366ceaf0ac7 (plain)
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "config.h"
  4. #include "node.h"
  5. static void
  6. S_node_unlink(cmark_node *node);
  7. cmark_node*
  8. cmark_node_new(cmark_node_type type) {
  9. cmark_node *node = (cmark_node *)calloc(1, sizeof(*node));
  10. node->type = type;
  11. switch (node->type) {
  12. case CMARK_NODE_HEADER:
  13. node->as.header.level = 1;
  14. break;
  15. case CMARK_NODE_LIST: {
  16. cmark_list *list = &node->as.list;
  17. list->list_type = CMARK_BULLET_LIST;
  18. list->start = 1;
  19. list->tight = false;
  20. break;
  21. }
  22. default:
  23. break;
  24. }
  25. return node;
  26. }
  27. // Free a cmark_node list and any children.
  28. static
  29. void S_free_nodes(cmark_node *e)
  30. {
  31. cmark_node *next;
  32. while (e != NULL) {
  33. strbuf_free(&e->string_content);
  34. switch (e->type){
  35. case NODE_CODE_BLOCK:
  36. strbuf_free(&e->as.code.info);
  37. break;
  38. case NODE_TEXT:
  39. case NODE_INLINE_HTML:
  40. case NODE_INLINE_CODE:
  41. cmark_chunk_free(&e->as.literal);
  42. break;
  43. case NODE_LINK:
  44. case NODE_IMAGE:
  45. free(e->as.link.url);
  46. free(e->as.link.title);
  47. break;
  48. default:
  49. break;
  50. }
  51. if (e->last_child) {
  52. // Splice children into list
  53. e->last_child->next = e->next;
  54. e->next = e->first_child;
  55. }
  56. next = e->next;
  57. free(e);
  58. e = next;
  59. }
  60. }
  61. void
  62. cmark_node_free(cmark_node *node) {
  63. S_node_unlink(node);
  64. node->next = NULL;
  65. S_free_nodes(node);
  66. }
  67. cmark_node_type
  68. cmark_node_get_type(cmark_node *node)
  69. {
  70. return node->type;
  71. }
  72. static const char*
  73. S_type_string(cmark_node *node)
  74. {
  75. switch (node->type) {
  76. case CMARK_NODE_DOCUMENT: return "DOCUMENT";
  77. case CMARK_NODE_BLOCK_QUOTE: return "BLOCK_QUOTE";
  78. case CMARK_NODE_LIST: return "LIST";
  79. case CMARK_NODE_LIST_ITEM: return "LIST_ITEM";
  80. case CMARK_NODE_CODE_BLOCK: return "CODE_BLOCK";
  81. case CMARK_NODE_HTML: return "HTML";
  82. case CMARK_NODE_PARAGRAPH: return "PARAGRAPH";
  83. case CMARK_NODE_HEADER: return "HEADER";
  84. case CMARK_NODE_HRULE: return "HRULE";
  85. case CMARK_NODE_REFERENCE_DEF: return "REFERENCE_DEF";
  86. case CMARK_NODE_TEXT: return "TEXT";
  87. case CMARK_NODE_SOFTBREAK: return "SOFTBREAK";
  88. case CMARK_NODE_LINEBREAK: return "LINEBREAK";
  89. case CMARK_NODE_INLINE_CODE: return "INLINE_CODE";
  90. case CMARK_NODE_INLINE_HTML: return "INLINE_HTML";
  91. case CMARK_NODE_EMPH: return "EMPH";
  92. case CMARK_NODE_STRONG: return "STRONG";
  93. case CMARK_NODE_LINK: return "LINK";
  94. case CMARK_NODE_IMAGE: return "IMAGE";
  95. }
  96. return "<unknown>";
  97. }
  98. cmark_node*
  99. cmark_node_next(cmark_node *node)
  100. {
  101. return node->next;
  102. }
  103. cmark_node*
  104. cmark_node_previous(cmark_node *node)
  105. {
  106. return node->prev;
  107. }
  108. cmark_node*
  109. cmark_node_parent(cmark_node *node)
  110. {
  111. return node->parent;
  112. }
  113. cmark_node*
  114. cmark_node_first_child(cmark_node *node)
  115. {
  116. return node->first_child;
  117. }
  118. cmark_node*
  119. cmark_node_last_child(cmark_node *node)
  120. {
  121. return node->last_child;
  122. }
  123. static char*
  124. S_strdup(const char *str) {
  125. size_t size = strlen(str) + 1;
  126. char *dup = (char *)malloc(size);
  127. memcpy(dup, str, size);
  128. return dup;
  129. }
  130. const char*
  131. cmark_node_get_string_content(cmark_node *node) {
  132. switch (node->type) {
  133. case NODE_CODE_BLOCK:
  134. case NODE_HTML:
  135. return cmark_strbuf_cstr(&node->string_content);
  136. case NODE_TEXT:
  137. case NODE_INLINE_HTML:
  138. case NODE_INLINE_CODE:
  139. return cmark_chunk_to_cstr(&node->as.literal);
  140. default:
  141. break;
  142. }
  143. return NULL;
  144. }
  145. int
  146. cmark_node_set_string_content(cmark_node *node, const char *content) {
  147. switch (node->type) {
  148. case NODE_CODE_BLOCK:
  149. case NODE_HTML:
  150. cmark_strbuf_sets(&node->string_content, content);
  151. return 1;
  152. case NODE_TEXT:
  153. case NODE_INLINE_HTML:
  154. case NODE_INLINE_CODE:
  155. cmark_chunk_set_cstr(&node->as.literal, content);
  156. return 1;
  157. default:
  158. break;
  159. }
  160. return 0;
  161. }
  162. int
  163. cmark_node_get_header_level(cmark_node *node) {
  164. switch (node->type) {
  165. case CMARK_NODE_HEADER:
  166. return node->as.header.level;
  167. default:
  168. break;
  169. }
  170. return 0;
  171. }
  172. int
  173. cmark_node_set_header_level(cmark_node *node, int level) {
  174. if (level < 1 || level > 6) {
  175. return 0;
  176. }
  177. switch (node->type) {
  178. case CMARK_NODE_HEADER:
  179. node->as.header.level = level;
  180. return 1;
  181. default:
  182. break;
  183. }
  184. return 0;
  185. }
  186. cmark_list_type
  187. cmark_node_get_list_type(cmark_node *node) {
  188. if (node->type == CMARK_NODE_LIST) {
  189. return node->as.list.list_type;
  190. }
  191. else {
  192. return CMARK_NO_LIST;
  193. }
  194. }
  195. int
  196. cmark_node_set_list_type(cmark_node *node, cmark_list_type type) {
  197. if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) {
  198. return 0;
  199. }
  200. if (node->type == CMARK_NODE_LIST) {
  201. node->as.list.list_type = type;
  202. return 1;
  203. }
  204. else {
  205. return 0;
  206. }
  207. }
  208. int
  209. cmark_node_get_list_start(cmark_node *node) {
  210. if (node->type == CMARK_NODE_LIST) {
  211. return node->as.list.start;
  212. }
  213. else {
  214. return 0;
  215. }
  216. }
  217. int
  218. cmark_node_set_list_start(cmark_node *node, int start) {
  219. if (start < 0) {
  220. return 0;
  221. }
  222. if (node->type == CMARK_NODE_LIST) {
  223. node->as.list.start = start;
  224. return 1;
  225. }
  226. else {
  227. return 0;
  228. }
  229. }
  230. int
  231. cmark_node_get_list_tight(cmark_node *node) {
  232. if (node->type == CMARK_NODE_LIST) {
  233. return node->as.list.tight;
  234. }
  235. else {
  236. return 0;
  237. }
  238. }
  239. int
  240. cmark_node_set_list_tight(cmark_node *node, int tight) {
  241. if (node->type == CMARK_NODE_LIST) {
  242. node->as.list.tight = tight;
  243. return 1;
  244. }
  245. else {
  246. return 0;
  247. }
  248. }
  249. const char*
  250. cmark_node_get_fence_info(cmark_node *node) {
  251. if (node->type == NODE_CODE_BLOCK) {
  252. return cmark_strbuf_cstr(&node->as.code.info);
  253. }
  254. else {
  255. return NULL;
  256. }
  257. }
  258. int
  259. cmark_node_set_fence_info(cmark_node *node, const char *info) {
  260. if (node->type == NODE_CODE_BLOCK) {
  261. cmark_strbuf_sets(&node->as.code.info, info);
  262. return 1;
  263. }
  264. else {
  265. return 0;
  266. }
  267. }
  268. const char*
  269. cmark_node_get_url(cmark_node *node) {
  270. switch (node->type) {
  271. case NODE_LINK:
  272. case NODE_IMAGE:
  273. return (char *)node->as.link.url;
  274. default:
  275. break;
  276. }
  277. return NULL;
  278. }
  279. int
  280. cmark_node_set_url(cmark_node *node, const char *url) {
  281. switch (node->type) {
  282. case NODE_LINK:
  283. case NODE_IMAGE:
  284. free(node->as.link.url);
  285. node->as.link.url = (unsigned char *)S_strdup(url);
  286. return 1;
  287. default:
  288. break;
  289. }
  290. return 0;
  291. }
  292. const char*
  293. cmark_node_get_title(cmark_node *node) {
  294. switch (node->type) {
  295. case NODE_LINK:
  296. case NODE_IMAGE:
  297. return (char *)node->as.link.title;
  298. default:
  299. break;
  300. }
  301. return NULL;
  302. }
  303. int
  304. cmark_node_set_title(cmark_node *node, const char *title) {
  305. switch (node->type) {
  306. case NODE_LINK:
  307. case NODE_IMAGE:
  308. free(node->as.link.title);
  309. node->as.link.title = (unsigned char *)S_strdup(title);
  310. return 1;
  311. default:
  312. break;
  313. }
  314. return 0;
  315. }
  316. int
  317. cmark_node_get_start_line(cmark_node *node) {
  318. return node->start_line;
  319. }
  320. int
  321. cmark_node_get_start_column(cmark_node *node) {
  322. return node->start_column;
  323. }
  324. int
  325. cmark_node_get_end_line(cmark_node *node) {
  326. return node->end_line;
  327. }
  328. static inline bool
  329. S_is_block(cmark_node *node) {
  330. return node->type >= CMARK_NODE_FIRST_BLOCK
  331. && node->type <= CMARK_NODE_LAST_BLOCK;
  332. }
  333. static inline bool
  334. S_is_inline(cmark_node *node) {
  335. return node->type >= CMARK_NODE_FIRST_INLINE
  336. && node->type <= CMARK_NODE_LAST_INLINE;
  337. }
  338. static bool
  339. S_can_contain(cmark_node *node, cmark_node *child)
  340. {
  341. cmark_node *cur;
  342. // Verify that child is not an ancestor of node or equal to node.
  343. cur = node;
  344. do {
  345. if (cur == child) {
  346. return false;
  347. }
  348. cur = cur->parent;
  349. } while (cur != NULL);
  350. if (child->type == CMARK_NODE_DOCUMENT) {
  351. return false;
  352. }
  353. switch (node->type) {
  354. case CMARK_NODE_DOCUMENT:
  355. case CMARK_NODE_BLOCK_QUOTE:
  356. case CMARK_NODE_LIST_ITEM:
  357. return S_is_block(child)
  358. && child->type != CMARK_NODE_LIST_ITEM;
  359. case CMARK_NODE_LIST:
  360. return child->type == CMARK_NODE_LIST_ITEM;
  361. case CMARK_NODE_PARAGRAPH:
  362. case CMARK_NODE_HEADER:
  363. case CMARK_NODE_EMPH:
  364. case CMARK_NODE_STRONG:
  365. case CMARK_NODE_LINK:
  366. case CMARK_NODE_IMAGE:
  367. return S_is_inline(child);
  368. default:
  369. break;
  370. }
  371. return false;
  372. }
  373. // Unlink a node without adjusting its next, prev, and parent pointers.
  374. static void
  375. S_node_unlink(cmark_node *node)
  376. {
  377. if (node->prev) {
  378. node->prev->next = node->next;
  379. }
  380. if (node->next) {
  381. node->next->prev = node->prev;
  382. }
  383. // Adjust first_child and last_child of parent.
  384. cmark_node *parent = node->parent;
  385. if (parent) {
  386. if (parent->first_child == node) {
  387. parent->first_child = node->next;
  388. }
  389. if (parent->last_child == node) {
  390. parent->last_child = node->prev;
  391. }
  392. }
  393. }
  394. void
  395. cmark_node_unlink(cmark_node *node) {
  396. S_node_unlink(node);
  397. node->next = NULL;
  398. node->prev = NULL;
  399. node->parent = NULL;
  400. }
  401. int
  402. cmark_node_insert_before(cmark_node *node, cmark_node *sibling)
  403. {
  404. if (!node->parent || !S_can_contain(node->parent, sibling)) {
  405. return 0;
  406. }
  407. S_node_unlink(sibling);
  408. cmark_node *old_prev = node->prev;
  409. // Insert 'sibling' between 'old_prev' and 'node'.
  410. if (old_prev) {
  411. old_prev->next = sibling;
  412. }
  413. sibling->prev = old_prev;
  414. sibling->next = node;
  415. node->prev = sibling;
  416. // Set new parent.
  417. cmark_node *parent = node->parent;
  418. sibling->parent = parent;
  419. // Adjust first_child of parent if inserted as first child.
  420. if (parent && !old_prev) {
  421. parent->first_child = sibling;
  422. }
  423. return 1;
  424. }
  425. int
  426. cmark_node_insert_after(cmark_node *node, cmark_node *sibling)
  427. {
  428. if (!node->parent || !S_can_contain(node->parent, sibling)) {
  429. return 0;
  430. }
  431. S_node_unlink(sibling);
  432. cmark_node *old_next = node->next;
  433. // Insert 'sibling' between 'node' and 'old_next'.
  434. if (old_next) {
  435. old_next->prev = sibling;
  436. }
  437. sibling->next = old_next;
  438. sibling->prev = node;
  439. node->next = sibling;
  440. // Set new parent.
  441. cmark_node *parent = node->parent;
  442. sibling->parent = parent;
  443. // Adjust last_child of parent if inserted as last child.
  444. if (parent && !old_next) {
  445. parent->last_child = sibling;
  446. }
  447. return 1;
  448. }
  449. int
  450. cmark_node_prepend_child(cmark_node *node, cmark_node *child)
  451. {
  452. if (!S_can_contain(node, child)) {
  453. return 0;
  454. }
  455. S_node_unlink(child);
  456. cmark_node *old_first_child = node->first_child;
  457. child->next = old_first_child;
  458. child->prev = NULL;
  459. child->parent = node;
  460. node->first_child = child;
  461. if (old_first_child) {
  462. old_first_child->prev = child;
  463. }
  464. else {
  465. // Also set last_child if node previously had no children.
  466. node->last_child = child;
  467. }
  468. return 1;
  469. }
  470. int
  471. cmark_node_append_child(cmark_node *node, cmark_node *child)
  472. {
  473. if (!S_can_contain(node, child)) {
  474. return 0;
  475. }
  476. S_node_unlink(child);
  477. cmark_node *old_last_child = node->last_child;
  478. child->next = NULL;
  479. child->prev = old_last_child;
  480. child->parent = node;
  481. node->last_child = child;
  482. if (old_last_child) {
  483. old_last_child->next = child;
  484. }
  485. else {
  486. // Also set first_child if node previously had no children.
  487. node->first_child = child;
  488. }
  489. return 1;
  490. }
  491. static void
  492. S_print_error(FILE *out, cmark_node *node, const char *elem)
  493. {
  494. if (out == NULL) {
  495. return;
  496. }
  497. fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem,
  498. S_type_string(node), node->start_line, node->start_column);
  499. }
  500. int
  501. cmark_node_check(cmark_node *node, FILE *out)
  502. {
  503. cmark_node *cur;
  504. int errors = 0;
  505. if (!node) {
  506. return 0;
  507. }
  508. cur = node;
  509. while (true) {
  510. if (cur->first_child) {
  511. if (cur->first_child->prev != NULL) {
  512. S_print_error(out, cur->first_child, "prev");
  513. cur->first_child->prev = NULL;
  514. ++errors;
  515. }
  516. if (cur->first_child->parent != cur) {
  517. S_print_error(out, cur->first_child, "parent");
  518. cur->first_child->parent = cur;
  519. ++errors;
  520. }
  521. cur = cur->first_child;
  522. continue;
  523. }
  524. next_sibling:
  525. if (cur == node) {
  526. break;
  527. }
  528. if (cur->next) {
  529. if (cur->next->prev != cur) {
  530. S_print_error(out, cur->next, "prev");
  531. cur->next->prev = cur;
  532. ++errors;
  533. }
  534. if (cur->next->parent != cur->parent) {
  535. S_print_error(out, cur->next, "parent");
  536. cur->next->parent = cur->parent;
  537. ++errors;
  538. }
  539. cur = cur->next;
  540. continue;
  541. }
  542. if (cur->parent->last_child != cur) {
  543. S_print_error(out, cur->parent, "last_child");
  544. cur->parent->last_child = cur;
  545. ++errors;
  546. }
  547. cur = cur->parent;
  548. goto next_sibling;
  549. }
  550. return errors;
  551. }