aboutsummaryrefslogtreecommitdiff
path: root/src/node.c
blob: 624baad330f7e22e36da3e48ff1a2fda3e7a8a4e (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. if (child->type == CMARK_NODE_DOCUMENT) {
  300. return false;
  301. }
  302. switch (node->type) {
  303. case CMARK_NODE_DOCUMENT:
  304. case CMARK_NODE_BQUOTE:
  305. case CMARK_NODE_LIST_ITEM:
  306. return S_is_block(child)
  307. && child->type != CMARK_NODE_LIST_ITEM;
  308. case CMARK_NODE_LIST:
  309. return child->type == CMARK_NODE_LIST_ITEM;
  310. case CMARK_NODE_PARAGRAPH:
  311. case CMARK_NODE_ATX_HEADER:
  312. case CMARK_NODE_SETEXT_HEADER:
  313. case CMARK_NODE_EMPH:
  314. case CMARK_NODE_STRONG:
  315. case CMARK_NODE_LINK:
  316. case CMARK_NODE_IMAGE:
  317. return S_is_inline(child);
  318. default:
  319. break;
  320. }
  321. return false;
  322. }
  323. // Unlink a node without adjusting its next, prev, and parent pointers.
  324. static void
  325. S_node_unlink(cmark_node *node)
  326. {
  327. if (node->prev) {
  328. node->prev->next = node->next;
  329. }
  330. if (node->next) {
  331. node->next->prev = node->prev;
  332. }
  333. // Adjust first_child and last_child of parent.
  334. cmark_node *parent = node->parent;
  335. if (parent) {
  336. if (parent->first_child == node) {
  337. parent->first_child = node->next;
  338. }
  339. if (parent->last_child == node) {
  340. parent->last_child = node->prev;
  341. }
  342. }
  343. }
  344. void
  345. cmark_node_unlink(cmark_node *node) {
  346. S_node_unlink(node);
  347. node->next = NULL;
  348. node->prev = NULL;
  349. node->parent = NULL;
  350. }
  351. int
  352. cmark_node_insert_before(cmark_node *node, cmark_node *sibling)
  353. {
  354. if (!S_can_contain(node->parent, sibling)) {
  355. return 0;
  356. }
  357. S_node_unlink(sibling);
  358. cmark_node *old_prev = node->prev;
  359. // Insert 'sibling' between 'old_prev' and 'node'.
  360. if (old_prev) {
  361. old_prev->next = sibling;
  362. }
  363. sibling->prev = old_prev;
  364. sibling->next = node;
  365. node->prev = sibling;
  366. // Set new parent.
  367. cmark_node *parent = node->parent;
  368. sibling->parent = parent;
  369. // Adjust first_child of parent if inserted as first child.
  370. if (parent && !old_prev) {
  371. parent->first_child = sibling;
  372. }
  373. return 1;
  374. }
  375. int
  376. cmark_node_insert_after(cmark_node *node, cmark_node *sibling)
  377. {
  378. if (!S_can_contain(node->parent, sibling)) {
  379. return 0;
  380. }
  381. S_node_unlink(sibling);
  382. cmark_node *old_next = node->next;
  383. // Insert 'sibling' between 'node' and 'old_next'.
  384. if (old_next) {
  385. old_next->prev = sibling;
  386. }
  387. sibling->next = old_next;
  388. sibling->prev = node;
  389. node->next = sibling;
  390. // Set new parent.
  391. cmark_node *parent = node->parent;
  392. sibling->parent = parent;
  393. // Adjust last_child of parent if inserted as last child.
  394. if (parent && !old_next) {
  395. parent->last_child = sibling;
  396. }
  397. return 1;
  398. }
  399. int
  400. cmark_node_prepend_child(cmark_node *node, cmark_node *child)
  401. {
  402. if (!S_can_contain(node, child)) {
  403. return 0;
  404. }
  405. S_node_unlink(child);
  406. cmark_node *old_first_child = node->first_child;
  407. child->next = old_first_child;
  408. child->prev = NULL;
  409. child->parent = node;
  410. node->first_child = child;
  411. if (old_first_child) {
  412. old_first_child->prev = child;
  413. }
  414. else {
  415. // Also set last_child if node previously had no children.
  416. node->last_child = child;
  417. }
  418. return 1;
  419. }
  420. int
  421. cmark_node_append_child(cmark_node *node, cmark_node *child)
  422. {
  423. if (!S_can_contain(node, child)) {
  424. return 0;
  425. }
  426. S_node_unlink(child);
  427. cmark_node *old_last_child = node->last_child;
  428. child->next = NULL;
  429. child->prev = old_last_child;
  430. child->parent = node;
  431. node->last_child = child;
  432. if (old_last_child) {
  433. old_last_child->next = child;
  434. }
  435. else {
  436. // Also set first_child if node previously had no children.
  437. node->first_child = child;
  438. }
  439. return 1;
  440. }
  441. static void
  442. S_print_error(cmark_node *node, const char *elem)
  443. {
  444. fprintf(stderr, "Invalid '%s' in node type %s at %d:%d\n", elem,
  445. S_type_string(node), node->start_line, node->start_column);
  446. }
  447. int
  448. cmark_node_check(cmark_node *node)
  449. {
  450. cmark_node *cur = node;
  451. int errors = 0;
  452. while (cur) {
  453. if (cur->first_child) {
  454. if (cur->first_child->parent != cur) {
  455. S_print_error(cur->first_child, "parent");
  456. cur->first_child->parent = cur;
  457. ++errors;
  458. }
  459. cur = cur->first_child;
  460. }
  461. else if (cur->next) {
  462. if (cur->next->prev != cur) {
  463. S_print_error(cur->next, "prev");
  464. cur->next->prev = cur;
  465. ++errors;
  466. }
  467. if (cur->next->parent != cur->parent) {
  468. S_print_error(cur->next, "parent");
  469. cur->next->parent = cur->parent;
  470. ++errors;
  471. }
  472. cur = cur->next;
  473. }
  474. else {
  475. if (cur->parent->last_child != cur) {
  476. S_print_error(cur->parent, "last_child");
  477. cur->parent->last_child = cur;
  478. ++errors;
  479. }
  480. cmark_node *ancestor = cur->parent;
  481. cur = NULL;
  482. while (ancestor != node->parent) {
  483. if (ancestor->next) {
  484. cur = ancestor->next;
  485. break;
  486. }
  487. ancestor = ancestor->parent;
  488. }
  489. }
  490. }
  491. return errors;
  492. }
  493. // Free a cmark_node list and any children.
  494. void cmark_free_nodes(cmark_node *e)
  495. {
  496. cmark_node *next;
  497. while (e != NULL) {
  498. strbuf_free(&e->string_content);
  499. switch (e->type){
  500. case NODE_FENCED_CODE:
  501. strbuf_free(&e->as.code.info);
  502. break;
  503. case NODE_STRING:
  504. case NODE_INLINE_HTML:
  505. case NODE_INLINE_CODE:
  506. cmark_chunk_free(&e->as.literal);
  507. break;
  508. case NODE_LINK:
  509. case NODE_IMAGE:
  510. free(e->as.link.url);
  511. free(e->as.link.title);
  512. break;
  513. default:
  514. break;
  515. }
  516. if (e->last_child) {
  517. // Splice children into list
  518. e->last_child->next = e->next;
  519. e->next = e->first_child;
  520. }
  521. next = e->next;
  522. free(e);
  523. e = next;
  524. }
  525. }