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