cmark

My personal build of CMark ✏️

node.c (17416B)

  1 #include <stdlib.h>
  2 #include <string.h>
  3 
  4 #include "config.h"
  5 #include "node.h"
  6 
  7 static void S_node_unlink(cmark_node *node);
  8 
  9 static CMARK_INLINE bool S_is_block(cmark_node *node) {
 10   if (node == NULL) {
 11     return false;
 12   }
 13   return node->type >= CMARK_NODE_FIRST_BLOCK &&
 14          node->type <= CMARK_NODE_LAST_BLOCK;
 15 }
 16 
 17 static CMARK_INLINE bool S_is_inline(cmark_node *node) {
 18   if (node == NULL) {
 19     return false;
 20   }
 21   return node->type >= CMARK_NODE_FIRST_INLINE &&
 22          node->type <= CMARK_NODE_LAST_INLINE;
 23 }
 24 
 25 static bool S_can_contain(cmark_node *node, cmark_node *child) {
 26   if (node == NULL || child == NULL || node == child) {
 27     return false;
 28   }
 29 
 30   // Verify that child is not an ancestor of node.
 31   if (child->first_child != NULL) {
 32     cmark_node *cur = node->parent;
 33 
 34     while (cur != NULL) {
 35       if (cur == child) {
 36         return false;
 37       }
 38       cur = cur->parent;
 39     }
 40   }
 41 
 42   if (child->type == CMARK_NODE_DOCUMENT) {
 43     return false;
 44   }
 45 
 46   switch (node->type) {
 47   case CMARK_NODE_DOCUMENT:
 48   case CMARK_NODE_BLOCK_QUOTE:
 49   case CMARK_NODE_ITEM:
 50     return S_is_block(child) && child->type != CMARK_NODE_ITEM;
 51 
 52   case CMARK_NODE_LIST:
 53     return child->type == CMARK_NODE_ITEM;
 54 
 55   case CMARK_NODE_CUSTOM_BLOCK:
 56     return true;
 57 
 58   case CMARK_NODE_PARAGRAPH:
 59   case CMARK_NODE_HEADING:
 60   case CMARK_NODE_EMPH:
 61   case CMARK_NODE_STRONG:
 62   case CMARK_NODE_LINK:
 63   case CMARK_NODE_IMAGE:
 64   case CMARK_NODE_CUSTOM_INLINE:
 65     return S_is_inline(child);
 66 
 67   default:
 68     break;
 69   }
 70 
 71   return false;
 72 }
 73 
 74 cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) {
 75   cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node));
 76   node->mem = mem;
 77   node->type = (uint16_t)type;
 78 
 79   switch (node->type) {
 80   case CMARK_NODE_HEADING:
 81     node->as.heading.level = 1;
 82     break;
 83 
 84   case CMARK_NODE_LIST: {
 85     cmark_list *list = &node->as.list;
 86     list->list_type = CMARK_BULLET_LIST;
 87     list->start = 0;
 88     list->tight = false;
 89     break;
 90   }
 91 
 92   default:
 93     break;
 94   }
 95 
 96   return node;
 97 }
 98 
 99 cmark_node *cmark_node_new(cmark_node_type type) {
100   extern cmark_mem DEFAULT_MEM_ALLOCATOR;
101   return cmark_node_new_with_mem(type, &DEFAULT_MEM_ALLOCATOR);
102 }
103 
104 // Free a cmark_node list and any children.
105 static void S_free_nodes(cmark_node *e) {
106   cmark_mem *mem = e->mem;
107   cmark_node *next;
108   while (e != NULL) {
109     switch (e->type) {
110     case CMARK_NODE_CODE_BLOCK:
111       mem->free(e->data);
112       mem->free(e->as.code.info);
113       break;
114     case CMARK_NODE_TEXT:
115     case CMARK_NODE_HTML_INLINE:
116     case CMARK_NODE_CODE:
117     case CMARK_NODE_HTML_BLOCK:
118       mem->free(e->data);
119       break;
120     case CMARK_NODE_LINK:
121     case CMARK_NODE_IMAGE:
122       mem->free(e->as.link.url);
123       mem->free(e->as.link.title);
124       break;
125     case CMARK_NODE_CUSTOM_BLOCK:
126     case CMARK_NODE_CUSTOM_INLINE:
127       mem->free(e->as.custom.on_enter);
128       mem->free(e->as.custom.on_exit);
129       break;
130     default:
131       break;
132     }
133     if (e->last_child) {
134       // Splice children into list
135       e->last_child->next = e->next;
136       e->next = e->first_child;
137     }
138     next = e->next;
139     mem->free(e);
140     e = next;
141   }
142 }
143 
144 void cmark_node_free(cmark_node *node) {
145   S_node_unlink(node);
146   node->next = NULL;
147   S_free_nodes(node);
148 }
149 
150 cmark_node_type cmark_node_get_type(cmark_node *node) {
151   if (node == NULL) {
152     return CMARK_NODE_NONE;
153   } else {
154     return (cmark_node_type)node->type;
155   }
156 }
157 
158 const char *cmark_node_get_type_string(cmark_node *node) {
159   if (node == NULL) {
160     return "NONE";
161   }
162 
163   switch (node->type) {
164   case CMARK_NODE_NONE:
165     return "none";
166   case CMARK_NODE_DOCUMENT:
167     return "document";
168   case CMARK_NODE_BLOCK_QUOTE:
169     return "block_quote";
170   case CMARK_NODE_LIST:
171     return "list";
172   case CMARK_NODE_ITEM:
173     return "item";
174   case CMARK_NODE_CODE_BLOCK:
175     return "code_block";
176   case CMARK_NODE_HTML_BLOCK:
177     return "html_block";
178   case CMARK_NODE_CUSTOM_BLOCK:
179     return "custom_block";
180   case CMARK_NODE_PARAGRAPH:
181     return "paragraph";
182   case CMARK_NODE_HEADING:
183     return "heading";
184   case CMARK_NODE_THEMATIC_BREAK:
185     return "thematic_break";
186   case CMARK_NODE_TEXT:
187     return "text";
188   case CMARK_NODE_SOFTBREAK:
189     return "softbreak";
190   case CMARK_NODE_LINEBREAK:
191     return "linebreak";
192   case CMARK_NODE_CODE:
193     return "code";
194   case CMARK_NODE_HTML_INLINE:
195     return "html_inline";
196   case CMARK_NODE_CUSTOM_INLINE:
197     return "custom_inline";
198   case CMARK_NODE_EMPH:
199     return "emph";
200   case CMARK_NODE_STRONG:
201     return "strong";
202   case CMARK_NODE_LINK:
203     return "link";
204   case CMARK_NODE_IMAGE:
205     return "image";
206   }
207 
208   return "<unknown>";
209 }
210 
211 cmark_node *cmark_node_next(cmark_node *node) {
212   if (node == NULL) {
213     return NULL;
214   } else {
215     return node->next;
216   }
217 }
218 
219 cmark_node *cmark_node_previous(cmark_node *node) {
220   if (node == NULL) {
221     return NULL;
222   } else {
223     return node->prev;
224   }
225 }
226 
227 cmark_node *cmark_node_parent(cmark_node *node) {
228   if (node == NULL) {
229     return NULL;
230   } else {
231     return node->parent;
232   }
233 }
234 
235 cmark_node *cmark_node_first_child(cmark_node *node) {
236   if (node == NULL) {
237     return NULL;
238   } else {
239     return node->first_child;
240   }
241 }
242 
243 cmark_node *cmark_node_last_child(cmark_node *node) {
244   if (node == NULL) {
245     return NULL;
246   } else {
247     return node->last_child;
248   }
249 }
250 
251 static bufsize_t cmark_set_cstr(cmark_mem *mem, unsigned char **dst,
252                                 const char *src) {
253   unsigned char *old = *dst;
254   bufsize_t len;
255 
256   if (src && src[0]) {
257       len = (bufsize_t)strlen(src);
258       *dst = (unsigned char *)mem->realloc(NULL, len + 1);
259       memcpy(*dst, src, len + 1);
260   } else {
261       len = 0;
262       *dst = NULL;
263   }
264   if (old) {
265     mem->free(old);
266   }
267 
268   return len;
269 }
270 
271 void *cmark_node_get_user_data(cmark_node *node) {
272   if (node == NULL) {
273     return NULL;
274   } else {
275     return node->user_data;
276   }
277 }
278 
279 int cmark_node_set_user_data(cmark_node *node, void *user_data) {
280   if (node == NULL) {
281     return 0;
282   }
283   node->user_data = user_data;
284   return 1;
285 }
286 
287 const char *cmark_node_get_literal(cmark_node *node) {
288   if (node == NULL) {
289     return NULL;
290   }
291 
292   switch (node->type) {
293   case CMARK_NODE_HTML_BLOCK:
294   case CMARK_NODE_TEXT:
295   case CMARK_NODE_HTML_INLINE:
296   case CMARK_NODE_CODE:
297   case CMARK_NODE_CODE_BLOCK:
298     return node->data ? (char *)node->data : "";
299 
300   default:
301     break;
302   }
303 
304   return NULL;
305 }
306 
307 int cmark_node_set_literal(cmark_node *node, const char *content) {
308   if (node == NULL) {
309     return 0;
310   }
311 
312   switch (node->type) {
313   case CMARK_NODE_HTML_BLOCK:
314   case CMARK_NODE_TEXT:
315   case CMARK_NODE_HTML_INLINE:
316   case CMARK_NODE_CODE:
317   case CMARK_NODE_CODE_BLOCK:
318     node->len = cmark_set_cstr(node->mem, &node->data, content);
319     return 1;
320 
321   default:
322     break;
323   }
324 
325   return 0;
326 }
327 
328 int cmark_node_get_heading_level(cmark_node *node) {
329   if (node == NULL) {
330     return 0;
331   }
332 
333   switch (node->type) {
334   case CMARK_NODE_HEADING:
335     return node->as.heading.level;
336 
337   default:
338     break;
339   }
340 
341   return 0;
342 }
343 
344 int cmark_node_set_heading_level(cmark_node *node, int level) {
345   if (node == NULL || level < 1 || level > 6) {
346     return 0;
347   }
348 
349   switch (node->type) {
350   case CMARK_NODE_HEADING:
351     node->as.heading.level = level;
352     return 1;
353 
354   default:
355     break;
356   }
357 
358   return 0;
359 }
360 
361 cmark_list_type cmark_node_get_list_type(cmark_node *node) {
362   if (node == NULL) {
363     return CMARK_NO_LIST;
364   }
365 
366   if (node->type == CMARK_NODE_LIST) {
367     return (cmark_list_type)node->as.list.list_type;
368   } else {
369     return CMARK_NO_LIST;
370   }
371 }
372 
373 int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) {
374   if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) {
375     return 0;
376   }
377 
378   if (node == NULL) {
379     return 0;
380   }
381 
382   if (node->type == CMARK_NODE_LIST) {
383     node->as.list.list_type = (unsigned char)type;
384     return 1;
385   } else {
386     return 0;
387   }
388 }
389 
390 cmark_delim_type cmark_node_get_list_delim(cmark_node *node) {
391   if (node == NULL) {
392     return CMARK_NO_DELIM;
393   }
394 
395   if (node->type == CMARK_NODE_LIST) {
396     return (cmark_delim_type)node->as.list.delimiter;
397   } else {
398     return CMARK_NO_DELIM;
399   }
400 }
401 
402 int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) {
403   if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) {
404     return 0;
405   }
406 
407   if (node == NULL) {
408     return 0;
409   }
410 
411   if (node->type == CMARK_NODE_LIST) {
412     node->as.list.delimiter = (unsigned char)delim;
413     return 1;
414   } else {
415     return 0;
416   }
417 }
418 
419 int cmark_node_get_list_start(cmark_node *node) {
420   if (node == NULL) {
421     return 0;
422   }
423 
424   if (node->type == CMARK_NODE_LIST) {
425     return node->as.list.start;
426   } else {
427     return 0;
428   }
429 }
430 
431 int cmark_node_set_list_start(cmark_node *node, int start) {
432   if (node == NULL || start < 0) {
433     return 0;
434   }
435 
436   if (node->type == CMARK_NODE_LIST) {
437     node->as.list.start = start;
438     return 1;
439   } else {
440     return 0;
441   }
442 }
443 
444 int cmark_node_get_list_tight(cmark_node *node) {
445   if (node == NULL) {
446     return 0;
447   }
448 
449   if (node->type == CMARK_NODE_LIST) {
450     return node->as.list.tight;
451   } else {
452     return 0;
453   }
454 }
455 
456 int cmark_node_set_list_tight(cmark_node *node, int tight) {
457   if (node == NULL) {
458     return 0;
459   }
460 
461   if (node->type == CMARK_NODE_LIST) {
462     node->as.list.tight = tight == 1;
463     return 1;
464   } else {
465     return 0;
466   }
467 }
468 
469 const char *cmark_node_get_fence_info(cmark_node *node) {
470   if (node == NULL) {
471     return NULL;
472   }
473 
474   if (node->type == CMARK_NODE_CODE_BLOCK) {
475     return node->as.code.info ? (char *)node->as.code.info : "";
476   } else {
477     return NULL;
478   }
479 }
480 
481 int cmark_node_set_fence_info(cmark_node *node, const char *info) {
482   if (node == NULL) {
483     return 0;
484   }
485 
486   if (node->type == CMARK_NODE_CODE_BLOCK) {
487     cmark_set_cstr(node->mem, &node->as.code.info, info);
488     return 1;
489   } else {
490     return 0;
491   }
492 }
493 
494 const char *cmark_node_get_url(cmark_node *node) {
495   if (node == NULL) {
496     return NULL;
497   }
498 
499   switch (node->type) {
500   case CMARK_NODE_LINK:
501   case CMARK_NODE_IMAGE:
502     return node->as.link.url ? (char *)node->as.link.url : "";
503   default:
504     break;
505   }
506 
507   return NULL;
508 }
509 
510 int cmark_node_set_url(cmark_node *node, const char *url) {
511   if (node == NULL) {
512     return 0;
513   }
514 
515   switch (node->type) {
516   case CMARK_NODE_LINK:
517   case CMARK_NODE_IMAGE:
518     cmark_set_cstr(node->mem, &node->as.link.url, url);
519     return 1;
520   default:
521     break;
522   }
523 
524   return 0;
525 }
526 
527 const char *cmark_node_get_title(cmark_node *node) {
528   if (node == NULL) {
529     return NULL;
530   }
531 
532   switch (node->type) {
533   case CMARK_NODE_LINK:
534   case CMARK_NODE_IMAGE:
535     return node->as.link.title ? (char *)node->as.link.title : "";
536   default:
537     break;
538   }
539 
540   return NULL;
541 }
542 
543 int cmark_node_set_title(cmark_node *node, const char *title) {
544   if (node == NULL) {
545     return 0;
546   }
547 
548   switch (node->type) {
549   case CMARK_NODE_LINK:
550   case CMARK_NODE_IMAGE:
551     cmark_set_cstr(node->mem, &node->as.link.title, title);
552     return 1;
553   default:
554     break;
555   }
556 
557   return 0;
558 }
559 
560 const char *cmark_node_get_on_enter(cmark_node *node) {
561   if (node == NULL) {
562     return NULL;
563   }
564 
565   switch (node->type) {
566   case CMARK_NODE_CUSTOM_INLINE:
567   case CMARK_NODE_CUSTOM_BLOCK:
568     return node->as.custom.on_enter ? (char *)node->as.custom.on_enter : "";
569   default:
570     break;
571   }
572 
573   return NULL;
574 }
575 
576 int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) {
577   if (node == NULL) {
578     return 0;
579   }
580 
581   switch (node->type) {
582   case CMARK_NODE_CUSTOM_INLINE:
583   case CMARK_NODE_CUSTOM_BLOCK:
584     cmark_set_cstr(node->mem, &node->as.custom.on_enter, on_enter);
585     return 1;
586   default:
587     break;
588   }
589 
590   return 0;
591 }
592 
593 const char *cmark_node_get_on_exit(cmark_node *node) {
594   if (node == NULL) {
595     return NULL;
596   }
597 
598   switch (node->type) {
599   case CMARK_NODE_CUSTOM_INLINE:
600   case CMARK_NODE_CUSTOM_BLOCK:
601     return node->as.custom.on_exit ? (char *)node->as.custom.on_exit : "";
602   default:
603     break;
604   }
605 
606   return NULL;
607 }
608 
609 int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) {
610   if (node == NULL) {
611     return 0;
612   }
613 
614   switch (node->type) {
615   case CMARK_NODE_CUSTOM_INLINE:
616   case CMARK_NODE_CUSTOM_BLOCK:
617     cmark_set_cstr(node->mem, &node->as.custom.on_exit, on_exit);
618     return 1;
619   default:
620     break;
621   }
622 
623   return 0;
624 }
625 
626 int cmark_node_get_start_line(cmark_node *node) {
627   if (node == NULL) {
628     return 0;
629   }
630   return node->start_line;
631 }
632 
633 int cmark_node_get_start_column(cmark_node *node) {
634   if (node == NULL) {
635     return 0;
636   }
637   return node->start_column;
638 }
639 
640 int cmark_node_get_end_line(cmark_node *node) {
641   if (node == NULL) {
642     return 0;
643   }
644   return node->end_line;
645 }
646 
647 int cmark_node_get_end_column(cmark_node *node) {
648   if (node == NULL) {
649     return 0;
650   }
651   return node->end_column;
652 }
653 
654 // Unlink a node without adjusting its next, prev, and parent pointers.
655 static void S_node_unlink(cmark_node *node) {
656   if (node == NULL) {
657     return;
658   }
659 
660   if (node->prev) {
661     node->prev->next = node->next;
662   }
663   if (node->next) {
664     node->next->prev = node->prev;
665   }
666 
667   // Adjust first_child and last_child of parent.
668   cmark_node *parent = node->parent;
669   if (parent) {
670     if (parent->first_child == node) {
671       parent->first_child = node->next;
672     }
673     if (parent->last_child == node) {
674       parent->last_child = node->prev;
675     }
676   }
677 }
678 
679 void cmark_node_unlink(cmark_node *node) {
680   S_node_unlink(node);
681 
682   node->next = NULL;
683   node->prev = NULL;
684   node->parent = NULL;
685 }
686 
687 int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) {
688   if (node == NULL || sibling == NULL) {
689     return 0;
690   }
691 
692   if (!node->parent || !S_can_contain(node->parent, sibling)) {
693     return 0;
694   }
695 
696   S_node_unlink(sibling);
697 
698   cmark_node *old_prev = node->prev;
699 
700   // Insert 'sibling' between 'old_prev' and 'node'.
701   if (old_prev) {
702     old_prev->next = sibling;
703   }
704   sibling->prev = old_prev;
705   sibling->next = node;
706   node->prev = sibling;
707 
708   // Set new parent.
709   cmark_node *parent = node->parent;
710   sibling->parent = parent;
711 
712   // Adjust first_child of parent if inserted as first child.
713   if (parent && !old_prev) {
714     parent->first_child = sibling;
715   }
716 
717   return 1;
718 }
719 
720 int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) {
721   if (node == NULL || sibling == NULL) {
722     return 0;
723   }
724 
725   if (!node->parent || !S_can_contain(node->parent, sibling)) {
726     return 0;
727   }
728 
729   S_node_unlink(sibling);
730 
731   cmark_node *old_next = node->next;
732 
733   // Insert 'sibling' between 'node' and 'old_next'.
734   if (old_next) {
735     old_next->prev = sibling;
736   }
737   sibling->next = old_next;
738   sibling->prev = node;
739   node->next = sibling;
740 
741   // Set new parent.
742   cmark_node *parent = node->parent;
743   sibling->parent = parent;
744 
745   // Adjust last_child of parent if inserted as last child.
746   if (parent && !old_next) {
747     parent->last_child = sibling;
748   }
749 
750   return 1;
751 }
752 
753 int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode) {
754   if (!cmark_node_insert_before(oldnode, newnode)) {
755     return 0;
756   }
757   cmark_node_unlink(oldnode);
758   return 1;
759 }
760 
761 int cmark_node_prepend_child(cmark_node *node, cmark_node *child) {
762   if (!S_can_contain(node, child)) {
763     return 0;
764   }
765 
766   S_node_unlink(child);
767 
768   cmark_node *old_first_child = node->first_child;
769 
770   child->next = old_first_child;
771   child->prev = NULL;
772   child->parent = node;
773   node->first_child = child;
774 
775   if (old_first_child) {
776     old_first_child->prev = child;
777   } else {
778     // Also set last_child if node previously had no children.
779     node->last_child = child;
780   }
781 
782   return 1;
783 }
784 
785 int cmark_node_append_child(cmark_node *node, cmark_node *child) {
786   if (!S_can_contain(node, child)) {
787     return 0;
788   }
789 
790   S_node_unlink(child);
791 
792   cmark_node *old_last_child = node->last_child;
793 
794   child->next = NULL;
795   child->prev = old_last_child;
796   child->parent = node;
797   node->last_child = child;
798 
799   if (old_last_child) {
800     old_last_child->next = child;
801   } else {
802     // Also set first_child if node previously had no children.
803     node->first_child = child;
804   }
805 
806   return 1;
807 }
808 
809 static void S_print_error(FILE *out, cmark_node *node, const char *elem) {
810   if (out == NULL) {
811     return;
812   }
813   fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem,
814           cmark_node_get_type_string(node), node->start_line,
815           node->start_column);
816 }
817 
818 int cmark_node_check(cmark_node *node, FILE *out) {
819   cmark_node *cur;
820   int errors = 0;
821 
822   if (!node) {
823     return 0;
824   }
825 
826   cur = node;
827   for (;;) {
828     if (cur->first_child) {
829       if (cur->first_child->prev != NULL) {
830         S_print_error(out, cur->first_child, "prev");
831         cur->first_child->prev = NULL;
832         ++errors;
833       }
834       if (cur->first_child->parent != cur) {
835         S_print_error(out, cur->first_child, "parent");
836         cur->first_child->parent = cur;
837         ++errors;
838       }
839       cur = cur->first_child;
840       continue;
841     }
842 
843   next_sibling:
844     if (cur == node) {
845       break;
846     }
847     if (cur->next) {
848       if (cur->next->prev != cur) {
849         S_print_error(out, cur->next, "prev");
850         cur->next->prev = cur;
851         ++errors;
852       }
853       if (cur->next->parent != cur->parent) {
854         S_print_error(out, cur->next, "parent");
855         cur->next->parent = cur->parent;
856         ++errors;
857       }
858       cur = cur->next;
859       continue;
860     }
861 
862     if (cur->parent->last_child != cur) {
863       S_print_error(out, cur->parent, "last_child");
864       cur->parent->last_child = cur;
865       ++errors;
866     }
867     cur = cur->parent;
868     goto next_sibling;
869   }
870 
871   return errors;
872 }