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