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