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