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