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