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