mkd2html.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * mkd2html: parse a markdown input file and generate a web page.
  3. *
  4. * usage: mkd2html [options] filename
  5. * or mkd2html [options] < markdown > html
  6. *
  7. * options
  8. * -css css-file
  9. * -header line-to-add-to-<HEADER>
  10. * -footer line-to-add-before-</BODY>
  11. *
  12. * example:
  13. *
  14. * mkd2html -css /~orc/pages.css syntax
  15. * ( read syntax OR syntax.text, write syntax.html )
  16. */
  17. /*
  18. * Copyright (C) 2007 David L Parsons.
  19. * The redistribution terms are provided in the COPYRIGHT file that must
  20. * be distributed with this source code.
  21. */
  22. #include "config.h"
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #ifdef HAVE_BASENAME
  27. # ifdef HAVE_LIBGEN_H
  28. # include <libgen.h>
  29. # else
  30. # include <unistd.h>
  31. # endif
  32. #endif
  33. #include <stdarg.h>
  34. #include "mkdio.h"
  35. #include "cstring.h"
  36. #include "amalloc.h"
  37. #include "gethopt.h"
  38. char *pgm = "mkd2html";
  39. extern int notspecial(char *filename);
  40. #ifndef HAVE_BASENAME
  41. char *
  42. basename(char *path)
  43. {
  44. char *p;
  45. if ( p = strrchr(path, '/') )
  46. return 1+p;
  47. return path;
  48. }
  49. #endif
  50. void
  51. fail(char *why, ...)
  52. {
  53. va_list ptr;
  54. va_start(ptr,why);
  55. fprintf(stderr, "%s: ", pgm);
  56. vfprintf(stderr, why, ptr);
  57. fputc('\n', stderr);
  58. va_end(ptr);
  59. exit(1);
  60. }
  61. enum { GFM, ADD_CSS, ADD_HEADER, ADD_FOOTER };
  62. struct h_opt opts[] = {
  63. { GFM, "gfm",'G', 0, "Github style markdown" },
  64. { ADD_CSS, "css", 0, "url", "Additional css for this page" },
  65. { ADD_HEADER, "header", 0, "header", "Additional headers for this page" },
  66. { ADD_FOOTER, "footer", 0, "footer", "Additional footers for this page" },
  67. };
  68. #define NROPTS (sizeof opts/sizeof opts[0])
  69. #if USE_H1TITLE
  70. extern char* mkd_h1_title(MMIOT *);
  71. #endif
  72. int
  73. main(argc, argv)
  74. char **argv;
  75. {
  76. char *h;
  77. char *source = 0, *dest = 0;
  78. MMIOT *mmiot;
  79. int i;
  80. int gfm = 0;
  81. FILE *input, *output;
  82. STRING(char*) css, headers, footers;
  83. struct h_opt *res;
  84. struct h_context flags;
  85. CREATE(css);
  86. CREATE(headers);
  87. CREATE(footers);
  88. pgm = basename(argv[0]);
  89. hoptset(&flags, argc, argv);
  90. hopterr(&flags, 1);
  91. while ( res = gethopt(&flags, opts, NROPTS) ) {
  92. if ( res == HOPTERR ) {
  93. hoptusage(pgm, opts, NROPTS, "source [dest]");
  94. exit(1);
  95. }
  96. switch ( res->option ) {
  97. case ADD_CSS:
  98. EXPAND(css) = hoptarg(&flags);
  99. break;
  100. case ADD_HEADER:
  101. EXPAND(headers) = hoptarg(&flags);
  102. break;
  103. case ADD_FOOTER:
  104. EXPAND(footers) = hoptarg(&flags);
  105. break;
  106. case GFM:
  107. gfm = 1;
  108. break;
  109. default:
  110. fprintf(stderr, "unknown option?\n");
  111. break;
  112. }
  113. }
  114. argc -= hoptind(&flags);
  115. argv += hoptind(&flags);
  116. switch ( argc ) {
  117. char *p, *dot;
  118. case 0:
  119. input = stdin;
  120. output = stdout;
  121. break;
  122. case 1:
  123. case 2:
  124. dest = malloc(strlen(argv[argc-1]) + 6);
  125. source = malloc(strlen(argv[0]) + 6);
  126. if ( !(source && dest) )
  127. fail("out of memory allocating name buffers");
  128. strcpy(source, argv[0]);
  129. strcpy(dest, argv[argc-1]);
  130. if (( p = strrchr(source, '/') ))
  131. p = source;
  132. else
  133. ++p;
  134. if ( (input = fopen(source, "r")) == 0 ) {
  135. strcat(source, ".text");
  136. if ( (input = fopen(source, "r")) == 0 )
  137. fail("can't open either %s or %s", argv[0], source);
  138. }
  139. if ( notspecial(dest) ) {
  140. if (( dot = strrchr(dest, '.') ))
  141. *dot = 0;
  142. strcat(dest, ".html");
  143. }
  144. if ( (output = fopen(dest, "w")) == 0 )
  145. fail("can't write to %s", dest);
  146. break;
  147. default:
  148. hoptusage(pgm, opts, NROPTS, "source [dest]");
  149. exit(1);
  150. }
  151. mmiot = gfm ? gfm_in(input, 0) : mkd_in(input, 0);
  152. if ( mmiot == 0 )
  153. fail("can't read %s", source ? source : "stdin");
  154. if ( !mkd_compile(mmiot, 0) )
  155. fail("couldn't compile input");
  156. h = mkd_doc_title(mmiot);
  157. #if USE_H1TITLE
  158. if ( ! h )
  159. h = mkd_h1_title(mmiot);
  160. #endif
  161. /* print a header */
  162. fprintf(output,
  163. "<!doctype html public \"-//W3C//DTD HTML 4.0 Transitional //EN\">\n"
  164. "<html>\n"
  165. "<head>\n"
  166. " <meta name=\"GENERATOR\" content=\"mkd2html %s\">\n", markdown_version);
  167. fprintf(output," <meta http-equiv=\"Content-Type\""
  168. " content=\"text/html; charset=utf-8\">\n");
  169. for ( i=0; i < S(css); i++ )
  170. fprintf(output, " <link rel=\"stylesheet\"\n"
  171. " type=\"text/css\"\n"
  172. " href=\"%s\" />\n", T(css)[i]);
  173. fprintf(output," <title>");
  174. if ( h )
  175. mkd_generateline(h, strlen(h), output, 0);
  176. /* xhtml requires a <title> in the header, even if it doesn't
  177. * contain anything
  178. */
  179. fprintf(output, "</title>\n");
  180. for ( i=0; i < S(headers); i++ )
  181. fprintf(output, " %s\n", T(headers)[i]);
  182. fprintf(output, "</head>\n"
  183. "<body>\n");
  184. /* print the compiled body */
  185. mkd_generatehtml(mmiot, output);
  186. for ( i=0; i < S(footers); i++ )
  187. fprintf(output, "%s\n", T(footers)[i]);
  188. fprintf(output, "</body>\n"
  189. "</html>\n");
  190. mkd_cleanup(mmiot);
  191. exit(0);
  192. }