Text::Markdown::Discount
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
2.6 KiB

  1. /*
  2. * toc -- spit out a table of contents based on header blocks
  3. *
  4. * Copyright (C) 2008 Jjgod Jiang, David L Parsons
  5. * portions Copyright (C) 2011 Stefano D'Angelo
  6. * The redistribution terms are provided in the COPYRIGHT file that must
  7. * be distributed with this source code.
  8. */
  9. #include "config.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13. #include "cstring.h"
  14. #include "markdown.h"
  15. #include "amalloc.h"
  16. /* write an header index
  17. */
  18. int
  19. mkd_toc(Document *p, char **doc)
  20. {
  21. Paragraph *tp, *srcp;
  22. int last_hnumber = 0;
  23. Cstring res;
  24. int size;
  25. int first = 1;
  26. if ( !(doc && p && p->ctx) ) return -1;
  27. *doc = 0;
  28. if ( ! (p->ctx->flags & MKD_TOC) ) return 0;
  29. CREATE(res);
  30. RESERVE(res, 100);
  31. for ( tp = p->code; tp ; tp = tp->next ) {
  32. if ( tp->typ == SOURCE ) {
  33. for ( srcp = tp->down; srcp; srcp = srcp->next ) {
  34. if ( srcp->typ == HDR && srcp->text ) {
  35. while ( last_hnumber > srcp->hnumber ) {
  36. if ( (last_hnumber - srcp->hnumber) > 1 )
  37. Csprintf(&res, "\n");
  38. Csprintf(&res, "</li>\n%*s</ul>\n%*s",
  39. last_hnumber-1, "", last_hnumber-1, "");
  40. --last_hnumber;
  41. }
  42. if ( last_hnumber == srcp->hnumber )
  43. Csprintf(&res, "</li>\n");
  44. else if ( (srcp->hnumber > last_hnumber) && !first )
  45. Csprintf(&res, "\n");
  46. while ( srcp->hnumber > last_hnumber ) {
  47. Csprintf(&res, "%*s<ul>\n", last_hnumber, "");
  48. if ( (srcp->hnumber - last_hnumber) > 1 )
  49. Csprintf(&res, "%*s<li>\n", last_hnumber+1, "");
  50. ++last_hnumber;
  51. }
  52. Csprintf(&res, "%*s<li><a href=\"#", srcp->hnumber, "");
  53. mkd_string_to_anchor(T(srcp->text->text),
  54. S(srcp->text->text),
  55. (mkd_sta_function_t)Csputc, &res,1);
  56. Csprintf(&res, "\">");
  57. mkd_string_to_anchor(T(srcp->text->text),
  58. S(srcp->text->text),
  59. (mkd_sta_function_t)Csputc, &res,0);
  60. Csprintf(&res, "</a>");
  61. first = 0;
  62. }
  63. }
  64. }
  65. }
  66. while ( last_hnumber > 0 ) {
  67. --last_hnumber;
  68. Csprintf(&res, "</li>\n%*s</ul>\n%*s",
  69. last_hnumber, "", last_hnumber, "");
  70. }
  71. if ( (size = S(res)) > 0 ) {
  72. EXPAND(res) = 0;
  73. /* HACK ALERT! HACK ALERT! HACK ALERT! */
  74. *doc = T(res); /* we know that a T(Cstring) is a character pointer
  75. * so we can simply pick it up and carry it away,
  76. * leaving the husk of the Ctring on the stack
  77. * END HACK ALERT
  78. */
  79. }
  80. else
  81. DELETE(res);
  82. return size;
  83. }
  84. /* write an header index
  85. */
  86. int
  87. mkd_generatetoc(Document *p, FILE *out)
  88. {
  89. char *buf = 0;
  90. int sz = mkd_toc(p, &buf);
  91. int ret = EOF;
  92. if ( sz > 0 )
  93. ret = fwrite(buf, 1, sz, out);
  94. if ( buf ) free(buf);
  95. return (ret == sz) ? ret : EOF;
  96. }