github_flavoured.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * github_flavoured -- implement the obnoxious "returns are hard newlines"
  3. * feature in github flavoured markdown.
  4. *
  5. * Copyright (C) 2012 David L Parsons.
  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. /* build a Document from any old input.
  17. */
  18. typedef int (*getc_func)(void*);
  19. Document *
  20. gfm_populate(getc_func getc, void* ctx, mkd_flag_t *flags)
  21. {
  22. Cstring line;
  23. Document *a = __mkd_new_Document();
  24. int c;
  25. int pandoc = 0;
  26. if ( !a ) return 0;
  27. a->tabstop = is_flag_set(flags, MKD_TABSTOP) ? 4 : TABSTOP;
  28. CREATE(line);
  29. while ( (c = (*getc)(ctx)) != EOF ) {
  30. if ( c == '\n' ) {
  31. if ( pandoc != EOF && pandoc < 3 ) {
  32. if ( S(line) && (T(line)[0] == '%') )
  33. pandoc++;
  34. else
  35. pandoc = EOF;
  36. }
  37. if (pandoc == EOF) {
  38. EXPAND(line) = ' ';
  39. EXPAND(line) = ' ';
  40. }
  41. __mkd_enqueue(a, &line);
  42. S(line) = 0;
  43. }
  44. else if ( isprint(c) || isspace(c) || (c & 0x80) )
  45. EXPAND(line) = c;
  46. }
  47. if ( S(line) )
  48. __mkd_enqueue(a, &line);
  49. DELETE(line);
  50. if ( (pandoc == 3) && !is_flag_set(flags, MKD_NOHEADER) ) {
  51. /* the first three lines started with %, so we have a header.
  52. * clip the first three lines out of content and hang them
  53. * off header.
  54. */
  55. Line *headers = T(a->content);
  56. a->title = headers; __mkd_trim_line(a->title, 1);
  57. a->author= headers->next; __mkd_trim_line(a->author, 1);
  58. a->date = headers->next->next; __mkd_trim_line(a->date, 1);
  59. T(a->content) = headers->next->next->next;
  60. }
  61. return a;
  62. }
  63. /* convert a block of text into a linked list
  64. */
  65. Document *
  66. gfm_string(const char *buf, int len, mkd_flag_t* flags)
  67. {
  68. struct string_stream about;
  69. about.data = buf;
  70. about.size = len;
  71. return gfm_populate((getc_func)__mkd_io_strget, &about, flags);
  72. }
  73. /* convert a file into a linked list
  74. */
  75. Document *
  76. gfm_in(FILE *f, mkd_flag_t* flags)
  77. {
  78. return gfm_populate((getc_func)fgetc, f, flags);
  79. }