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