aboutsummaryrefslogtreecommitdiff
path: root/src/node.c
blob: 88b1281b66207ad9d4a1576095a5cd116fdef49f (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. const char*
  79. cmark_node_get_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_ITEM: return "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. int
  409. cmark_node_get_end_column(cmark_node *node) {
  410. if (node == NULL) {
  411. return 0;
  412. }
  413. return node->end_column;
  414. }
  415. static inline bool
  416. S_is_block(cmark_node *node) {
  417. if (node == NULL) {
  418. return false;
  419. }
  420. return node->type >= CMARK_NODE_FIRST_BLOCK
  421. && node->type <= CMARK_NODE_LAST_BLOCK;
  422. }
  423. static inline bool
  424. S_is_inline(cmark_node *node) {
  425. if (node == NULL) {
  426. return false;
  427. }
  428. return node->type >= CMARK_NODE_FIRST_INLINE
  429. && node->type <= CMARK_NODE_LAST_INLINE;
  430. }
  431. static bool
  432. S_can_contain(cmark_node *node, cmark_node *child)
  433. {
  434. cmark_node *cur;
  435. if (node == NULL || child == NULL) {
  436. return false;
  437. }
  438. // Verify that child is not an ancestor of node or equal to node.
  439. cur = node;
  440. do {
  441. if (cur == child) {
  442. return false;
  443. }
  444. cur = cur->parent;
  445. } while (cur != NULL);
  446. if (child->type == CMARK_NODE_DOCUMENT) {
  447. return false;
  448. }
  449. switch (node->type) {
  450. case CMARK_NODE_DOCUMENT:
  451. case CMARK_NODE_BLOCK_QUOTE:
  452. case CMARK_NODE_ITEM:
  453. return S_is_block(child)
  454. && child->type != CMARK_NODE_ITEM;
  455. case CMARK_NODE_LIST:
  456. return child->type == CMARK_NODE_ITEM;
  457. case CMARK_NODE_PARAGRAPH:
  458. case CMARK_NODE_HEADER:
  459. case CMARK_NODE_EMPH:
  460. case CMARK_NODE_STRONG:
  461. case CMARK_NODE_LINK:
  462. case CMARK_NODE_IMAGE:
  463. return S_is_inline(child);
  464. default:
  465. break;
  466. }
  467. return false;
  468. }
  469. // Unlink a node without adjusting its next, prev, and parent pointers.
  470. static void
  471. S_node_unlink(cmark_node *node)
  472. {
  473. if (node == NULL) {
  474. return;
  475. }
  476. if (node->prev) {
  477. node->prev->next = node->next;
  478. }
  479. if (node->next) {
  480. node->next->prev = node->prev;
  481. }
  482. // Adjust first_child and last_child of parent.
  483. cmark_node *parent = node->parent;
  484. if (parent) {
  485. if (parent->first_child == node) {
  486. parent->first_child = node->next;
  487. }
  488. if (parent->last_child == node) {
  489. parent->last_child = node->prev;
  490. }
  491. }
  492. }
  493. void
  494. cmark_node_unlink(cmark_node *node) {
  495. S_node_unlink(node);
  496. node->next = NULL;
  497. node->prev = NULL;
  498. node->parent = NULL;
  499. }
  500. int
  501. cmark_node_insert_before(cmark_node *node, cmark_node *sibling)
  502. {
  503. if (node == NULL || sibling == NULL) {
  504. return 0;
  505. }
  506. if (!node->parent || !S_can_contain(node->parent, sibling)) {
  507. return 0;
  508. }
  509. S_node_unlink(sibling);
  510. cmark_node *old_prev = node->prev;
  511. // Insert 'sibling' between 'old_prev' and 'node'.
  512. if (old_prev) {
  513. old_prev->next = sibling;
  514. }
  515. sibling->prev = old_prev;
  516. sibling->next = node;
  517. node->prev = sibling;
  518. // Set new parent.
  519. cmark_node *parent = node->parent;
  520. sibling->parent = parent;
  521. // Adjust first_child of parent if inserted as first child.
  522. if (parent && !old_prev) {
  523. parent->first_child = sibling;
  524. }
  525. return 1;
  526. }
  527. int
  528. cmark_node_insert_after(cmark_node *node, cmark_node *sibling)
  529. {
  530. if (node == NULL || sibling == NULL) {
  531. return 0;
  532. }
  533. if (!node->parent || !S_can_contain(node->parent, sibling)) {
  534. return 0;
  535. }
  536. S_node_unlink(sibling);
  537. cmark_node *old_next = node->next;
  538. // Insert 'sibling' between 'node' and 'old_next'.
  539. if (old_next) {
  540. old_next->prev = sibling;
  541. }
  542. sibling->next = old_next;
  543. sibling->prev = node;
  544. node->next = sibling;
  545. // Set new parent.
  546. cmark_node *parent = node->parent;
  547. sibling->parent = parent;
  548. // Adjust last_child of parent if inserted as last child.
  549. if (parent && !old_next) {
  550. parent->last_child = sibling;
  551. }
  552. return 1;
  553. }
  554. int
  555. cmark_node_prepend_child(cmark_node *node, cmark_node *child)
  556. {
  557. if (!S_can_contain(node, child)) {
  558. return 0;
  559. }
  560. S_node_unlink(child);
  561. cmark_node *old_first_child = node->first_child;
  562. child->next = old_first_child;
  563. child->prev = NULL;
  564. child->parent = node;
  565. node->first_child = child;
  566. if (old_first_child) {
  567. old_first_child->prev = child;
  568. }
  569. else {
  570. // Also set last_child if node previously had no children.
  571. node->last_child = child;
  572. }
  573. return 1;
  574. }
  575. int
  576. cmark_node_append_child(cmark_node *node, cmark_node *child)
  577. {
  578. if (!S_can_contain(node, child)) {
  579. return 0;
  580. }
  581. S_node_unlink(child);
  582. cmark_node *old_last_child = node->last_child;
  583. child->next = NULL;
  584. child->prev = old_last_child;
  585. child->parent = node;
  586. node->last_child = child;
  587. if (old_last_child) {
  588. old_last_child->next = child;
  589. }
  590. else {
  591. // Also set first_child if node previously had no children.
  592. node->first_child = child;
  593. }
  594. return 1;
  595. }
  596. static void
  597. S_print_error(FILE *out, cmark_node *node, const char *elem)
  598. {
  599. if (out == NULL) {
  600. return;
  601. }
  602. fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem,
  603. cmark_node_get_type_string(node), node->start_line,
  604. node->start_column);
  605. }
  606. int
  607. cmark_node_check(cmark_node *node, FILE *out)
  608. {
  609. cmark_node *cur;
  610. int errors = 0;
  611. if (!node) {
  612. return 0;
  613. }
  614. cur = node;
  615. while (true) {
  616. if (cur->first_child) {
  617. if (cur->first_child->prev != NULL) {
  618. S_print_error(out, cur->first_child, "prev");
  619. cur->first_child->prev = NULL;
  620. ++errors;
  621. }
  622. if (cur->first_child->parent != cur) {
  623. S_print_error(out, cur->first_child, "parent");
  624. cur->first_child->parent = cur;
  625. ++errors;
  626. }
  627. cur = cur->first_child;
  628. continue;
  629. }
  630. next_sibling:
  631. if (cur == node) {
  632. break;
  633. }
  634. if (cur->next) {
  635. if (cur->next->prev != cur) {
  636. S_print_error(out, cur->next, "prev");
  637. cur->next->prev = cur;
  638. ++errors;
  639. }
  640. if (cur->next->parent != cur->parent) {
  641. S_print_error(out, cur->next, "parent");
  642. cur->next->parent = cur->parent;
  643. ++errors;
  644. }
  645. cur = cur->next;
  646. continue;
  647. }
  648. if (cur->parent->last_child != cur) {
  649. S_print_error(out, cur->parent, "last_child");
  650. cur->parent->last_child = cur;
  651. ++errors;
  652. }
  653. cur = cur->parent;
  654. goto next_sibling;
  655. }
  656. return errors;
  657. }