aboutsummaryrefslogtreecommitdiff
path: root/src/node.c
blob: fe3dac31d2e70dc01c084595cddc83307fe39ad5 (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. static inline bool
  8. S_is_block(cmark_node *node)
  9. {
  10. if (node == NULL) {
  11. return false;
  12. }
  13. return node->type >= CMARK_NODE_FIRST_BLOCK
  14. && node->type <= CMARK_NODE_LAST_BLOCK;
  15. }
  16. static inline bool
  17. S_is_inline(cmark_node *node)
  18. {
  19. if (node == NULL) {
  20. return false;
  21. }
  22. return node->type >= CMARK_NODE_FIRST_INLINE
  23. && node->type <= CMARK_NODE_LAST_INLINE;
  24. }
  25. static bool
  26. S_can_contain(cmark_node *node, cmark_node *child)
  27. {
  28. cmark_node *cur;
  29. if (node == NULL || child == NULL) {
  30. return false;
  31. }
  32. // Verify that child is not an ancestor of node or equal to node.
  33. cur = node;
  34. do {
  35. if (cur == child) {
  36. return false;
  37. }
  38. cur = cur->parent;
  39. } while (cur != NULL);
  40. if (child->type == CMARK_NODE_DOCUMENT) {
  41. return false;
  42. }
  43. switch (node->type) {
  44. case CMARK_NODE_DOCUMENT:
  45. case CMARK_NODE_BLOCK_QUOTE:
  46. case CMARK_NODE_ITEM:
  47. return S_is_block(child)
  48. && child->type != CMARK_NODE_ITEM;
  49. case CMARK_NODE_LIST:
  50. return child->type == CMARK_NODE_ITEM;
  51. case CMARK_NODE_PARAGRAPH:
  52. case CMARK_NODE_HEADER:
  53. case CMARK_NODE_EMPH:
  54. case CMARK_NODE_STRONG:
  55. case CMARK_NODE_LINK:
  56. case CMARK_NODE_IMAGE:
  57. return S_is_inline(child);
  58. default:
  59. break;
  60. }
  61. return false;
  62. }
  63. cmark_node*
  64. cmark_node_new(cmark_node_type type)
  65. {
  66. cmark_node *node = (cmark_node *)calloc(1, sizeof(*node));
  67. node->type = type;
  68. switch (node->type) {
  69. case CMARK_NODE_HEADER:
  70. node->as.header.level = 1;
  71. break;
  72. case CMARK_NODE_LIST: {
  73. cmark_list *list = &node->as.list;
  74. list->list_type = CMARK_BULLET_LIST;
  75. list->start = 1;
  76. list->tight = false;
  77. break;
  78. }
  79. default:
  80. break;
  81. }
  82. return node;
  83. }
  84. // Free a cmark_node list and any children.
  85. static
  86. void S_free_nodes(cmark_node *e)
  87. {
  88. cmark_node *next;
  89. while (e != NULL) {
  90. if (S_is_block(e)) {
  91. cmark_strbuf_free(&e->string_content);
  92. }
  93. switch (e->type) {
  94. case NODE_CODE_BLOCK:
  95. cmark_chunk_free(&e->as.code.info);
  96. cmark_chunk_free(&e->as.code.literal);
  97. break;
  98. case NODE_TEXT:
  99. case NODE_INLINE_HTML:
  100. case NODE_CODE:
  101. case NODE_HTML:
  102. cmark_chunk_free(&e->as.literal);
  103. break;
  104. case NODE_LINK:
  105. case NODE_IMAGE:
  106. if (e->as.link.url) {
  107. free(e->as.link.url);
  108. }
  109. if (e->as.link.title) {
  110. free(e->as.link.title);
  111. }
  112. break;
  113. default:
  114. break;
  115. }
  116. if (e->last_child) {
  117. // Splice children into list
  118. e->last_child->next = e->next;
  119. e->next = e->first_child;
  120. }
  121. next = e->next;
  122. free(e);
  123. e = next;
  124. }
  125. }
  126. void
  127. cmark_node_free(cmark_node *node)
  128. {
  129. S_node_unlink(node);
  130. node->next = NULL;
  131. S_free_nodes(node);
  132. }
  133. cmark_node_type
  134. cmark_node_get_type(cmark_node *node)
  135. {
  136. if (node == NULL) {
  137. return CMARK_NODE_NONE;
  138. } else {
  139. return node->type;
  140. }
  141. }
  142. const char*
  143. cmark_node_get_type_string(cmark_node *node)
  144. {
  145. if (node == NULL) {
  146. return "NONE";
  147. }
  148. switch (node->type) {
  149. case CMARK_NODE_NONE:
  150. return "none";
  151. case CMARK_NODE_DOCUMENT:
  152. return "document";
  153. case CMARK_NODE_BLOCK_QUOTE:
  154. return "block_quote";
  155. case CMARK_NODE_LIST:
  156. return "list";
  157. case CMARK_NODE_ITEM:
  158. return "item";
  159. case CMARK_NODE_CODE_BLOCK:
  160. return "code_block";
  161. case CMARK_NODE_HTML:
  162. return "html";
  163. case CMARK_NODE_PARAGRAPH:
  164. return "paragraph";
  165. case CMARK_NODE_HEADER:
  166. return "header";
  167. case CMARK_NODE_HRULE:
  168. return "hrule";
  169. case CMARK_NODE_TEXT:
  170. return "text";
  171. case CMARK_NODE_SOFTBREAK:
  172. return "softbreak";
  173. case CMARK_NODE_LINEBREAK:
  174. return "linebreak";
  175. case CMARK_NODE_CODE:
  176. return "code";
  177. case CMARK_NODE_INLINE_HTML:
  178. return "inline_html";
  179. case CMARK_NODE_EMPH:
  180. return "emph";
  181. case CMARK_NODE_STRONG:
  182. return "strong";
  183. case CMARK_NODE_LINK:
  184. return "link";
  185. case CMARK_NODE_IMAGE:
  186. return "image";
  187. }
  188. return "<unknown>";
  189. }
  190. cmark_node*
  191. cmark_node_next(cmark_node *node)
  192. {
  193. if (node == NULL) {
  194. return NULL;
  195. } else {
  196. return node->next;
  197. }
  198. }
  199. cmark_node*
  200. cmark_node_previous(cmark_node *node)
  201. {
  202. if (node == NULL) {
  203. return NULL;
  204. } else {
  205. return node->prev;
  206. }
  207. }
  208. cmark_node*
  209. cmark_node_parent(cmark_node *node)
  210. {
  211. if (node == NULL) {
  212. return NULL;
  213. } else {
  214. return node->parent;
  215. }
  216. }
  217. cmark_node*
  218. cmark_node_first_child(cmark_node *node)
  219. {
  220. if (node == NULL) {
  221. return NULL;
  222. } else {
  223. return node->first_child;
  224. }
  225. }
  226. cmark_node*
  227. cmark_node_last_child(cmark_node *node)
  228. {
  229. if (node == NULL) {
  230. return NULL;
  231. } else {
  232. return node->last_child;
  233. }
  234. }
  235. void*
  236. cmark_node_get_user_data(cmark_node *node) {
  237. if (node == NULL) {
  238. return NULL;
  239. } else {
  240. return node->user_data;
  241. }
  242. }
  243. int
  244. cmark_node_set_user_data(cmark_node *node, void *user_data) {
  245. if (node == NULL) {
  246. return 0;
  247. }
  248. node->user_data = user_data;
  249. return 1;
  250. }
  251. static char*
  252. S_strdup(const char *str)
  253. {
  254. size_t size = strlen(str) + 1;
  255. char *dup = (char *)malloc(size);
  256. memcpy(dup, str, size);
  257. return dup;
  258. }
  259. const char*
  260. cmark_node_get_literal(cmark_node *node)
  261. {
  262. if (node == NULL) {
  263. return NULL;
  264. }
  265. switch (node->type) {
  266. case NODE_HTML:
  267. case NODE_TEXT:
  268. case NODE_INLINE_HTML:
  269. case NODE_CODE:
  270. return cmark_chunk_to_cstr(&node->as.literal);
  271. case NODE_CODE_BLOCK:
  272. return cmark_chunk_to_cstr(&node->as.code.literal);
  273. default:
  274. break;
  275. }
  276. return NULL;
  277. }
  278. int
  279. cmark_node_set_literal(cmark_node *node, const char *content)
  280. {
  281. if (node == NULL) {
  282. return 0;
  283. }
  284. switch (node->type) {
  285. case NODE_HTML:
  286. case NODE_TEXT:
  287. case NODE_INLINE_HTML:
  288. case NODE_CODE:
  289. cmark_chunk_set_cstr(&node->as.literal, content);
  290. return 1;
  291. case NODE_CODE_BLOCK:
  292. cmark_chunk_set_cstr(&node->as.code.literal, content);
  293. return 1;
  294. default:
  295. break;
  296. }
  297. return 0;
  298. }
  299. int
  300. cmark_node_get_header_level(cmark_node *node)
  301. {
  302. if (node == NULL) {
  303. return 0;
  304. }
  305. switch (node->type) {
  306. case CMARK_NODE_HEADER:
  307. return node->as.header.level;
  308. default:
  309. break;
  310. }
  311. return 0;
  312. }
  313. int
  314. cmark_node_set_header_level(cmark_node *node, int level)
  315. {
  316. if (node == NULL || level < 1 || level > 6) {
  317. return 0;
  318. }
  319. switch (node->type) {
  320. case CMARK_NODE_HEADER:
  321. node->as.header.level = level;
  322. return 1;
  323. default:
  324. break;
  325. }
  326. return 0;
  327. }
  328. cmark_list_type
  329. cmark_node_get_list_type(cmark_node *node)
  330. {
  331. if (node == NULL) {
  332. return CMARK_NO_LIST;
  333. }
  334. if (node->type == CMARK_NODE_LIST) {
  335. return node->as.list.list_type;
  336. } else {
  337. return CMARK_NO_LIST;
  338. }
  339. }
  340. int
  341. cmark_node_set_list_type(cmark_node *node, cmark_list_type type)
  342. {
  343. if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) {
  344. return 0;
  345. }
  346. if (node == NULL) {
  347. return 0;
  348. }
  349. if (node->type == CMARK_NODE_LIST) {
  350. node->as.list.list_type = type;
  351. return 1;
  352. } else {
  353. return 0;
  354. }
  355. }
  356. cmark_delim_type
  357. cmark_node_get_list_delim(cmark_node *node)
  358. {
  359. if (node == NULL) {
  360. return CMARK_NO_DELIM;
  361. }
  362. if (node->type == CMARK_NODE_LIST) {
  363. return node->as.list.delimiter;
  364. } else {
  365. return CMARK_NO_DELIM;
  366. }
  367. }
  368. int
  369. cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim)
  370. {
  371. if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) {
  372. return 0;
  373. }
  374. if (node == NULL) {
  375. return 0;
  376. }
  377. if (node->type == CMARK_NODE_LIST) {
  378. node->as.list.delimiter = delim;
  379. return 1;
  380. } else {
  381. return 0;
  382. }
  383. }
  384. int
  385. cmark_node_get_list_start(cmark_node *node)
  386. {
  387. if (node == NULL) {
  388. return 0;
  389. }
  390. if (node->type == CMARK_NODE_LIST) {
  391. return node->as.list.start;
  392. } else {
  393. return 0;
  394. }
  395. }
  396. int
  397. cmark_node_set_list_start(cmark_node *node, int start)
  398. {
  399. if (node == NULL || start < 0) {
  400. return 0;
  401. }
  402. if (node->type == CMARK_NODE_LIST) {
  403. node->as.list.start = start;
  404. return 1;
  405. } else {
  406. return 0;
  407. }
  408. }
  409. int
  410. cmark_node_get_list_tight(cmark_node *node)
  411. {
  412. if (node == NULL) {
  413. return 0;
  414. }
  415. if (node->type == CMARK_NODE_LIST) {
  416. return node->as.list.tight;
  417. } else {
  418. return 0;
  419. }
  420. }
  421. int
  422. cmark_node_set_list_tight(cmark_node *node, int tight)
  423. {
  424. if (node == NULL) {
  425. return 0;
  426. }
  427. if (node->type == CMARK_NODE_LIST) {
  428. node->as.list.tight = tight;
  429. return 1;
  430. } else {
  431. return 0;
  432. }
  433. }
  434. const char*
  435. cmark_node_get_fence_info(cmark_node *node)
  436. {
  437. if (node == NULL) {
  438. return NULL;
  439. }
  440. if (node->type == NODE_CODE_BLOCK) {
  441. return cmark_chunk_to_cstr(&node->as.code.info);
  442. } else {
  443. return NULL;
  444. }
  445. }
  446. int
  447. cmark_node_set_fence_info(cmark_node *node, const char *info)
  448. {
  449. if (node == NULL) {
  450. return 0;
  451. }
  452. if (node->type == NODE_CODE_BLOCK) {
  453. cmark_chunk_set_cstr(&node->as.code.info, info);
  454. return 1;
  455. } else {
  456. return 0;
  457. }
  458. }
  459. const char*
  460. cmark_node_get_url(cmark_node *node)
  461. {
  462. if (node == NULL) {
  463. return NULL;
  464. }
  465. switch (node->type) {
  466. case NODE_LINK:
  467. case NODE_IMAGE:
  468. return (char *)node->as.link.url;
  469. default:
  470. break;
  471. }
  472. return NULL;
  473. }
  474. int
  475. cmark_node_set_url(cmark_node *node, const char *url)
  476. {
  477. if (node == NULL) {
  478. return 0;
  479. }
  480. switch (node->type) {
  481. case NODE_LINK:
  482. case NODE_IMAGE:
  483. free(node->as.link.url);
  484. node->as.link.url = (unsigned char *)S_strdup(url);
  485. return 1;
  486. default:
  487. break;
  488. }
  489. return 0;
  490. }
  491. const char*
  492. cmark_node_get_title(cmark_node *node)
  493. {
  494. if (node == NULL) {
  495. return NULL;
  496. }
  497. switch (node->type) {
  498. case NODE_LINK:
  499. case NODE_IMAGE:
  500. return (char *)node->as.link.title;
  501. default:
  502. break;
  503. }
  504. return NULL;
  505. }
  506. int
  507. cmark_node_set_title(cmark_node *node, const char *title)
  508. {
  509. if (node == NULL) {
  510. return 0;
  511. }
  512. switch (node->type) {
  513. case NODE_LINK:
  514. case NODE_IMAGE:
  515. free(node->as.link.title);
  516. node->as.link.title = (unsigned char *)S_strdup(title);
  517. return 1;
  518. default:
  519. break;
  520. }
  521. return 0;
  522. }
  523. int
  524. cmark_node_get_start_line(cmark_node *node)
  525. {
  526. if (node == NULL) {
  527. return 0;
  528. }
  529. return node->start_line;
  530. }
  531. int
  532. cmark_node_get_start_column(cmark_node *node)
  533. {
  534. if (node == NULL) {
  535. return 0;
  536. }
  537. return node->start_column;
  538. }
  539. int
  540. cmark_node_get_end_line(cmark_node *node)
  541. {
  542. if (node == NULL) {
  543. return 0;
  544. }
  545. return node->end_line;
  546. }
  547. int
  548. cmark_node_get_end_column(cmark_node *node)
  549. {
  550. if (node == NULL) {
  551. return 0;
  552. }
  553. return node->end_column;
  554. }
  555. // Unlink a node without adjusting its next, prev, and parent pointers.
  556. static void
  557. S_node_unlink(cmark_node *node)
  558. {
  559. if (node == NULL) {
  560. return;
  561. }
  562. if (node->prev) {
  563. node->prev->next = node->next;
  564. }
  565. if (node->next) {
  566. node->next->prev = node->prev;
  567. }
  568. // Adjust first_child and last_child of parent.
  569. cmark_node *parent = node->parent;
  570. if (parent) {
  571. if (parent->first_child == node) {
  572. parent->first_child = node->next;
  573. }
  574. if (parent->last_child == node) {
  575. parent->last_child = node->prev;
  576. }
  577. }
  578. }
  579. void
  580. cmark_node_unlink(cmark_node *node)
  581. {
  582. S_node_unlink(node);
  583. node->next = NULL;
  584. node->prev = NULL;
  585. node->parent = NULL;
  586. }
  587. int
  588. cmark_node_insert_before(cmark_node *node, cmark_node *sibling)
  589. {
  590. if (node == NULL || sibling == NULL) {
  591. return 0;
  592. }
  593. if (!node->parent || !S_can_contain(node->parent, sibling)) {
  594. return 0;
  595. }
  596. S_node_unlink(sibling);
  597. cmark_node *old_prev = node->prev;
  598. // Insert 'sibling' between 'old_prev' and 'node'.
  599. if (old_prev) {
  600. old_prev->next = sibling;
  601. }
  602. sibling->prev = old_prev;
  603. sibling->next = node;
  604. node->prev = sibling;
  605. // Set new parent.
  606. cmark_node *parent = node->parent;
  607. sibling->parent = parent;
  608. // Adjust first_child of parent if inserted as first child.
  609. if (parent && !old_prev) {
  610. parent->first_child = sibling;
  611. }
  612. return 1;
  613. }
  614. int
  615. cmark_node_insert_after(cmark_node *node, cmark_node *sibling)
  616. {
  617. if (node == NULL || sibling == NULL) {
  618. return 0;
  619. }
  620. if (!node->parent || !S_can_contain(node->parent, sibling)) {
  621. return 0;
  622. }
  623. S_node_unlink(sibling);
  624. cmark_node *old_next = node->next;
  625. // Insert 'sibling' between 'node' and 'old_next'.
  626. if (old_next) {
  627. old_next->prev = sibling;
  628. }
  629. sibling->next = old_next;
  630. sibling->prev = node;
  631. node->next = sibling;
  632. // Set new parent.
  633. cmark_node *parent = node->parent;
  634. sibling->parent = parent;
  635. // Adjust last_child of parent if inserted as last child.
  636. if (parent && !old_next) {
  637. parent->last_child = sibling;
  638. }
  639. return 1;
  640. }
  641. int
  642. cmark_node_prepend_child(cmark_node *node, cmark_node *child)
  643. {
  644. if (!S_can_contain(node, child)) {
  645. return 0;
  646. }
  647. S_node_unlink(child);
  648. cmark_node *old_first_child = node->first_child;
  649. child->next = old_first_child;
  650. child->prev = NULL;
  651. child->parent = node;
  652. node->first_child = child;
  653. if (old_first_child) {
  654. old_first_child->prev = child;
  655. } else {
  656. // Also set last_child if node previously had no children.
  657. node->last_child = child;
  658. }
  659. return 1;
  660. }
  661. int
  662. cmark_node_append_child(cmark_node *node, cmark_node *child)
  663. {
  664. if (!S_can_contain(node, child)) {
  665. return 0;
  666. }
  667. S_node_unlink(child);
  668. cmark_node *old_last_child = node->last_child;
  669. child->next = NULL;
  670. child->prev = old_last_child;
  671. child->parent = node;
  672. node->last_child = child;
  673. if (old_last_child) {
  674. old_last_child->next = child;
  675. } else {
  676. // Also set first_child if node previously had no children.
  677. node->first_child = child;
  678. }
  679. return 1;
  680. }
  681. static void
  682. S_print_error(FILE *out, cmark_node *node, const char *elem)
  683. {
  684. if (out == NULL) {
  685. return;
  686. }
  687. fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem,
  688. cmark_node_get_type_string(node), node->start_line,
  689. node->start_column);
  690. }
  691. int
  692. cmark_node_check(cmark_node *node, FILE *out)
  693. {
  694. cmark_node *cur;
  695. int errors = 0;
  696. if (!node) {
  697. return 0;
  698. }
  699. cur = node;
  700. while (true) {
  701. if (cur->first_child) {
  702. if (cur->first_child->prev != NULL) {
  703. S_print_error(out, cur->first_child, "prev");
  704. cur->first_child->prev = NULL;
  705. ++errors;
  706. }
  707. if (cur->first_child->parent != cur) {
  708. S_print_error(out, cur->first_child, "parent");
  709. cur->first_child->parent = cur;
  710. ++errors;
  711. }
  712. cur = cur->first_child;
  713. continue;
  714. }
  715. next_sibling:
  716. if (cur == node) {
  717. break;
  718. }
  719. if (cur->next) {
  720. if (cur->next->prev != cur) {
  721. S_print_error(out, cur->next, "prev");
  722. cur->next->prev = cur;
  723. ++errors;
  724. }
  725. if (cur->next->parent != cur->parent) {
  726. S_print_error(out, cur->next, "parent");
  727. cur->next->parent = cur->parent;
  728. ++errors;
  729. }
  730. cur = cur->next;
  731. continue;
  732. }
  733. if (cur->parent->last_child != cur) {
  734. S_print_error(out, cur->parent, "last_child");
  735. cur->parent->last_child = cur;
  736. ++errors;
  737. }
  738. cur = cur->parent;
  739. goto next_sibling;
  740. }
  741. return errors;
  742. }