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