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