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