markdown/0000755000175100001440000000000013076075152012120 5ustar hornikusersmarkdown/inst/0000755000175100001440000000000013075742411013073 5ustar hornikusersmarkdown/inst/COPYING0000644000175100001440000004345312330062343014127 0ustar hornikusersThe markdown package is licensed to you under the GPLv2, the terms of which are included below. The markdown pacakge includes other open source software whose license terms can be found in the file NOTICE. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. markdown/inst/examples/0000755000175100001440000000000012515350542014707 5ustar hornikusersmarkdown/inst/examples/HTMLOptions.R0000644000175100001440000000365212515340370017156 0ustar hornikusers# HTML OPTIONS # The following examples are short, so we allways add the HTML option 'fragment_only' tOpt <- "fragment_only" # skip_html example mkd = 'Hello' cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html"))) # skip_style example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style"))) # skip_images example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images"))) # skip_links example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links"))) # safelink example cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt))) cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt, "safelink"))) # toc example mkd <- paste(c("# Header 1", "p1", "## Header 2", "p2"), collapse = "\n") cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "toc"))) # hard_wrap example cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt))) cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap"))) # use_xhtml example cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap"))) cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap", "use_xhtml"))) # escape example mkd = 'Hello' cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html"))) # overrides all 'skip_*' options cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", "escape"))) # smartypants example cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt))) cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, "smartypants"))) cat(smartypants(text = "1/2 (c)\n")) markdown/inst/examples/markdownExtensions.R0000644000175100001440000000434413075741515020747 0ustar hornikusers# The following examples are short, so we set the HTML option 'fragment_only' options(markdown.HTML.options = "fragment_only") # no_intra_emphasis example cat(markdownToHTML(text = "foo_bar_function", extensions = c())) cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis"))) # tables example (need 4 spaces at beginning of line here) cat(markdownToHTML(text = " First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ", extensions = c())) # but not here cat(markdownToHTML(text = " First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ", extensions = c("tables"))) # fenced_code example (need at least three leading ~ or `) fenced_block <- function(text, x = "`", n = 3) { fence <- paste(rep(x, n), collapse = "") paste(fence, text, fence, sep = "") } cat(markdownToHTML(text = fenced_block(" preformatted text here without having to indent first line. "), extensions = c())) cat(markdownToHTML(text = fenced_block(" preformatted text here without having to indent first line. "), extensions = c("fenced_code"))) # autolink example cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c())) cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c("autolink"))) # strikethrough example cat(markdownToHTML(text = "~~awesome~~", extensions = c())) cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough"))) # lax_spacing cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
_markdown_
extra text. ", extensions = c(""))) cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
_markdown_
extra text. ", extensions = c("lax_spacing"))) # space_headers example cat(markdownToHTML(text = "#A Header\neven though there is no space between # and A", extensions = c(""))) cat(markdownToHTML(text = "#Not A Header\nbecause there is no space between # and N", extensions = c("space_headers"))) # superscript example cat(markdownToHTML(text = "2^10", extensions = c())) cat(markdownToHTML(text = "2^10", extensions = c("superscript"))) markdown/inst/resources/0000755000175100001440000000000012452316244015104 5ustar hornikusersmarkdown/inst/resources/markdown.css0000644000175100001440000000332212364504110017431 0ustar hornikusersbody, td { font-family: sans-serif; background-color: white; font-size: 13px; } body { max-width: 800px; margin: auto; padding: 1em; line-height: 20px; } tt, code, pre { font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace; } h1 { font-size:2.2em; } h2 { font-size:1.8em; } h3 { font-size:1.4em; } h4 { font-size:1.0em; } h5 { font-size:0.9em; } h6 { font-size:0.8em; } a:visited { color: rgb(50%, 0%, 50%); } pre, img { max-width: 100%; } pre { overflow-x: auto; } pre code { display: block; padding: 0.5em; } code { font-size: 92%; border: 1px solid #ccc; } code[class] { background-color: #F8F8F8; } table, td, th { border: none; } blockquote { color:#666666; margin:0; padding-left: 1em; border-left: 0.5em #EEE solid; } hr { height: 0px; border-bottom: none; border-top-width: thin; border-top-style: dotted; border-top-color: #999999; } @media print { * { background: transparent !important; color: black !important; filter:none !important; -ms-filter: none !important; } body { font-size:12pt; max-width:100%; } a, a:visited { text-decoration: underline; } hr { visibility: hidden; page-break-before: always; } pre, blockquote { padding-right: 1em; page-break-inside: avoid; } tr, img { page-break-inside: avoid; } img { max-width: 100% !important; } @page :left { margin: 15mm 20mm 15mm 10mm; } @page :right { margin: 15mm 10mm 15mm 20mm; } p, h2, h3 { orphans: 3; widows: 3; } h2, h3 { page-break-after: avoid; } } markdown/inst/resources/markdown.html0000644000175100001440000000115712364515712017623 0ustar hornikusers #!title# #!r_highlight# #!mathjax# #!header# #!html_output# markdown/inst/resources/mathjax.html0000644000175100001440000000022313073475747017441 0ustar hornikusers markdown/inst/resources/r_highlight.html0000644000175100001440000002531012330062343020254 0ustar hornikusers markdown/inst/doc/0000755000175100001440000000000013075742411013640 5ustar hornikusersmarkdown/inst/doc/markdown-examples.Rmd0000644000175100001440000000133413075742411017743 0ustar hornikusers This vignette shows some examples for different Markdown extensions and HTML options. ```{r read-code, include=FALSE} library(knitr) opts_chunk$set(tidy = FALSE) # otherwise \n will cause problems read_chunk(system.file('examples', 'markdownExtensions.R', package = 'markdown'), labels = 'md-extensions') read_chunk(system.file('examples', 'HTMLOptions.R', package = 'markdown'), labels = 'html-options') ``` ```{r} library(markdown) ``` # Markdown Extensions ```{r md-extensions} ``` # HTML Options ```{r html-options} ``` ```{r include=FALSE} options(markdown.HTML.options=markdownHTMLOptions(defaults=TRUE)) ``` markdown/inst/doc/markdown-examples.html0000644000175100001440000006053113075742411020171 0ustar hornikusers Markdown Extensions

This vignette shows some examples for different Markdown extensions and HTML options.

library(markdown)

Markdown Extensions

# The following examples are short, so we set the HTML option 'fragment_only'

options(markdown.HTML.options = "fragment_only")

# no_intra_emphasis example
cat(markdownToHTML(text = "foo_bar_function", extensions = c()))
## <p>foo<em>bar</em>function</p>
cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis")))
## <p>foo_bar_function</p>
# tables example (need 4 spaces at beginning of line here)
cat(markdownToHTML(text = "
    First Header  | Second Header
    ------------- | -------------
    Content Cell  | Content Cell
    Content Cell  | Content Cell
", extensions = c()))
## <pre><code>First Header  | Second Header
## ------------- | -------------
## Content Cell  | Content Cell
## Content Cell  | Content Cell
## </code></pre>
# but not here
cat(markdownToHTML(text = "
First Header  | Second Header
------------- | -------------
Content Cell  | Content Cell
Content Cell  | Content Cell
", extensions = c("tables")))
## <table><thead>
## <tr>
## <th>First Header</th>
## <th>Second Header</th>
## </tr>
## </thead><tbody>
## <tr>
## <td>Content Cell</td>
## <td>Content Cell</td>
## </tr>
## <tr>
## <td>Content Cell</td>
## <td>Content Cell</td>
## </tr>
## </tbody></table>
# fenced_code example (need at least three leading ~ or `)
fenced_block <- function(text, x = "`", n = 3) {
  fence <- paste(rep(x, n), collapse = "")
  paste(fence, text, fence, sep = "")
}
cat(markdownToHTML(text = fenced_block("
preformatted text here without having to indent
first line.
"), extensions = c()))
## <p><code>
## preformatted text here without having to indent
## first line.
## </code></p>
cat(markdownToHTML(text = fenced_block("
preformatted text here without having to indent
first line.
"), extensions = c("fenced_code")))
## <pre><code>preformatted text here without having to indent
## first line.
## </code></pre>
# autolink example
cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c()))
## <p>https://www.r-project.org/</p>
cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c("autolink")))
## <p><a href="https://www.r-project.org/">https://www.r-project.org/</a></p>
# strikethrough example
cat(markdownToHTML(text = "~~awesome~~", extensions = c()))
## <p>~~awesome~~</p>
cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough")))
## <p><del>awesome</del></p>
# lax_spacing
cat(markdownToHTML(text = "
Embedding html without surrounding with empty newline.
<div>_markdown_</div>
extra text.
", extensions = c("")))
## <p>Embedding html without surrounding with empty newline.
## <div><em>markdown</em></div>
## extra text.</p>
cat(markdownToHTML(text = "
Embedding html without surrounding with empty newline.
<div>_markdown_</div>
extra text.
", extensions = c("lax_spacing")))
## <p>Embedding html without surrounding with empty newline.</p>
## 
## <div>_markdown_</div>
## 
## <p>extra text.</p>
# space_headers example
cat(markdownToHTML(text = "#A Header\neven though there is no space between # and A",
                   extensions = c("")))
## <h1>A Header</h1>
## 
## <p>even though there is no space between # and A</p>
cat(markdownToHTML(text = "#Not A Header\nbecause there is no space between # and N",
                   extensions = c("space_headers")))
## <p>#Not A Header
## because there is no space between # and N</p>
# superscript example
cat(markdownToHTML(text = "2^10", extensions = c()))
## <p>2^10</p>
cat(markdownToHTML(text = "2^10", extensions = c("superscript")))
## <p>2<sup>10</sup></p>

HTML Options

# HTML OPTIONS

# The following examples are short, so we allways add the HTML option 'fragment_only'
tOpt <- "fragment_only"

# skip_html example
mkd = '<style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a>'
cat(markdownToHTML(text = mkd, options = c(tOpt)))
## <p><style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a></p>
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))
## <p>Hello</p>
# skip_style example
cat(markdownToHTML(text = mkd, options = c(tOpt)))
## <p><style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a></p>
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style")))
## <p><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a></p>
# skip_images example
cat(markdownToHTML(text = mkd, options = c(tOpt)))
## <p><style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a></p>
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images")))
## <p><style></style><a href="#">Hello</a></p>
# skip_links example
cat(markdownToHTML(text = mkd, options = c(tOpt)))
## <p><style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a></p>
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links")))
## <p><style></style><img src="http://cran.rstudio.com/Rlogo.jpg">Hello</p>
# safelink example
cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt)))
## <p><a href="http://google.com" title="baz">foo</a></p>
cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt, "safelink")))
## <p><a href="http://google.com" title="baz">foo</a></p>
# toc example
mkd <- paste(c("# Header 1", "p1", "## Header 2", "p2"), collapse = "\n")

cat(markdownToHTML(text = mkd, options = c(tOpt)))
## <h1>Header 1</h1>
## 
## <p>p1</p>
## 
## <h2>Header 2</h2>
## 
## <p>p2</p>
cat(markdownToHTML(text = mkd, options = c(tOpt, "toc")))
## <div id="toc">
## <div id="toc_header">Table of Contents</div>
## <ul>
## <li>
## <a href="#toc_0">Header 1</a>
## <ul>
## <li>
## <a href="#toc_1">Header 2</a>
## </li>
## </ul>
## </li>
## </ul>
## </div>
## 
## 
## <h1 id="toc_0">Header 1</h1>
## 
## <p>p1</p>
## 
## <h2 id="toc_1">Header 2</h2>
## 
## <p>p2</p>
# hard_wrap example
cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt)))
## <p>foo
## bar</p>
cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap")))
## <p>foo<br>
## bar</p>
# use_xhtml example
cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap")))
## <p>foo<br>
## bar</p>
cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap", "use_xhtml")))
## <p>foo<br/>
## bar</p>
# escape example
mkd = '<style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a>'
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))
## <p>Hello</p>
# overrides all 'skip_*' options
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", "escape")))
## <p>&lt;style&gt;&lt;/style&gt;&lt;img src=&quot;http://cran.rstudio.com/Rlogo.jpg&quot;&gt;&lt;a href=&quot;#&quot;&gt;Hello&lt;/a&gt;</p>
# smartypants example
cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt)))
## <p>1/2 (c)</p>
cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, "smartypants")))
## <p>&frac12; &copy;</p>
cat(smartypants(text = "1/2 (c)\n"))
## &frac12; &copy;
markdown/inst/doc/markdown-output.R0000644000175100001440000001216713075742411017152 0ustar hornikusers## ----read-code, include=FALSE-------------------------------------------- library(knitr) opts_chunk$set(tidy = FALSE) # otherwise \n will cause problems read_chunk(system.file('examples', 'markdownExtensions.R', package = 'markdown'), labels = 'md-extensions') read_chunk(system.file('examples', 'HTMLOptions.R', package = 'markdown'), labels = 'html-options') ## ------------------------------------------------------------------------ library(markdown) ## ----md-extensions------------------------------------------------------- # The following examples are short, so we set the HTML option 'fragment_only' options(markdown.HTML.options = "fragment_only") # no_intra_emphasis example cat(markdownToHTML(text = "foo_bar_function", extensions = c())) cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis"))) # tables example (need 4 spaces at beginning of line here) cat(markdownToHTML(text = " First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ", extensions = c())) # but not here cat(markdownToHTML(text = " First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ", extensions = c("tables"))) # fenced_code example (need at least three leading ~ or `) fenced_block <- function(text, x = "`", n = 3) { fence <- paste(rep(x, n), collapse = "") paste(fence, text, fence, sep = "") } cat(markdownToHTML(text = fenced_block(" preformatted text here without having to indent first line. "), extensions = c())) cat(markdownToHTML(text = fenced_block(" preformatted text here without having to indent first line. "), extensions = c("fenced_code"))) # autolink example cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c())) cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c("autolink"))) # strikethrough example cat(markdownToHTML(text = "~~awesome~~", extensions = c())) cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough"))) # lax_spacing cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
_markdown_
extra text. ", extensions = c(""))) cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
_markdown_
extra text. ", extensions = c("lax_spacing"))) # space_headers example cat(markdownToHTML(text = "#A Header\neven though there is no space between # and A", extensions = c(""))) cat(markdownToHTML(text = "#Not A Header\nbecause there is no space between # and N", extensions = c("space_headers"))) # superscript example cat(markdownToHTML(text = "2^10", extensions = c())) cat(markdownToHTML(text = "2^10", extensions = c("superscript"))) ## ----html-options-------------------------------------------------------- # HTML OPTIONS # The following examples are short, so we allways add the HTML option 'fragment_only' tOpt <- "fragment_only" # skip_html example mkd = 'Hello' cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html"))) # skip_style example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style"))) # skip_images example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images"))) # skip_links example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links"))) # safelink example cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt))) cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt, "safelink"))) # toc example mkd <- paste(c("# Header 1", "p1", "## Header 2", "p2"), collapse = "\n") cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "toc"))) # hard_wrap example cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt))) cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap"))) # use_xhtml example cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap"))) cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap", "use_xhtml"))) # escape example mkd = 'Hello' cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html"))) # overrides all 'skip_*' options cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", "escape"))) # smartypants example cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt))) cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, "smartypants"))) cat(smartypants(text = "1/2 (c)\n")) ## ----include=FALSE------------------------------------------------------- options(markdown.HTML.options=markdownHTMLOptions(defaults=TRUE)) ## ----read, include=FALSE------------------------------------------------- library(knitr) opts_chunk$set(results = 'asis') out = knit_child(text = scan('markdown-examples.Rmd', what = 'character', skip = 7, sep = '\n')) markdown/inst/doc/markdown-output.html0000644000175100001440000005357413075742411017724 0ustar hornikusers Markdown Extensions

This vignette shows how the output looks like in HTML from the other vignette markdown-examples.Rmd, in which the literal HTML code was shown.

library(markdown)

Markdown Extensions

# The following examples are short, so we set the HTML option 'fragment_only'

options(markdown.HTML.options = "fragment_only")

# no_intra_emphasis example
cat(markdownToHTML(text = "foo_bar_function", extensions = c()))

foobarfunction

cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis")))

foo_bar_function

# tables example (need 4 spaces at beginning of line here)
cat(markdownToHTML(text = "
    First Header  | Second Header
    ------------- | -------------
    Content Cell  | Content Cell
    Content Cell  | Content Cell
", extensions = c()))
First Header  | Second Header
------------- | -------------
Content Cell  | Content Cell
Content Cell  | Content Cell
# but not here
cat(markdownToHTML(text = "
First Header  | Second Header
------------- | -------------
Content Cell  | Content Cell
Content Cell  | Content Cell
", extensions = c("tables")))
First Header Second Header
Content Cell Content Cell
Content Cell Content Cell
# fenced_code example (need at least three leading ~ or `)
fenced_block <- function(text, x = "`", n = 3) {
  fence <- paste(rep(x, n), collapse = "")
  paste(fence, text, fence, sep = "")
}
cat(markdownToHTML(text = fenced_block("
preformatted text here without having to indent
first line.
"), extensions = c()))

preformatted text here without having to indent first line.

cat(markdownToHTML(text = fenced_block("
preformatted text here without having to indent
first line.
"), extensions = c("fenced_code")))
preformatted text here without having to indent
first line.
# autolink example
cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c()))

https://www.r-project.org/

cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c("autolink")))

https://www.r-project.org/

# strikethrough example
cat(markdownToHTML(text = "~~awesome~~", extensions = c()))

~~awesome~~

cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough")))

awesome

# lax_spacing
cat(markdownToHTML(text = "
Embedding html without surrounding with empty newline.
<div>_markdown_</div>
extra text.
", extensions = c("")))

Embedding html without surrounding with empty newline.

markdown
extra text.

cat(markdownToHTML(text = "
Embedding html without surrounding with empty newline.
<div>_markdown_</div>
extra text.
", extensions = c("lax_spacing")))

Embedding html without surrounding with empty newline.

_markdown_

extra text.

# space_headers example
cat(markdownToHTML(text = "#A Header\neven though there is no space between # and A",
                   extensions = c("")))

A Header

even though there is no space between # and A

cat(markdownToHTML(text = "#Not A Header\nbecause there is no space between # and N",
                   extensions = c("space_headers")))

#Not A Header because there is no space between # and N

# superscript example
cat(markdownToHTML(text = "2^10", extensions = c()))

2^10

cat(markdownToHTML(text = "2^10", extensions = c("superscript")))

210

HTML Options

# HTML OPTIONS

# The following examples are short, so we allways add the HTML option 'fragment_only'
tOpt <- "fragment_only"

# skip_html example
mkd = '<style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a>'
cat(markdownToHTML(text = mkd, options = c(tOpt)))

Hello

cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))

Hello

# skip_style example
cat(markdownToHTML(text = mkd, options = c(tOpt)))

Hello

cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style")))

Hello

# skip_images example
cat(markdownToHTML(text = mkd, options = c(tOpt)))

Hello

cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images")))

Hello

# skip_links example
cat(markdownToHTML(text = mkd, options = c(tOpt)))

Hello

cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links")))

Hello

# safelink example
cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt)))

foo

cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt, "safelink")))

foo

# toc example
mkd <- paste(c("# Header 1", "p1", "## Header 2", "p2"), collapse = "\n")

cat(markdownToHTML(text = mkd, options = c(tOpt)))

Header 1

p1

Header 2

p2

cat(markdownToHTML(text = mkd, options = c(tOpt, "toc")))
Table of Contents

Header 1

p1

Header 2

p2

# hard_wrap example
cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt)))

foo bar

cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap")))

foo
bar

# use_xhtml example
cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap")))

foo
bar

cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap", "use_xhtml")))

foo
bar

# escape example
mkd = '<style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a>'
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))

Hello

# overrides all 'skip_*' options
cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", "escape")))

<style></style><img src=“http://cran.rstudio.com/Rlogo.jpg”><a href=“#”>Hello</a>

# smartypants example
cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt)))

½ ©

cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, "smartypants")))

½ ©

cat(smartypants(text = "1/2 (c)\n"))

½ ©

markdown/inst/doc/markdown-examples.R0000644000175100001440000001163113075742411017423 0ustar hornikusers## ----read-code, include=FALSE-------------------------------------------- library(knitr) opts_chunk$set(tidy = FALSE) # otherwise \n will cause problems read_chunk(system.file('examples', 'markdownExtensions.R', package = 'markdown'), labels = 'md-extensions') read_chunk(system.file('examples', 'HTMLOptions.R', package = 'markdown'), labels = 'html-options') ## ------------------------------------------------------------------------ library(markdown) ## ----md-extensions------------------------------------------------------- # The following examples are short, so we set the HTML option 'fragment_only' options(markdown.HTML.options = "fragment_only") # no_intra_emphasis example cat(markdownToHTML(text = "foo_bar_function", extensions = c())) cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis"))) # tables example (need 4 spaces at beginning of line here) cat(markdownToHTML(text = " First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ", extensions = c())) # but not here cat(markdownToHTML(text = " First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ", extensions = c("tables"))) # fenced_code example (need at least three leading ~ or `) fenced_block <- function(text, x = "`", n = 3) { fence <- paste(rep(x, n), collapse = "") paste(fence, text, fence, sep = "") } cat(markdownToHTML(text = fenced_block(" preformatted text here without having to indent first line. "), extensions = c())) cat(markdownToHTML(text = fenced_block(" preformatted text here without having to indent first line. "), extensions = c("fenced_code"))) # autolink example cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c())) cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c("autolink"))) # strikethrough example cat(markdownToHTML(text = "~~awesome~~", extensions = c())) cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough"))) # lax_spacing cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
_markdown_
extra text. ", extensions = c(""))) cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
_markdown_
extra text. ", extensions = c("lax_spacing"))) # space_headers example cat(markdownToHTML(text = "#A Header\neven though there is no space between # and A", extensions = c(""))) cat(markdownToHTML(text = "#Not A Header\nbecause there is no space between # and N", extensions = c("space_headers"))) # superscript example cat(markdownToHTML(text = "2^10", extensions = c())) cat(markdownToHTML(text = "2^10", extensions = c("superscript"))) ## ----html-options-------------------------------------------------------- # HTML OPTIONS # The following examples are short, so we allways add the HTML option 'fragment_only' tOpt <- "fragment_only" # skip_html example mkd = 'Hello' cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html"))) # skip_style example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style"))) # skip_images example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images"))) # skip_links example cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links"))) # safelink example cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt))) cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt, "safelink"))) # toc example mkd <- paste(c("# Header 1", "p1", "## Header 2", "p2"), collapse = "\n") cat(markdownToHTML(text = mkd, options = c(tOpt))) cat(markdownToHTML(text = mkd, options = c(tOpt, "toc"))) # hard_wrap example cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt))) cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap"))) # use_xhtml example cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap"))) cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, "hard_wrap", "use_xhtml"))) # escape example mkd = 'Hello' cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html"))) # overrides all 'skip_*' options cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", "escape"))) # smartypants example cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt))) cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, "smartypants"))) cat(smartypants(text = "1/2 (c)\n")) ## ----include=FALSE------------------------------------------------------- options(markdown.HTML.options=markdownHTMLOptions(defaults=TRUE)) markdown/inst/doc/markdown-output.Rmd0000644000175100001440000000070513075742411017466 0ustar hornikusers This vignette shows how the output looks like in HTML from the other vignette `markdown-examples.Rmd`, in which the literal HTML code was shown. ```{r read, include=FALSE} library(knitr) opts_chunk$set(results = 'asis') out = knit_child(text = scan('markdown-examples.Rmd', what = 'character', skip = 7, sep = '\n')) ``` `r paste(out, collapse = '\n')` markdown/inst/NOTICE0000644000175100001440000000401312330062343013765 0ustar hornikusersThe markdown package includes a copy of the Sundown markdown library. The license for the Sundown library is as follows: Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- The markdown package also includes source code from http://base64.sourceforge.net/b64.c fetched on 2012-05-11. The license for b64.c is as follows: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. markdown/inst/include/0000755000175100001440000000000012452315315014513 5ustar hornikusersmarkdown/inst/include/markdown.h0000644000175100001440000001136512330062343016507 0ustar hornikusers/* markdown.h - generic markdown parser */ /* * Copyright (c) 2009, Natacha Porté * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef UPSKIRT_MARKDOWN_H #define UPSKIRT_MARKDOWN_H #include "buffer.h" #include "autolink.h" #ifdef __cplusplus extern "C" { #endif #define SUNDOWN_VERSION "1.16.0" #define SUNDOWN_VER_MAJOR 1 #define SUNDOWN_VER_MINOR 16 #define SUNDOWN_VER_REVISION 0 /******************** * TYPE DEFINITIONS * ********************/ /* mkd_autolink - type of autolink */ enum mkd_autolink { MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */ MKDA_EMAIL, /* e-mail link without explit mailto: */ }; enum mkd_tableflags { MKD_TABLE_ALIGN_L = 1, MKD_TABLE_ALIGN_R = 2, MKD_TABLE_ALIGN_CENTER = 3, MKD_TABLE_ALIGNMASK = 3, MKD_TABLE_HEADER = 4 }; enum mkd_extensions { MKDEXT_NO_INTRA_EMPHASIS = (1 << 0), MKDEXT_TABLES = (1 << 1), MKDEXT_FENCED_CODE = (1 << 2), MKDEXT_AUTOLINK = (1 << 3), MKDEXT_STRIKETHROUGH = (1 << 4), MKDEXT_SPACE_HEADERS = (1 << 6), MKDEXT_SUPERSCRIPT = (1 << 7), MKDEXT_LAX_SPACING = (1 << 8), }; /* sd_callbacks - functions for rendering parsed data */ struct sd_callbacks { /* block level callbacks - NULL skips the block */ void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque); void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque); void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque); void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque); void (*hrule)(struct buf *ob, void *opaque); void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque); void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque); void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque); void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque); void (*table_row)(struct buf *ob, const struct buf *text, void *opaque); void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque); /* span level callbacks - NULL or return 0 prints the span verbatim */ int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque); int (*codespan)(struct buf *ob, const struct buf *text, void *opaque); int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque); int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque); int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque); int (*linebreak)(struct buf *ob, void *opaque); int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque); int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque); int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque); int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque); int (*superscript)(struct buf *ob, const struct buf *text, void *opaque); /* low level callbacks - NULL copies input directly into the output */ void (*entity)(struct buf *ob, const struct buf *entity, void *opaque); void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque); /* header and footer */ void (*doc_header)(struct buf *ob, void *opaque); void (*doc_footer)(struct buf *ob, void *opaque); }; struct sd_markdown; /********* * FLAGS * *********/ /* list/listitem flags */ #define MKD_LIST_ORDERED 1 #define MKD_LI_BLOCK 2 /*
  • containing block data */ /********************** * EXPORTED FUNCTIONS * **********************/ extern struct sd_markdown * sd_markdown_new( unsigned int extensions, size_t max_nesting, const struct sd_callbacks *callbacks, void *opaque); extern void sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md); extern void sd_markdown_free(struct sd_markdown *md); extern void sd_version(int *major, int *minor, int *revision); #ifdef __cplusplus } #endif #endif /* vim: set filetype=c: */ markdown/inst/include/markdown_rstubs.h0000644000175100001440000000775012330062343020114 0ustar hornikusers/* * markdown_rstubs.h * * Copyright (C) 2009-2013 by RStudio, Inc. * * This program is licensed to you under the terms of version 2 of the * GNU General Public License. This program is distributed WITHOUT ANY * EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details. * */ #ifndef MARKDOWN_RSTUBS #define MARKDOWN_RSTUBS #include #include #include "markdown.h" #ifdef __cplusplus extern "C" { #endif /* bufgrow: increasing the allocated size to the given value */ int rstub_bufgrow(struct buf *, size_t); #define bufgrow rstub_bufgrow /* bufnew: allocation of a new buffer */ struct buf *rstub_bufnew(size_t) __attribute__ ((malloc)); #define bufnew rstub_bufnew /* bufnullterm: NUL-termination of the string array (making a C-string) */ const char *rstub_bufcstr(struct buf *); #define bufcstr rstub_bufcstr /* bufprefix: compare the beginning of a buffer with a string */ int rstub_bufprefix(const struct buf *buf, const char *prefix); #define bufprefix rstub_bufprefix /* bufput: appends raw data to a buffer */ void rstub_bufput(struct buf *, const void *, size_t); #define bufput rstub_bufput /* bufputs: appends a NUL-terminated string to a buffer */ void rstub_bufputs(struct buf *, const char *); #define bufputs rstub_bufputs /* bufputc: appends a single char to a buffer */ void rstub_bufputc(struct buf *, int); #define bufputc rstub_bufputc /* bufrelease: decrease the reference count and free the buffer if needed */ void rstub_bufrelease(struct buf *); #define bufrelease rstub_bufrelease /* bufreset: frees internal data of the buffer */ void rstub_bufreset(struct buf *); #define bufreset rstub_bufreset /* bufslurp: removes a given number of bytes from the head of the array */ void rstub_bufslurp(struct buf *, size_t); #define bufslurp rstub_bufslurp /* bufprintf: formatted printing to a buffer */ void rstub_bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); #define bufprintf rstub_bufprintf extern int rstub_sd_autolink_issafe(const uint8_t *link, size_t link_len); #define sd_autolink_issafe rstub_sd_autolink_issafe extern size_t rstub_sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); #define sd_autolink__www rstub_sd_autolink__www extern size_t rstub_sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); #define sd_autolink__email rstub_sd_autolink__email extern size_t rstub_sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); #define sd_autolink__url rstub_sd_autolink__url extern struct sd_markdown * rstub_sd_markdown_new( unsigned int extensions, size_t max_nesting, const struct sd_callbacks *callbacks, void *opaque); #define sd_markdown_new rstub_sd_markdown_new extern void rstub_sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md); #define sd_markdown_render rstub_sd_markdown_render extern void rstub_sd_markdown_free(struct sd_markdown *md); #define sd_markdown_free rstub_sd_markdown_free extern void rstub_sd_version(int *major, int *minor, int *revision); #define sd_version rstub_sd_version struct rmd_renderer { char *name; Rboolean (*render)(struct buf *,struct buf *, SEXP, SEXP); }; Rboolean rstub_rmd_register_renderer(struct rmd_renderer *); #define rmd_register_renderer rstub_rmd_register_renderer Rboolean rstub_rmd_renderer_exists(const char *); #define rmd_renderer_exists rstub_rmd_renderer_exists Rboolean rstub_rmd_buf_to_output(struct buf *, SEXP, SEXP *); #define rmd_buf_to_output rstub_rmd_buf_to_output Rboolean rstub_rmd_input_to_buf(SEXP, SEXP, struct buf *); #define rmd_input_to_buf rstub_rmd_input_to_buf #ifdef __cplusplus } #endif #endif // MARKDOWN_RSTUBS markdown/inst/include/markdown_rstubs.c0000644000175100001440000001711112330062343020077 0ustar hornikusers/* * markdown_rstubs.c * * Copyright (C) 2009-2013 by RStudio, Inc. * * This program is licensed to you under the terms of version 2 of the * GNU General Public License. This program is distributed WITHOUT ANY * EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details. * */ /* Inspird by Matrix/inst/include/Matrix_stubs.c */ #include "markdown_rstubs.h" int rstub_bufgrow(struct buf *buf, size_t sz) { static int (*fun)(struct buf *, size_t) = NULL; if (fun==NULL) fun = (int (*)(struct buf *,size_t))R_GetCCallable("markdown","bufgrow"); return fun(buf,sz); } struct buf *rstub_bufnew(size_t sz) { static struct buf *(*fun)(size_t) = NULL; if (fun==NULL) fun = (struct buf *(*)(size_t))R_GetCCallable("markdown","bufnew"); return fun(sz); } const char *rstub_bufcstr(struct buf *buf) { static const char *(*fun)(struct buf *) = NULL; if (fun==NULL) fun = (const char *(*)(struct buf *))R_GetCCallable("markdown","bufcstr"); return fun(buf); } int rstub_bufprefix(const struct buf *buf, const char *prefix) { static int (*fun)(const struct buf *, const char *) = NULL; if (fun==NULL) fun = (int (*)(const struct buf *, const char *))R_GetCCallable("markdown","bufprefix"); return fun(buf,prefix); } void rstub_bufput(struct buf *buf, const void *v, size_t sz) { static void (*fun)(struct buf *, const void *, size_t) = NULL; if (fun==NULL) fun = (void (*)(struct buf *, const void *, size_t))R_GetCCallable("markdown","bufput"); return fun(buf,v,sz); } void rstub_bufputs(struct buf *buf, const char *c) { static void (*fun)(struct buf *, const char *) = NULL; if (fun==NULL) fun = (void (*)(struct buf *, const char *))R_GetCCallable("markdown","bufputs"); return fun(buf,c); } void rstub_bufputc(struct buf *buf, int i) { static void (*fun)(struct buf *, int) = NULL; if (fun==NULL) fun = (void (*)(struct buf *, int))R_GetCCallable("markdown","bufputc"); return fun(buf,i); } void rstub_bufrelease(struct buf *buf) { static void (*fun)(struct buf *) = NULL; if (fun==NULL) fun = (void (*)(struct buf *t))R_GetCCallable("markdown","bufrelease"); return fun(buf); } void rstub_bufreset(struct buf *buf) { static void (*fun)(struct buf *) = NULL; if (fun==NULL) fun = (void (*)(struct buf *t))R_GetCCallable("markdown","bufreset"); return fun(buf); } void rstub_bufslurp(struct buf *buf, size_t sz) { static int (*fun)(struct buf *, size_t) = NULL; if (fun==NULL) fun = (int (*)(struct buf *,size_t))R_GetCCallable("markdown","bufslurp"); fun(buf,sz); } void rstub_bufprintf(struct buf *buf, const char *fmt, ...) { va_list ap; static int (*fun)(struct buf *, const char *, ...) = NULL; if (fun==NULL) fun = (int (*)(struct buf *,const char *, ...)) R_GetCCallable("markdown","bufprintf"); va_start(ap, fmt); fun(buf,fmt,ap); va_end(ap); } int rstub_sd_autolink_issafe(const uint8_t *link, size_t link_len){ static int (*fun)(const uint8_t *, size_t) = NULL; if (fun==NULL) fun = (int (*)(const uint8_t *, size_t)) R_GetCCallable("markdown","sd_autolink_issafe"); return fun(link,link_len); } size_t rstub_sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { static size_t (*fun)(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) = NULL; if (fun==NULL) fun = (size_t (*)(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)) R_GetCCallable("markdown","sd_autolink__www"); return fun(rewind_p,link,data,offset,size); } size_t rstub_sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { static size_t (*fun)(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) = NULL; if (fun==NULL) fun = (size_t (*)(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)) R_GetCCallable("markdown","sd_autolink__email"); return fun(rewind_p,link,data,offset,size); } size_t rstub_sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { static size_t (*fun)(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) = NULL; if (fun==NULL) fun = (size_t (*)(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)) R_GetCCallable("markdown","sd_autolink__url"); return fun(rewind_p,link,data,offset,size); } struct sd_markdown * rstub_sd_markdown_new(unsigned int extensions, size_t max_nesting, const struct sd_callbacks *callbacks, void *opaque) { static struct sd_markdown *(*fun)(unsigned int, size_t, const struct sd_callbacks *callbacks, void *) = NULL; if (fun==NULL) fun = (struct sd_markdown *(*)(unsigned int, size_t, const struct sd_callbacks *callbacks, void *)) R_GetCCallable("markdown","sd_markdown_new"); return fun(extensions,max_nesting,callbacks,opaque); } void rstub_sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md) { static void (*fun)(struct buf *, const uint8_t *, size_t, struct sd_markdown *) = NULL; if (fun==NULL) fun = (void (*)(struct buf *, const uint8_t *, size_t, struct sd_markdown *)) R_GetCCallable("markdown","sd_markdown_render"); return fun(ob,document,doc_size,md); } void rstub_sd_markdown_free(struct sd_markdown *md) { static void (*fun)(struct sd_markdown *) = NULL; if (fun==NULL) fun = (void (*)(struct sd_markdown *)) R_GetCCallable("markdown","sd_markdown_free"); return fun(md); } void rstub_sd_version(int *major, int *minor, int *revision) { static void (*fun)(int *, int *, int *) = NULL; if (fun==NULL) fun = (void (*)(int *, int *, int *)) R_GetCCallable("markdown","sd_version"); return fun(major,minor,revision); } Rboolean rstub_rmd_register_renderer(struct rmd_renderer *renderer) { static Rboolean (*fun)(struct rmd_renderer *) = NULL; if (fun==NULL) fun = (Rboolean (*)(struct rmd_renderer *)) R_GetCCallable("markdown","rmd_register_renderer"); return fun(renderer); } Rboolean rstub_rmd_renderer_exists(const char *name) { static SEXP (*fun)(SEXP) = NULL; if (fun==NULL) fun = (SEXP (*)(SEXP)) R_GetCCallable("markdown","rmd_renderer_exists"); return fun(name); } Rboolean rstub_rmd_buf_to_output(struct buf *ob, SEXP Soutput, SEXP *raw_vec) { static Rboolean (*fun)(struct buf *, SEXP, SEXP *) = NULL; if (fun==NULL) fun = (Rboolean (*)(struct buf *, SEXP, SEXP *)) R_GetCCallable("markdown","rmd_buf_to_output"); return fun(ob,Soutput,raw_vec); } Rboolean rstub_rmd_input_to_buf(SEXP Sfile, SEXP Stext, struct buf *ib) { static Rboolean (*fun)(SEXP, SEXP, struct buf *) = NULL; if (fun==NULL) fun = (Rboolean (*)(SEXP, SEXP, struct buf *)) R_GetCCallable("markdown","rmd_input_to_buf"); return fun(Sfile,Stext,ib); } markdown/inst/include/autolink.h0000644000175100001440000000252112330062343016505 0ustar hornikusers/* * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef UPSKIRT_AUTOLINK_H #define UPSKIRT_AUTOLINK_H #include "buffer.h" #ifdef __cplusplus extern "C" { #endif extern int sd_autolink_issafe(const uint8_t *link, size_t link_len); extern size_t sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); extern size_t sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); extern size_t sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); #ifdef __cplusplus } #endif #endif /* vim: set filetype=c: */ markdown/inst/include/buffer.h0000644000175100001440000000563112330062343016135 0ustar hornikusers/* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef BUFFER_H__ #define BUFFER_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif #if defined(_MSC_VER) #define __attribute__(x) #define inline #endif typedef enum { BUF_OK = 0, BUF_ENOMEM = -1, } buferror_t; /* struct buf: character array buffer */ struct buf { uint8_t *data; /* actual character data */ size_t size; /* size of the string */ size_t asize; /* allocated size (0 = volatile buffer) */ size_t unit; /* reallocation unit size (0 = read-only buffer) */ }; /* CONST_BUF: global buffer from a string litteral */ #define BUF_STATIC(string) \ { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 } /* VOLATILE_BUF: macro for creating a volatile buffer on the stack */ #define BUF_VOLATILE(strname) \ { (uint8_t *)strname, strlen(strname), 0, 0, 0 } /* BUFPUTSL: optimized bufputs of a string litteral */ #define BUFPUTSL(output, literal) \ bufput(output, literal, sizeof literal - 1) /* bufgrow: increasing the allocated size to the given value */ int bufgrow(struct buf *, size_t); /* bufnew: allocation of a new buffer */ struct buf *bufnew(size_t) __attribute__ ((malloc)); /* bufnullterm: NUL-termination of the string array (making a C-string) */ const char *bufcstr(struct buf *); /* bufprefix: compare the beginning of a buffer with a string */ int bufprefix(const struct buf *buf, const char *prefix); /* bufput: appends raw data to a buffer */ void bufput(struct buf *, const void *, size_t); /* bufputs: appends a NUL-terminated string to a buffer */ void bufputs(struct buf *, const char *); /* bufputc: appends a single char to a buffer */ void bufputc(struct buf *, int); /* bufrelease: decrease the reference count and free the buffer if needed */ void bufrelease(struct buf *); /* bufreset: frees internal data of the buffer */ void bufreset(struct buf *); /* bufslurp: removes a given number of bytes from the head of the array */ void bufslurp(struct buf *, size_t); /* bufprintf: formatted printing to a buffer */ void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); #ifdef __cplusplus } #endif #endif markdown/tests/0000755000175100001440000000000013075741765013273 5ustar hornikusersmarkdown/tests/empty.R0000644000175100001440000000020612561031415014531 0ustar hornikuserslibrary(markdown) f = tempfile() if (file.create(f)) { markdownToHTML(f, fragment.only = TRUE) markdownToHTML(f) unlink(f) } markdown/tests/b64EncodeFile.R0000644000175100001440000000043213075733465015724 0ustar hornikuserslibrary(markdown) ## Download url = "https://www.r-project.org/Rlogo.png" path = tempdir() pathname = file.path(tempdir(), basename(url)) if (!file_test("-f", pathname)) download.file(url, pathname) ## Encode data = markdown:::.b64EncodeFile(pathname) str(data) unlink(pathname) markdown/tests/tests.Rout.save0000644000175100001440000001575213075741756016257 0ustar hornikusers R version 3.3.3 (2017-03-06) -- "Another Canoe" Copyright (C) 2017 The R Foundation for Statistical Computing Platform: x86_64-apple-darwin13.4.0 (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. Natural language support but running in an English locale R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > library(markdown) > > source(system.file('examples', 'markdownExtensions.R', package = 'markdown'), echo = TRUE) > options(markdown.HTML.options = "fragment_only") > cat(markdownToHTML(text = "foo_bar_function", extensions = c()))

    foobarfunction

    > cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis")))

    foo_bar_function

    > cat(markdownToHTML(text = "\n First Header | Second Header\n ------------- | -------------\n Content Cell | Content Cell\n Content Cel ..." ... [TRUNCATED]
    First Header  | Second Header
    ------------- | -------------
    Content Cell  | Content Cell
    Content Cell  | Content Cell
    
    > cat(markdownToHTML(text = "\nFirst Header | Second Header\n------------- | -------------\nContent Cell | Content Cell\nContent Cell | Content Cel ..." ... [TRUNCATED]
    First Header Second Header
    Content Cell Content Cell
    Content Cell Content Cell
    > fenced_block <- function(text, x = "`", n = 3) { + fence <- paste(rep(x, n), collapse = "") + paste(fence, text, fence, sep = "") + } > cat(markdownToHTML(text = fenced_block("\npreformatted text here without having to indent\nfirst line.\n"), + extensions = c()))

    preformatted text here without having to indent first line.

    > cat(markdownToHTML(text = fenced_block("\npreformatted text here without having to indent\nfirst line.\n"), + extensions = c("fenced_code")))
    preformatted text here without having to indent
    first line.
    
    > cat(markdownToHTML(text = "https://www.r-project.org/", + extensions = c()))

    https://www.r-project.org/

    > cat(markdownToHTML(text = "https://www.r-project.org/", + extensions = c("autolink")))

    https://www.r-project.org/

    > cat(markdownToHTML(text = "~~awesome~~", extensions = c()))

    ~~awesome~~

    > cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough")))

    awesome

    > cat(markdownToHTML(text = "\nEmbedding html without surrounding with empty newline.\n
    _markdown_
    \nextra text.\n", + extensions = c("" .... [TRUNCATED]

    Embedding html without surrounding with empty newline.

    markdown
    extra text.

    > cat(markdownToHTML(text = "\nEmbedding html without surrounding with empty newline.\n
    _markdown_
    \nextra text.\n", + extensions = c("l ..." ... [TRUNCATED]

    Embedding html without surrounding with empty newline.

    _markdown_

    extra text.

    > cat(markdownToHTML(text = "#A Header\neven though there is no space between # and A", + extensions = c("")))

    A Header

    even though there is no space between # and A

    > cat(markdownToHTML(text = "#Not A Header\nbecause there is no space between # and N", + extensions = c("space_headers")))

    #Not A Header because there is no space between # and N

    > cat(markdownToHTML(text = "2^10", extensions = c()))

    2^10

    > cat(markdownToHTML(text = "2^10", extensions = c("superscript")))

    210

    > source(system.file('examples', 'HTMLOptions.R', package = 'markdown'), echo = TRUE) > tOpt <- "fragment_only" > mkd = "Hello" > cat(markdownToHTML(text = mkd, options = c(tOpt)))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt)))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style")))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt)))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images")))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt)))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links")))

    Hello

    > cat(markdownToHTML(text = "[foo](http://google.com \"baz\")", + options = c(tOpt)))

    foo

    > cat(markdownToHTML(text = "[foo](http://google.com \"baz\")", + options = c(tOpt, "safelink")))

    foo

    > mkd <- paste(c("# Header 1", "p1", "## Header 2", + "p2"), collapse = "\n") > cat(markdownToHTML(text = mkd, options = c(tOpt)))

    Header 1

    p1

    Header 2

    p2

    > cat(markdownToHTML(text = mkd, options = c(tOpt, "toc")))
    Table of Contents

    Header 1

    p1

    Header 2

    p2

    > cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt)))

    foo bar

    > cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, + "hard_wrap")))

    foo
    bar

    > cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, + "hard_wrap")))

    foo
    bar

    > cat(markdownToHTML(text = "foo\nbar\n", options = c(tOpt, + "hard_wrap", "use_xhtml")))

    foo
    bar

    > mkd = "Hello" > cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))

    Hello

    > cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", + "escape")))

    <style></style><img src="http://cran.rstudio.com/Rlogo.jpg"><a href="#">Hello</a>

    > cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt)))

    1/2 (c)

    > cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, + "smartypants")))

    ½ ©

    > cat(smartypants(text = "1/2 (c)\n")) ½ © > > rm(mkd) > rm(tOpt) > > proc.time() user system elapsed 0.187 0.045 0.233 markdown/tests/tests.R0000644000175100001440000000032412330062343014534 0ustar hornikuserslibrary(markdown) source(system.file('examples', 'markdownExtensions.R', package = 'markdown'), echo = TRUE) source(system.file('examples', 'HTMLOptions.R', package = 'markdown'), echo = TRUE) rm(mkd) rm(tOpt) markdown/src/0000755000175100001440000000000013075742411012705 5ustar hornikusersmarkdown/src/houdini.h0000644000175100001440000000250413075742411014516 0ustar hornikusers#ifndef HOUDINI_H__ #define HOUDINI_H__ #include "buffer.h" #ifdef __cplusplus extern "C" { #endif #ifdef HOUDINI_USE_LOCALE # define _isxdigit(c) isxdigit(c) # define _isdigit(c) isdigit(c) #else /* * Helper _isdigit methods -- do not trust the current locale * */ # define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL) # define _isdigit(c) ((c) >= '0' && (c) <= '9') #endif extern void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure); extern void houdini_unescape_html(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_escape_xml(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_escape_uri(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_escape_url(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_unescape_uri(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_unescape_url(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size); extern void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size); #ifdef __cplusplus } #endif #endif markdown/src/buffer.c0000644000175100001440000001056113075742411014325 0ustar hornikusers/* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) /* 16mb */ #include "buffer.h" #include #include #include #include /* MSVC compat */ #if defined(__MINGW32__) # define _buf_vsnprintf _vsnprintf #else # define _buf_vsnprintf vsnprintf #endif int bufprefix(const struct buf *buf, const char *prefix) { size_t i; assert(buf && buf->unit); for (i = 0; i < buf->size; ++i) { if (prefix[i] == 0) return 0; if (buf->data[i] != prefix[i]) return buf->data[i] - prefix[i]; } return 0; } /* bufgrow: increasing the allocated size to the given value */ int bufgrow(struct buf *buf, size_t neosz) { size_t neoasz; void *neodata; assert(buf && buf->unit); if (neosz > BUFFER_MAX_ALLOC_SIZE) return BUF_ENOMEM; if (buf->asize >= neosz) return BUF_OK; neoasz = buf->asize + buf->unit; while (neoasz < neosz) neoasz += buf->unit; neodata = realloc(buf->data, neoasz); if (!neodata) return BUF_ENOMEM; buf->data = neodata; buf->asize = neoasz; return BUF_OK; } /* bufnew: allocation of a new buffer */ struct buf * bufnew(size_t unit) { struct buf *ret; ret = malloc(sizeof (struct buf)); if (ret) { ret->data = 0; ret->size = ret->asize = 0; ret->unit = unit; } return ret; } /* bufnullterm: NULL-termination of the string array */ const char * bufcstr(struct buf *buf) { assert(buf && buf->unit); if (buf->size < buf->asize && buf->data[buf->size] == 0) return (char *)buf->data; if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) { buf->data[buf->size] = 0; return (char *)buf->data; } return NULL; } /* bufprintf: formatted printing to a buffer */ void bufprintf(struct buf *buf, const char *fmt, ...) { va_list ap; int n; assert(buf && buf->unit); if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0) return; va_start(ap, fmt); n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); va_end(ap); if (n < 0) { #ifdef __MINGW32__ va_start(ap, fmt); n = _vscprintf(fmt, ap); va_end(ap); #else return; #endif } if ((size_t)n >= buf->asize - buf->size) { if (bufgrow(buf, buf->size + n + 1) < 0) return; va_start(ap, fmt); n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); va_end(ap); } if (n < 0) return; buf->size += n; } /* bufput: appends raw data to a buffer */ void bufput(struct buf *buf, const void *data, size_t len) { assert(buf && buf->unit); if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0) return; memcpy(buf->data + buf->size, data, len); buf->size += len; } /* bufputs: appends a NUL-terminated string to a buffer */ void bufputs(struct buf *buf, const char *str) { bufput(buf, str, strlen(str)); } /* bufputc: appends a single uint8_t to a buffer */ void bufputc(struct buf *buf, int c) { assert(buf && buf->unit); if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0) return; buf->data[buf->size] = c; buf->size += 1; } /* bufrelease: decrease the reference count and free the buffer if needed */ void bufrelease(struct buf *buf) { if (!buf) return; free(buf->data); free(buf); } /* bufreset: frees internal data of the buffer */ void bufreset(struct buf *buf) { if (!buf) return; free(buf->data); buf->data = NULL; buf->size = buf->asize = 0; } /* bufslurp: removes a given number of bytes from the head of the array */ void bufslurp(struct buf *buf, size_t len) { assert(buf && buf->unit); if (len >= buf->size) { buf->size = 0; return; } buf->size -= len; memmove(buf->data, buf->data + len, buf->size); } markdown/src/stack.c0000644000175100001440000000210413075742411014153 0ustar hornikusers#include "stack.h" #include int stack_grow(struct stack *st, size_t new_size) { void **new_st; if (st->asize >= new_size) return 0; new_st = realloc(st->item, new_size * sizeof(void *)); if (new_st == NULL) return -1; memset(new_st + st->asize, 0x0, (new_size - st->asize) * sizeof(void *)); st->item = new_st; st->asize = new_size; if (st->size > new_size) st->size = new_size; return 0; } void stack_free(struct stack *st) { if (!st) return; free(st->item); st->item = NULL; st->size = 0; st->asize = 0; } int stack_init(struct stack *st, size_t initial_size) { st->item = NULL; st->size = 0; st->asize = 0; if (!initial_size) initial_size = 8; return stack_grow(st, initial_size); } void * stack_pop(struct stack *st) { if (!st->size) return NULL; return st->item[--st->size]; } int stack_push(struct stack *st, void *item) { if (stack_grow(st, st->size * 2) < 0) return -1; st->item[st->size++] = item; return 0; } void * stack_top(struct stack *st) { if (!st->size) return NULL; return st->item[st->size - 1]; } markdown/src/Rmarkdown.h0000644000175100001440000000262213075742411015024 0ustar hornikusers/* * Rmarkdown.h * * Copyright (C) 2009-2013 by RStudio, Inc. * * This program is licensed to you under the terms of version 2 of the * GNU General Public License. This program is distributed WITHOUT ANY * EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details. * */ #include #include #include "markdown.h" #include "html.h" #define READ_UNIT 1024 #define OUTPUT_UNIT 64 #define RMD_WARNING_NOMEM warning("Out of memory!") /* * output_type should be either "raw" or "character" */ struct rmd_renderer { char *name; Rboolean (*render)(struct buf *,struct buf *, SEXP, SEXP); char *output_type; }; extern void rmd_init_renderer_list(); extern Rboolean rmd_buf_to_output(struct buf *, SEXP, SEXP *); extern Rboolean rmd_input_to_buf(SEXP, SEXP, struct buf *); extern Rboolean rmd_register_renderer(struct rmd_renderer *); extern Rboolean rmd_renderer_exists(const char *name); extern SEXP rmd_registered_renderers(void); extern SEXP rmd_render_markdown(SEXP Sfile, SEXP Soutput, SEXP Stext, SEXP Srenderer, SEXP Srender_options, SEXP Soptions); extern SEXP rmd_render_smartypants(SEXP Sfile, SEXP Soutput, SEXP Stext); extern SEXP rmd_b64encode_data( SEXP Sdata); markdown/src/Rbase64.c0000644000175100001440000000324313075742411014261 0ustar hornikusers#include "Rmarkdown.h" #include #include /* * Translation Table as described in RFC1113 */ static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * encodeblock * * encode 3 8-bit binary bytes as 4 '6-bit' characters */ void encodeblock( unsigned char in[3], unsigned char out[4], int len ) { out[0] = cb64[ in[0] >> 2 ]; out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); } SEXP rmd_b64encode_data( SEXP Sdata) { unsigned char in[3], out[4]; int i, len; int data_len = LENGTH(Sdata); int data_elem = 0; Rbyte *data = RAW(Sdata); SEXP ans; struct buf *databuf; const char* str; /* Create a buffer that grows READ_UNIT bytes at the time as a larger buffer is needed */ databuf = bufnew(READ_UNIT); if (!databuf) { RMD_WARNING_NOMEM; return R_NilValue; } while( data_elem < data_len ) { len = 0; for( i = 0; i < 3; i++ ) { if( data_elem < data_len ) { in[i] = (unsigned char) data[data_elem++]; len++; } else { in[i] = 0; } } if( len ) { encodeblock( in, out, len ); bufput(databuf,out,4); } } str = bufcstr(databuf); if (!str) { bufrelease(databuf); RMD_WARNING_NOMEM; return R_NilValue; } PROTECT(ans = allocVector(STRSXP,1)); SET_STRING_ELT(ans,0,mkChar(str)); bufrelease(databuf); UNPROTECT(1); return ans; } markdown/src/markdown.h0000644000175100001440000001165113075742411014704 0ustar hornikusers/* markdown.h - generic markdown parser */ /* * Copyright (c) 2009, Natacha Porté * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef UPSKIRT_MARKDOWN_H #define UPSKIRT_MARKDOWN_H #include "buffer.h" #include "autolink.h" #ifdef __cplusplus extern "C" { #endif #define SUNDOWN_VERSION "1.16.0" #define SUNDOWN_VER_MAJOR 1 #define SUNDOWN_VER_MINOR 16 #define SUNDOWN_VER_REVISION 0 /******************** * TYPE DEFINITIONS * ********************/ /* mkd_autolink - type of autolink */ enum mkd_autolink { MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */ MKDA_EMAIL /* e-mail link without explit mailto: */ }; enum mkd_tableflags { MKD_TABLE_ALIGN_L = 1, MKD_TABLE_ALIGN_R = 2, MKD_TABLE_ALIGN_CENTER = 3, MKD_TABLE_ALIGNMASK = 3, MKD_TABLE_HEADER = 4 }; enum mkd_extensions { MKDEXT_NO_INTRA_EMPHASIS = (1 << 0), MKDEXT_TABLES = (1 << 1), MKDEXT_FENCED_CODE = (1 << 2), MKDEXT_AUTOLINK = (1 << 3), MKDEXT_STRIKETHROUGH = (1 << 4), MKDEXT_SPACE_HEADERS = (1 << 6), MKDEXT_SUPERSCRIPT = (1 << 7), MKDEXT_LAX_SPACING = (1 << 8), MKDEXT_LATEX_MATH = (1 << 9) }; /* sd_callbacks - functions for rendering parsed data */ struct sd_callbacks { /* block level callbacks - NULL skips the block */ void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque); void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque); void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque); void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque); void (*hrule)(struct buf *ob, void *opaque); void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque); void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque); void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque); void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque); void (*table_row)(struct buf *ob, const struct buf *text, void *opaque); void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque); /* span level callbacks - NULL or return 0 prints the span verbatim */ int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque); int (*codespan)(struct buf *ob, const struct buf *text, void *opaque); int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque); int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque); int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque); int (*linebreak)(struct buf *ob, void *opaque); int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque); int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque); int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque); int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque); int (*superscript)(struct buf *ob, const struct buf *text, void *opaque); int (*inlinemath)(struct buf *ob, const struct buf *text, void *opaque); int (*displayedmath)(struct buf *ob, const struct buf *text, void *opaque); /* low level callbacks - NULL copies input directly into the output */ void (*entity)(struct buf *ob, const struct buf *entity, void *opaque); void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque); /* header and footer */ void (*doc_header)(struct buf *ob, void *opaque); void (*doc_footer)(struct buf *ob, void *opaque); }; struct sd_markdown; /********* * FLAGS * *********/ /* list/listitem flags */ #define MKD_LIST_ORDERED 1 #define MKD_LI_BLOCK 2 /*
  • containing block data */ /********************** * EXPORTED FUNCTIONS * **********************/ extern struct sd_markdown * sd_markdown_new( unsigned int extensions, size_t max_nesting, const struct sd_callbacks *callbacks, void *opaque); extern void sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md); extern void sd_markdown_free(struct sd_markdown *md); extern void sd_version(int *major, int *minor, int *revision); #ifdef __cplusplus } #endif #endif /* vim: set filetype=c: */ markdown/src/houdini_href_e.c0000644000175100001440000000560613075742411016027 0ustar hornikusers#include #include #include #include "houdini.h" #define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) /* * The following characters will not be escaped: * * -_.+!*'(),%#@?=;:/,+&$ alphanum * * Note that this character set is the addition of: * * - The characters which are safe to be in an URL * - The characters which are *not* safe to be in * an URL because they are RESERVED characters. * * We asume (lazily) that any RESERVED char that * appears inside an URL is actually meant to * have its native function (i.e. as an URL * component/separator) and hence needs no escaping. * * There are two exceptions: the chacters & (amp) * and ' (single quote) do not appear in the table. * They are meant to appear in the URL as components, * yet they require special HTML-entity escaping * to generate valid HTML markup. * * All other characters will be escaped to %XX. * */ static const char HREF_SAFE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size) { static const char hex_chars[] = "0123456789ABCDEF"; size_t i = 0, org; char hex_str[3]; bufgrow(ob, ESCAPE_GROW_FACTOR(size)); hex_str[0] = '%'; while (i < size) { org = i; while (i < size && HREF_SAFE[src[i]] != 0) i++; if (i > org) bufput(ob, src + org, i - org); /* escaping */ if (i >= size) break; switch (src[i]) { /* amp appears all the time in URLs, but needs * HTML-entity escaping to be inside an href */ case '&': BUFPUTSL(ob, "&"); break; /* the single quote is a valid URL character * according to the standard; it needs HTML * entity escaping too */ case '\'': BUFPUTSL(ob, "'"); break; /* the space can be escaped to %20 or a plus * sign. we're going with the generic escape * for now. the plus thing is more commonly seen * when building GET strings */ #if 0 case ' ': bufputc(ob, '+'); break; #endif /* every other character goes with a %XX escaping */ default: hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; hex_str[2] = hex_chars[src[i] & 0xF]; bufput(ob, hex_str, 3); } i++; } } markdown/src/markdown.c0000644000175100001440000017532213075742411014705 0ustar hornikusers/* markdown.c - generic markdown parser */ /* * Copyright (c) 2009, Natacha Porté * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "markdown.h" #include "stack.h" #include #include #include #include #if defined(_WIN32) #define strncasecmp _strnicmp #endif #define REF_TABLE_SIZE 8 #define BUFFER_BLOCK 0 #define BUFFER_SPAN 1 #define MKD_LI_END 8 /* internal list flag */ #define gperf_case_strncmp(s1, s2, n) strncasecmp(s1, s2, n) #define GPERF_DOWNCASE 1 #define GPERF_CASE_STRNCMP 1 #include "html_blocks.h" /*************** * LOCAL TYPES * ***************/ /* link_ref: reference to a link */ struct link_ref { unsigned int id; struct buf *link; struct buf *title; struct link_ref *next; }; /* char_trigger: function pointer to render active chars */ /* returns the number of chars taken care of */ /* data is the pointer of the beginning of the span */ /* offset is the number of valid chars before data */ struct sd_markdown; typedef size_t (*char_trigger)(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); static size_t char_dollar(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size); enum markdown_char_t { MD_CHAR_NONE = 0, MD_CHAR_EMPHASIS, MD_CHAR_CODESPAN, MD_CHAR_LINEBREAK, MD_CHAR_LINK, MD_CHAR_LANGLE, MD_CHAR_ESCAPE, MD_CHAR_ENTITITY, MD_CHAR_AUTOLINK_URL, MD_CHAR_AUTOLINK_EMAIL, MD_CHAR_AUTOLINK_WWW, MD_CHAR_SUPERSCRIPT, MD_CHAR_DOLLAR }; static char_trigger markdown_char_ptrs[] = { NULL, &char_emphasis, &char_codespan, &char_linebreak, &char_link, &char_langle_tag, &char_escape, &char_entity, &char_autolink_url, &char_autolink_email, &char_autolink_www, &char_superscript, &char_dollar }; /* render • structure containing one particular render */ struct sd_markdown { struct sd_callbacks cb; void *opaque; struct link_ref *refs[REF_TABLE_SIZE]; uint8_t active_char[256]; struct stack work_bufs[2]; unsigned int ext_flags; size_t max_nesting; int in_link_body; }; /*************************** * HELPER FUNCTIONS * ***************************/ static inline struct buf * rndr_newbuf(struct sd_markdown *rndr, int type) { static const size_t buf_size[2] = {256, 64}; struct buf *work = NULL; struct stack *pool = &rndr->work_bufs[type]; if (pool->size < pool->asize && pool->item[pool->size] != NULL) { work = pool->item[pool->size++]; work->size = 0; } else { work = bufnew(buf_size[type]); stack_push(pool, work); } return work; } static inline void rndr_popbuf(struct sd_markdown *rndr, int type) { rndr->work_bufs[type].size--; } static void unscape_text(struct buf *ob, struct buf *src) { size_t i = 0, org; while (i < src->size) { org = i; while (i < src->size && src->data[i] != '\\') i++; if (i > org) bufput(ob, src->data + org, i - org); if (i + 1 >= src->size) break; bufputc(ob, src->data[i + 1]); i += 2; } } static unsigned int hash_link_ref(const uint8_t *link_ref, size_t length) { size_t i; unsigned int hash = 0; for (i = 0; i < length; ++i) hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash; return hash; } static struct link_ref * add_link_ref( struct link_ref **references, const uint8_t *name, size_t name_size) { struct link_ref *ref = calloc(1, sizeof(struct link_ref)); if (!ref) return NULL; ref->id = hash_link_ref(name, name_size); ref->next = references[ref->id % REF_TABLE_SIZE]; references[ref->id % REF_TABLE_SIZE] = ref; return ref; } static struct link_ref * find_link_ref(struct link_ref **references, uint8_t *name, size_t length) { unsigned int hash = hash_link_ref(name, length); struct link_ref *ref = NULL; ref = references[hash % REF_TABLE_SIZE]; while (ref != NULL) { if (ref->id == hash) return ref; ref = ref->next; } return NULL; } static void free_link_refs(struct link_ref **references) { size_t i; for (i = 0; i < REF_TABLE_SIZE; ++i) { struct link_ref *r = references[i]; struct link_ref *next; while (r) { next = r->next; bufrelease(r->link); bufrelease(r->title); free(r); r = next; } } } /* * Check whether a char is a Markdown space. * Right now we only consider spaces the actual * space and a newline: tabs and carriage returns * are filtered out during the preprocessing phase. * * If we wanted to actually be UTF-8 compliant, we * should instead extract an Unicode codepoint from * this character and check for space properties. */ static inline int _isspace(int c) { return c == ' ' || c == '\n'; } /******************************** * LATEX MATH PARSING FUNCTIONS * ********************************/ /* org-mode inline latex math, e.g. $...$ * * Rules for parsing: * * 1. eqations must be attached to begin and end $ * 2. at most two newlines in the equation * 3. the closing $ must be followed by whitespace, punctuation, or a dash. */ static size_t prefix_math(uint8_t *data, size_t size) { /* $$latex */ if (7 < size && data[0] == '$' && data[1] == '$' && data[2] == 'l' && data[3] == 'a' && data[4] == 't' && data[5] == 'e' && data[6] == 'x') return 7; /* $latex */ if (6 < size && data[0] == '$' && data[1] == 'l' && data[2] == 'a' && data[3] == 't' && data[4] == 'e' && data[5] == 'x') return 6; /* $$ */ else if (2 < size && data[0] == '$' && data[1] == '$') return 2; /* $ */ else if (1 < size && data[0] == '$') return 1; return 0; } static size_t parse_orgmode_math(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { static const char *punct = "!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~"; size_t i = 1, nl = 0, length = 0; struct buf *work; int r; if (!rndr->cb.inlinemath) return 0; if (i < size && (data[i] == ' ' || data[i] == '\n') ) return 0; while(i < size){ while (i < size && !(data[i] == '\n' || data[i] == '$')) { i++; length++; } if (i == size) return 0; if (data[i] == '\n') nl++; if (nl > 2) return 0; if (data[i] == '$'){ /* bail if there's whitespace before the dollar or */ if (data[i - 1] == ' ' || data[i - 1] == '\n') return 0; /* bail if there's not whitespace or punctuation following the * dollar. */ if (i < size && data[i + 1] != ' ' && data[i + 1] != '\n' && (strchr(punct,data[i + 1]) == NULL) ) return 0; i++; if (i <= size) { work = rndr_newbuf(rndr, BUFFER_SPAN); bufput(work, data + 1, length); r = rndr->cb.inlinemath(ob,work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); return r ? i : 0; } else { return 0; } } i++; length++; } return 0; } /* parse_escape_math • parse \(...\) or \[...\] and return */ static size_t parse_escape_math(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { int (*render_method)(struct buf *ob, const struct buf *text, void *opaque); size_t i = 1, length = 0; uint8_t c; struct buf *work; int r; if (i < size) { switch (data[i]) { case '(': if (!rndr->cb.inlinemath) return 0; render_method = rndr->cb.inlinemath; c = ')'; break; case '[': if (!rndr->cb.displayedmath) return 0; render_method = rndr->cb.displayedmath; c = ']'; break; default: return 0; } } i++; while (i < size) { while (i < size && data[i] != '\\') { i++; length++; } if (i == size) return 0; if (i + 1 < size && data[i + 1] == c){ i += 2; work = rndr_newbuf(rndr, BUFFER_SPAN); bufput(work, data + 2, length); r = render_method(ob,work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); return r ? i : 0; } i++; length++; } return 0; } static size_t parse_inline_math(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t i = 0, pre; struct buf *work; int r; if (!rndr->cb.inlinemath) return 0; pre = prefix_math(data, size); if (pre == 0) return 0; i = pre; while (i < size && data[i] != '$') i++; if (i == size) return 0; work = rndr_newbuf(rndr, BUFFER_SPAN); bufput(work, data + pre, i - pre); r = rndr->cb.inlinemath(ob,work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); i++; return r ? i : 0; } static size_t parse_displayed_math(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t i = 0, pre; struct buf *work; int r; if (!rndr->cb.displayedmath) return 0; pre = prefix_math(data, size); if (pre == 0) return 0; i = pre; while (i + 1 < size && !(data[i] == '$' && data[i + 1] == '$') ) i++; if (i == size - 1) return 0; work = rndr_newbuf(rndr, BUFFER_SPAN); bufput(work, data + pre, i - pre); r = rndr->cb.displayedmath(ob,work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); i += 2; /* passed the $$ */ return r ? i : 0; } static size_t char_dollar(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { size_t i; i = prefix_math(data, size); if (i == 0) return 0; if (i > 1) { /* $$latex or $$ */ if (data[0] == '$' && data[1] == '$') return parse_displayed_math(ob, rndr, data, size); /* $latex */ return parse_inline_math(ob, rndr, data, size); } /* $ */ if (i == 1) return parse_orgmode_math(ob, rndr, data, size); return 0; } /**************************** * INLINE PARSING FUNCTIONS * ****************************/ /* is_mail_autolink • looks for the address part of a mail autolink and '>' */ /* this is less strict than the original markdown e-mail address matching */ static size_t is_mail_autolink(uint8_t *data, size_t size) { size_t i = 0, nb = 0; /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */ for (i = 0; i < size; ++i) { if (isalnum(data[i])) continue; switch (data[i]) { case '@': nb++; case '-': case '.': case '_': break; case '>': return (nb == 1) ? i + 1 : 0; default: return 0; } } return 0; } /* tag_length • returns the length of the given tag, or 0 is it's not valid */ static size_t tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink) { size_t i, j; /* a valid tag can't be shorter than 3 chars */ if (size < 3) return 0; /* begins with a '<' optionally followed by '/', followed by letter or number */ if (data[0] != '<') return 0; i = (data[1] == '/') ? 2 : 1; if (!isalnum(data[i])) return 0; /* scheme test */ *autolink = MKDA_NOT_AUTOLINK; /* try to find the beginning of an URI */ while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-')) i++; if (i > 1 && data[i] == '@') { if ((j = is_mail_autolink(data + i, size - i)) != 0) { *autolink = MKDA_EMAIL; return i + j; } } if (i > 2 && data[i] == ':') { *autolink = MKDA_NORMAL; i++; } /* completing autolink test: no whitespace or ' or " */ if (i >= size) *autolink = MKDA_NOT_AUTOLINK; else if (*autolink) { j = i; while (i < size) { if (data[i] == '\\') i += 2; else if (data[i] == '>' || data[i] == '\'' || data[i] == '"' || data[i] == ' ' || data[i] == '\n') break; else i++; } if (i >= size) return 0; if (i > j && data[i] == '>') return i + 1; /* one of the forbidden chars has been found */ *autolink = MKDA_NOT_AUTOLINK; } /* looking for sometinhg looking like a tag end */ while (i < size && data[i] != '>') i++; if (i >= size) return 0; return i + 1; } /* parse_inline • parses inline markdown elements */ static void parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t i = 0, end = 0; uint8_t action = 0; struct buf work = { 0, 0, 0, 0 }; if (rndr->work_bufs[BUFFER_SPAN].size + rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting) return; while (i < size) { /* copying inactive chars into the output */ while (end < size && (action = rndr->active_char[data[end]]) == 0) { end++; } if (rndr->cb.normal_text) { work.data = data + i; work.size = end - i; rndr->cb.normal_text(ob, &work, rndr->opaque); } else bufput(ob, data + i, end - i); if (end >= size) break; i = end; end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i); if (!end) /* no action from the callback */ end = i + 1; else { i += end; end = i; } } } /* find_emph_char • looks for the next emph uint8_t, skipping other constructs */ static size_t find_emph_char(uint8_t *data, size_t size, uint8_t c) { size_t i = 1; while (i < size) { while (i < size && data[i] != c && data[i] != '`' && data[i] != '[') i++; if (i == size) return 0; if (data[i] == c) return i; /* not counting escaped chars */ if (i && data[i - 1] == '\\') { i++; continue; } if (data[i] == '`') { size_t span_nb = 0, bt; size_t tmp_i = 0; /* counting the number of opening backticks */ while (i < size && data[i] == '`') { i++; span_nb++; } if (i >= size) return 0; /* finding the matching closing sequence */ bt = 0; while (i < size && bt < span_nb) { if (!tmp_i && data[i] == c) tmp_i = i; if (data[i] == '`') bt++; else bt = 0; i++; } if (i >= size) return tmp_i; } /* skipping a link */ else if (data[i] == '[') { size_t tmp_i = 0; uint8_t cc; i++; while (i < size && data[i] != ']') { if (!tmp_i && data[i] == c) tmp_i = i; i++; } i++; while (i < size && (data[i] == ' ' || data[i] == '\n')) i++; if (i >= size) return tmp_i; switch (data[i]) { case '[': cc = ']'; break; case '(': cc = ')'; break; default: if (tmp_i) return tmp_i; else continue; } i++; while (i < size && data[i] != cc) { if (!tmp_i && data[i] == c) tmp_i = i; i++; } if (i >= size) return tmp_i; i++; } } return 0; } /* parse_emph1 • parsing single emphase */ /* closed by a symbol not preceded by whitespace and not followed by symbol */ static size_t parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) { size_t i = 0, len; struct buf *work = 0; int r; if (!rndr->cb.emphasis) return 0; /* skipping one symbol if coming from emph3 */ if (size > 1 && data[0] == c && data[1] == c) i = 1; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; if (i >= size) return 0; if (data[i] == c && !_isspace(data[i - 1])) { if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) { if (!(i + 1 == size || _isspace(data[i + 1]) || ispunct(data[i + 1]))) continue; } work = rndr_newbuf(rndr, BUFFER_SPAN); parse_inline(work, rndr, data, i); r = rndr->cb.emphasis(ob, work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); return r ? i + 1 : 0; } } return 0; } /* parse_emph2 • parsing single emphase */ static size_t parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) { int (*render_method)(struct buf *ob, const struct buf *text, void *opaque); size_t i = 0, len; struct buf *work = 0; int r; render_method = (c == '~') ? rndr->cb.strikethrough : rndr->cb.double_emphasis; if (!render_method) return 0; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) { work = rndr_newbuf(rndr, BUFFER_SPAN); parse_inline(work, rndr, data, i); r = render_method(ob, work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); return r ? i + 2 : 0; } i++; } return 0; } /* parse_emph3 • parsing single emphase */ /* finds the first closing tag, and delegates to the other emph */ static size_t parse_emph3(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c) { size_t i = 0, len; int r; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; /* skip whitespace preceded symbols */ if (data[i] != c || _isspace(data[i - 1])) continue; if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && rndr->cb.triple_emphasis) { /* triple symbol found */ struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN); parse_inline(work, rndr, data, i); r = rndr->cb.triple_emphasis(ob, work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); return r ? i + 3 : 0; } else if (i + 1 < size && data[i + 1] == c) { /* double symbol found, handing over to emph1 */ len = parse_emph1(ob, rndr, data - 2, size + 2, c); if (!len) return 0; else return len - 2; } else { /* single symbol found, handing over to emph2 */ len = parse_emph2(ob, rndr, data - 1, size + 1, c); if (!len) return 0; else return len - 1; } } return 0; } /* char_emphasis • single and double emphasis parsing */ static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { uint8_t c = data[0]; size_t ret; if (size > 2 && data[1] != c) { /* whitespace cannot follow an opening emphasis; * strikethrough only takes two characters '~~' */ if (c == '~' || _isspace(data[1]) || (ret = parse_emph1(ob, rndr, data + 1, size - 1, c)) == 0) return 0; return ret + 1; } if (size > 3 && data[1] == c && data[2] != c) { if (_isspace(data[2]) || (ret = parse_emph2(ob, rndr, data + 2, size - 2, c)) == 0) return 0; return ret + 2; } if (size > 4 && data[1] == c && data[2] == c && data[3] != c) { if (c == '~' || _isspace(data[3]) || (ret = parse_emph3(ob, rndr, data + 3, size - 3, c)) == 0) return 0; return ret + 3; } return 0; } /* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */ static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { if (offset < 2 || data[-1] != ' ' || data[-2] != ' ') return 0; /* removing the last space from ob and rendering */ while (ob->size && ob->data[ob->size - 1] == ' ') ob->size--; return rndr->cb.linebreak(ob, rndr->opaque) ? 1 : 0; } /* char_codespan • '`' parsing a code span (assuming codespan != 0) */ static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { size_t end, nb = 0, i, f_begin, f_end; /* counting the number of backticks in the delimiter */ while (nb < size && data[nb] == '`') nb++; /* finding the next delimiter */ i = 0; for (end = nb; end < size && i < nb; end++) { if (data[end] == '`') i++; else i = 0; } if (i < nb && end >= size) return 0; /* no matching delimiter */ /* trimming outside whitespaces */ f_begin = nb; while (f_begin < end && data[f_begin] == ' ') f_begin++; f_end = end - nb; while (f_end > nb && data[f_end-1] == ' ') f_end--; /* real code span */ if (f_begin < f_end) { struct buf work = {0, 0, 0, 0}; work.data = data + f_begin; work.size = f_end - f_begin; if (!rndr->cb.codespan(ob, &work, rndr->opaque)) end = 0; } else { if (!rndr->cb.codespan(ob, 0, rndr->opaque)) end = 0; } return end; } /* char_escape • '\\' backslash escape */ static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>^~$"; struct buf work = { 0, 0, 0, 0 }; if (size > 1) { size_t i; if (strchr(escape_chars, data[1]) == NULL) return 0; if (size > 2 && (data[1] == '(' || data[1] == '[') && ((rndr->ext_flags & MKDEXT_LATEX_MATH) != 0) && ((i = parse_escape_math(ob, rndr, data, size)) != 0) ) return i; if (rndr->cb.normal_text) { work.data = data + 1; work.size = 1; rndr->cb.normal_text(ob, &work, rndr->opaque); } else bufputc(ob, data[1]); } else if (size == 1) { bufputc(ob, data[0]); } return 2; } /* char_entity • '&' escaped when it doesn't belong to an entity */ /* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { size_t end = 1; struct buf work = { 0, 0, 0, 0 }; if (end < size && data[end] == '#') end++; while (end < size && isalnum(data[end])) end++; if (end < size && data[end] == ';') end++; /* real entity */ else return 0; /* lone '&' */ if (rndr->cb.entity) { work.data = data; work.size = end; rndr->cb.entity(ob, &work, rndr->opaque); } else bufput(ob, data, end); return end; } /* char_langle_tag • '<' when tags or autolinks are allowed */ static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { enum mkd_autolink altype = MKDA_NOT_AUTOLINK; size_t end = tag_length(data, size, &altype); int ret = 0; struct buf work = { 0, 0, 0, 0 }; work.data = data; work.size = end; if (end > 2) { if (rndr->cb.autolink && altype != MKDA_NOT_AUTOLINK) { struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN); work.data = data + 1; work.size = end - 2; unscape_text(u_link, &work); ret = rndr->cb.autolink(ob, u_link, altype, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); } else if (rndr->cb.raw_html_tag) ret = rndr->cb.raw_html_tag(ob, &work, rndr->opaque); } if (!ret) return 0; else return end; } static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { struct buf *link, *link_url, *link_text; size_t link_len, rewind; if (!rndr->cb.link || rndr->in_link_body) return 0; link = rndr_newbuf(rndr, BUFFER_SPAN); if ((link_len = sd_autolink__www(&rewind, link, data, offset, size)) > 0) { link_url = rndr_newbuf(rndr, BUFFER_SPAN); BUFPUTSL(link_url, "http://"); bufput(link_url, link->data, link->size); ob->size -= rewind; if (rndr->cb.normal_text) { link_text = rndr_newbuf(rndr, BUFFER_SPAN); rndr->cb.normal_text(link_text, link, rndr->opaque); rndr->cb.link(ob, link_url, NULL, link_text, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); } else { rndr->cb.link(ob, link_url, NULL, link, rndr->opaque); } rndr_popbuf(rndr, BUFFER_SPAN); } rndr_popbuf(rndr, BUFFER_SPAN); return link_len; } static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { struct buf *link; size_t link_len, rewind; if (!rndr->cb.autolink || rndr->in_link_body) return 0; link = rndr_newbuf(rndr, BUFFER_SPAN); if ((link_len = sd_autolink__email(&rewind, link, data, offset, size)) > 0) { ob->size -= rewind; rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque); } rndr_popbuf(rndr, BUFFER_SPAN); return link_len; } static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { struct buf *link; size_t link_len, rewind; if (!rndr->cb.autolink || rndr->in_link_body) return 0; link = rndr_newbuf(rndr, BUFFER_SPAN); if ((link_len = sd_autolink__url(&rewind, link, data, offset, size)) > 0) { ob->size -= rewind; rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque); } rndr_popbuf(rndr, BUFFER_SPAN); return link_len; } /* char_link • '[': parsing a link or an image */ static size_t char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { int is_img = (offset && data[-1] == '!'), level; size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; struct buf *content = 0; struct buf *link = 0; struct buf *title = 0; struct buf *u_link = 0; size_t org_work_size = rndr->work_bufs[BUFFER_SPAN].size; int text_has_nl = 0, ret = 0; int in_title = 0, qtype = 0; /* checking whether the correct renderer exists */ if ((is_img && !rndr->cb.image) || (!is_img && !rndr->cb.link)) goto cleanup; /* looking for the matching closing bracket */ for (level = 1; i < size; i++) { if (data[i] == '\n') text_has_nl = 1; else if (data[i - 1] == '\\') continue; else if (data[i] == '[') level++; else if (data[i] == ']') { level--; if (level <= 0) break; } } if (i >= size) goto cleanup; txt_e = i; i++; /* skip any amount of whitespace or newline */ /* (this is much more laxist than original markdown syntax) */ while (i < size && _isspace(data[i])) i++; /* inline style link */ if (i < size && data[i] == '(') { /* skipping initial whitespace */ i++; while (i < size && _isspace(data[i])) i++; link_b = i; /* looking for link end: ' " ) */ while (i < size) { if (data[i] == '\\') i += 2; else if (data[i] == ')') break; else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break; else i++; } if (i >= size) goto cleanup; link_e = i; /* looking for title end if present */ if (data[i] == '\'' || data[i] == '"') { qtype = data[i]; in_title = 1; i++; title_b = i; while (i < size) { if (data[i] == '\\') i += 2; else if (data[i] == qtype) {in_title = 0; i++;} else if ((data[i] == ')') && !in_title) break; else i++; } if (i >= size) goto cleanup; /* skipping whitespaces after title */ title_e = i - 1; while (title_e > title_b && _isspace(data[title_e])) title_e--; /* checking for closing quote presence */ if (data[title_e] != '\'' && data[title_e] != '"') { title_b = title_e = 0; link_e = i; } } /* remove whitespace at the end of the link */ while (link_e > link_b && _isspace(data[link_e - 1])) link_e--; /* remove optional angle brackets around the link */ if (data[link_b] == '<') link_b++; if (data[link_e - 1] == '>') link_e--; /* building escaped link and title */ if (link_e > link_b) { link = rndr_newbuf(rndr, BUFFER_SPAN); bufput(link, data + link_b, link_e - link_b); } if (title_e > title_b) { title = rndr_newbuf(rndr, BUFFER_SPAN); bufput(title, data + title_b, title_e - title_b); } i++; } /* reference style link */ else if (i < size && data[i] == '[') { struct buf id = { 0, 0, 0, 0 }; struct link_ref *lr; /* looking for the id */ i++; link_b = i; while (i < size && data[i] != ']') i++; if (i >= size) goto cleanup; link_e = i; /* finding the link_ref */ if (link_b == link_e) { if (text_has_nl) { struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN); size_t j; for (j = 1; j < txt_e; j++) { if (data[j] != '\n') bufputc(b, data[j]); else if (data[j - 1] != ' ') bufputc(b, ' '); } id.data = b->data; id.size = b->size; } else { id.data = data + 1; id.size = txt_e - 1; } } else { id.data = data + link_b; id.size = link_e - link_b; } lr = find_link_ref(rndr->refs, id.data, id.size); if (!lr) goto cleanup; /* keeping link and title from link_ref */ link = lr->link; title = lr->title; i++; } /* shortcut reference style link */ else { struct buf id = { 0, 0, 0, 0 }; struct link_ref *lr; /* crafting the id */ if (text_has_nl) { struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN); size_t j; for (j = 1; j < txt_e; j++) { if (data[j] != '\n') bufputc(b, data[j]); else if (data[j - 1] != ' ') bufputc(b, ' '); } id.data = b->data; id.size = b->size; } else { id.data = data + 1; id.size = txt_e - 1; } /* finding the link_ref */ lr = find_link_ref(rndr->refs, id.data, id.size); if (!lr) goto cleanup; /* keeping link and title from link_ref */ link = lr->link; title = lr->title; /* rewinding the whitespace */ i = txt_e + 1; } /* building content: img alt is escaped, link content is parsed */ if (txt_e > 1) { content = rndr_newbuf(rndr, BUFFER_SPAN); if (is_img) { bufput(content, data + 1, txt_e - 1); } else { /* disable autolinking when parsing inline the * content of a link */ rndr->in_link_body = 1; parse_inline(content, rndr, data + 1, txt_e - 1); rndr->in_link_body = 0; } } if (link) { u_link = rndr_newbuf(rndr, BUFFER_SPAN); unscape_text(u_link, link); } /* calling the relevant rendering function */ if (is_img) { if (ob->size && ob->data[ob->size - 1] == '!') ob->size -= 1; ret = rndr->cb.image(ob, u_link, title, content, rndr->opaque); } else { ret = rndr->cb.link(ob, u_link, title, content, rndr->opaque); } /* cleanup */ cleanup: rndr->work_bufs[BUFFER_SPAN].size = (int)org_work_size; return ret ? i : 0; } static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size) { size_t sup_start, sup_len; struct buf *sup; if (!rndr->cb.superscript) return 0; if (size < 2) return 0; if (data[1] == '(') { sup_start = sup_len = 2; while (sup_len < size && data[sup_len] != ')' && data[sup_len - 1] != '\\') sup_len++; if (sup_len == size) return 0; } else { sup_start = sup_len = 1; while (sup_len < size && !_isspace(data[sup_len])) sup_len++; } if (sup_len - sup_start == 0) return (sup_start == 2) ? 3 : 0; sup = rndr_newbuf(rndr, BUFFER_SPAN); parse_inline(sup, rndr, data + sup_start, sup_len - sup_start); rndr->cb.superscript(ob, sup, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); return (sup_start == 2) ? sup_len + 1 : sup_len; } /********************************* * BLOCK-LEVEL PARSING FUNCTIONS * *********************************/ /* is_empty • returns the line length when it is empty, 0 otherwise */ static size_t is_empty(uint8_t *data, size_t size) { size_t i; for (i = 0; i < size && data[i] != '\n'; i++) if (data[i] != ' ') return 0; return i + 1; } /* is_hrule • returns whether a line is a horizontal rule */ static int is_hrule(uint8_t *data, size_t size) { size_t i = 0, n = 0; uint8_t c; /* skipping initial spaces */ if (size < 3) return 0; if (data[0] == ' ') { i++; if (data[1] == ' ') { i++; if (data[2] == ' ') { i++; } } } /* looking at the hrule uint8_t */ if (i + 2 >= size || (data[i] != '*' && data[i] != '-' && data[i] != '_')) return 0; c = data[i]; /* the whole line must be the char or whitespace */ while (i < size && data[i] != '\n') { if (data[i] == c) n++; else if (data[i] != ' ') return 0; i++; } return n >= 3; } /* check if a line begins with a code fence; return the * width of the code fence */ static size_t prefix_codefence(uint8_t *data, size_t size) { size_t i = 0, n = 0; uint8_t c; /* skipping initial spaces */ if (size < 3) return 0; if (data[0] == ' ') { i++; if (data[1] == ' ') { i++; if (data[2] == ' ') { i++; } } } /* looking at the hrule uint8_t */ if (i + 2 >= size || !(data[i] == '~' || data[i] == '`')) return 0; c = data[i]; /* the whole line must be the uint8_t or whitespace */ while (i < size && data[i] == c) { n++; i++; } if (n < 3) return 0; return i; } /* check if a line is a code fence; return its size if it is */ static size_t is_codefence(uint8_t *data, size_t size, struct buf *syntax) { size_t i = 0, syn_len = 0; uint8_t *syn_start; i = prefix_codefence(data, size); if (i == 0) return 0; while (i < size && data[i] == ' ') i++; syn_start = data + i; if (i < size && data[i] == '{') { i++; syn_start++; while (i < size && data[i] != '}' && data[i] != '\n') { syn_len++; i++; } if (i == size || data[i] != '}') return 0; /* strip all whitespace at the beginning and the end * of the {} block */ while (syn_len > 0 && _isspace(syn_start[0])) { syn_start++; syn_len--; } while (syn_len > 0 && _isspace(syn_start[syn_len - 1])) syn_len--; i++; } else { while (i < size && !_isspace(data[i])) { syn_len++; i++; } } if (syntax) { syntax->data = syn_start; syntax->size = syn_len; } while (i < size && data[i] != '\n') { if (!_isspace(data[i])) return 0; i++; } return i + 1; } /* is_atxheader • returns whether the line is a hash-prefixed header */ static int is_atxheader(struct sd_markdown *rndr, uint8_t *data, size_t size) { if (data[0] != '#') return 0; if (rndr->ext_flags & MKDEXT_SPACE_HEADERS) { size_t level = 0; while (level < size && level < 6 && data[level] == '#') level++; if (level < size && data[level] != ' ') return 0; } return 1; } /* is_headerline • returns whether the line is a setext-style hdr underline */ static int is_headerline(uint8_t *data, size_t size) { size_t i = 0; /* test of level 1 header */ if (data[i] == '=') { for (i = 1; i < size && data[i] == '='; i++); while (i < size && data[i] == ' ') i++; return (i >= size || data[i] == '\n') ? 1 : 0; } /* test of level 2 header */ if (data[i] == '-') { for (i = 1; i < size && data[i] == '-'; i++); while (i < size && data[i] == ' ') i++; return (i >= size || data[i] == '\n') ? 2 : 0; } return 0; } static int is_next_headerline(uint8_t *data, size_t size) { size_t i = 0; while (i < size && data[i] != '\n') i++; if (++i >= size) return 0; return is_headerline(data + i, size - i); } /* prefix_quote • returns blockquote prefix length */ static size_t prefix_quote(uint8_t *data, size_t size) { size_t i = 0; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == '>') { if (i + 1 < size && data[i + 1] == ' ') return i + 2; return i + 1; } return 0; } /* prefix_code • returns prefix length for block code*/ static size_t prefix_code(uint8_t *data, size_t size) { if (size > 3 && data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ') return 4; return 0; } /* prefix_oli • returns ordered list item prefix */ static size_t prefix_oli(uint8_t *data, size_t size) { size_t i = 0; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == ' ') i++; if (i >= size || data[i] < '0' || data[i] > '9') return 0; while (i < size && data[i] >= '0' && data[i] <= '9') i++; if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ') return 0; if (is_next_headerline(data + i, size - i)) return 0; return i + 2; } /* prefix_uli • returns ordered list item prefix */ static size_t prefix_uli(uint8_t *data, size_t size) { size_t i = 0; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == ' ') i++; if (i < size && data[i] == ' ') i++; if (i + 1 >= size || (data[i] != '*' && data[i] != '+' && data[i] != '-') || data[i + 1] != ' ') return 0; if (is_next_headerline(data + i, size - i)) return 0; return i + 2; } /* parse_block • parsing of one block, returning next uint8_t to parse */ static void parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size); /* parse_blockquote • handles parsing of a blockquote fragment */ static size_t parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t beg, end = 0, pre, work_size = 0; uint8_t *work_data = 0; struct buf *out = 0; out = rndr_newbuf(rndr, BUFFER_BLOCK); beg = 0; while (beg < size) { for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); pre = prefix_quote(data + beg, end - beg); if (pre) beg += pre; /* skipping prefix */ /* empty line followed by non-quote line */ else if (is_empty(data + beg, end - beg) && (end >= size || (prefix_quote(data + end, size - end) == 0 && !is_empty(data + end, size - end)))) break; if (beg < end) { /* copy into the in-place working buffer */ /* bufput(work, data + beg, end - beg); */ if (!work_data) work_data = data + beg; else if (data + beg != work_data + work_size) memmove(work_data + work_size, data + beg, end - beg); work_size += end - beg; } beg = end; } parse_block(out, rndr, work_data, work_size); if (rndr->cb.blockquote) rndr->cb.blockquote(ob, out, rndr->opaque); rndr_popbuf(rndr, BUFFER_BLOCK); return end; } static size_t parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render); /* parse_blockquote • handles parsing of a regular paragraph */ static size_t parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t i = 0, end = 0; int level = 0; struct buf work = { 0, 0, 0, 0 }; work.data = data; while (i < size) { for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; if (is_empty(data + i, size - i)) break; if ((level = is_headerline(data + i, size - i)) != 0) break; if (is_atxheader(rndr, data + i, size - i) || is_hrule(data + i, size - i) || prefix_quote(data + i, size - i)) { end = i; break; } /* * Early termination of a paragraph with the same logic * as Markdown 1.0.0. If this logic is applied, the * Markdown 1.0.3 test suite won't pass cleanly * * :: If the first character in a new line is not a letter, * let's check to see if there's some kind of block starting * here */ if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) { if (prefix_oli(data + i, size - i) || prefix_uli(data + i, size - i)) { end = i; break; } /* see if an html block starts here */ if (data[i] == '<' && rndr->cb.blockhtml && parse_htmlblock(ob, rndr, data + i, size - i, 0)) { end = i; break; } /* see if a code fence starts here */ if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && is_codefence(data + i, size - i, NULL) != 0) { end = i; break; } } i = end; } work.size = i; while (work.size && data[work.size - 1] == '\n') work.size--; if (!level) { struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK); parse_inline(tmp, rndr, work.data, work.size); if (rndr->cb.paragraph) rndr->cb.paragraph(ob, tmp, rndr->opaque); rndr_popbuf(rndr, BUFFER_BLOCK); } else { struct buf *header_work; if (work.size) { size_t beg; i = work.size; work.size -= 1; while (work.size && data[work.size] != '\n') work.size -= 1; beg = work.size + 1; while (work.size && data[work.size - 1] == '\n') work.size -= 1; if (work.size > 0) { struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK); parse_inline(tmp, rndr, work.data, work.size); if (rndr->cb.paragraph) rndr->cb.paragraph(ob, tmp, rndr->opaque); rndr_popbuf(rndr, BUFFER_BLOCK); work.data += beg; work.size = i - beg; } else work.size = i; } header_work = rndr_newbuf(rndr, BUFFER_SPAN); parse_inline(header_work, rndr, work.data, work.size); if (rndr->cb.header) rndr->cb.header(ob, header_work, (int)level, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); } return end; } /* parse_fencedcode • handles parsing of a block-level code fragment */ static size_t parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t beg, end; struct buf *work = 0; struct buf lang = { 0, 0, 0, 0 }; beg = is_codefence(data, size, &lang); if (beg == 0) return 0; work = rndr_newbuf(rndr, BUFFER_BLOCK); while (beg < size) { size_t fence_end; struct buf fence_trail = { 0, 0, 0, 0 }; fence_end = is_codefence(data + beg, size - beg, &fence_trail); if (fence_end != 0 && fence_trail.size == 0) { beg += fence_end; break; } for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); if (beg < end) { /* verbatim copy to the working buffer, escaping entities */ if (is_empty(data + beg, end - beg)) bufputc(work, '\n'); else bufput(work, data + beg, end - beg); } beg = end; } if (work->size && work->data[work->size - 1] != '\n') bufputc(work, '\n'); if (rndr->cb.blockcode) rndr->cb.blockcode(ob, work, lang.size ? &lang : NULL, rndr->opaque); rndr_popbuf(rndr, BUFFER_BLOCK); return beg; } static size_t parse_blockcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t beg, end, pre; struct buf *work = 0; work = rndr_newbuf(rndr, BUFFER_BLOCK); beg = 0; while (beg < size) { for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {}; pre = prefix_code(data + beg, end - beg); if (pre) beg += pre; /* skipping prefix */ else if (!is_empty(data + beg, end - beg)) /* non-empty non-prefixed line breaks the pre */ break; if (beg < end) { /* verbatim copy to the working buffer, escaping entities */ if (is_empty(data + beg, end - beg)) bufputc(work, '\n'); else bufput(work, data + beg, end - beg); } beg = end; } while (work->size && work->data[work->size - 1] == '\n') work->size -= 1; bufputc(work, '\n'); if (rndr->cb.blockcode) rndr->cb.blockcode(ob, work, NULL, rndr->opaque); rndr_popbuf(rndr, BUFFER_BLOCK); return beg; } /* parse_listitem • parsing of a single list item */ /* assuming initial prefix is already removed */ static size_t parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int *flags) { struct buf *work = 0, *inter = 0; size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; int in_empty = 0, has_inside_empty = 0, in_fence = 0; /* keeping track of the first indentation prefix */ while (orgpre < 3 && orgpre < size && data[orgpre] == ' ') orgpre++; beg = prefix_uli(data, size); if (!beg) beg = prefix_oli(data, size); if (!beg) return 0; /* skipping to the beginning of the following line */ end = beg; while (end < size && data[end - 1] != '\n') end++; /* getting working buffers */ work = rndr_newbuf(rndr, BUFFER_SPAN); inter = rndr_newbuf(rndr, BUFFER_SPAN); /* putting the first line into the working buffer */ bufput(work, data + beg, end - beg); beg = end; /* process the following lines */ while (beg < size) { size_t has_next_uli = 0, has_next_oli = 0; end++; while (end < size && data[end - 1] != '\n') end++; /* process an empty line */ if (is_empty(data + beg, end - beg)) { in_empty = 1; beg = end; continue; } /* calculating the indentation */ i = 0; while (i < 4 && beg + i < end && data[beg + i] == ' ') i++; pre = i; if (rndr->ext_flags & MKDEXT_FENCED_CODE) { if (is_codefence(data + beg + i, end - beg - i, NULL) != 0) in_fence = !in_fence; } /* Only check for new list items if we are **not** inside * a fenced code block */ if (!in_fence) { has_next_uli = prefix_uli(data + beg + i, end - beg - i); has_next_oli = prefix_oli(data + beg + i, end - beg - i); } /* checking for ul/ol switch */ if (in_empty && ( ((*flags & MKD_LIST_ORDERED) && has_next_uli) || (!(*flags & MKD_LIST_ORDERED) && has_next_oli))){ *flags |= MKD_LI_END; break; /* the following item must have same list type */ } /* checking for a new item */ if ((has_next_uli && !is_hrule(data + beg + i, end - beg - i)) || has_next_oli) { if (in_empty) has_inside_empty = 1; if (pre == orgpre) /* the following item must have */ break; /* the same indentation */ if (!sublist) sublist = work->size; } /* joining only indented stuff after empty lines; * note that now we only require 1 space of indentation * to continue a list */ else if (in_empty && pre == 0) { *flags |= MKD_LI_END; break; } else if (in_empty) { bufputc(work, '\n'); has_inside_empty = 1; } in_empty = 0; /* adding the line without prefix into the working buffer */ bufput(work, data + beg + i, end - beg - i); beg = end; } /* render of li contents */ if (has_inside_empty) *flags |= MKD_LI_BLOCK; if (*flags & MKD_LI_BLOCK) { /* intermediate render of block li */ if (sublist && sublist < work->size) { parse_block(inter, rndr, work->data, sublist); parse_block(inter, rndr, work->data + sublist, work->size - sublist); } else parse_block(inter, rndr, work->data, work->size); } else { /* intermediate render of inline li */ if (sublist && sublist < work->size) { parse_inline(inter, rndr, work->data, sublist); parse_block(inter, rndr, work->data + sublist, work->size - sublist); } else parse_inline(inter, rndr, work->data, work->size); } /* render of li itself */ if (rndr->cb.listitem) rndr->cb.listitem(ob, inter, *flags, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); rndr_popbuf(rndr, BUFFER_SPAN); return beg; } /* parse_list • parsing ordered or unordered list block */ static size_t parse_list(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int flags) { struct buf *work = 0; size_t i = 0, j; work = rndr_newbuf(rndr, BUFFER_BLOCK); while (i < size) { j = parse_listitem(work, rndr, data + i, size - i, &flags); i += j; if (!j || (flags & MKD_LI_END)) break; } if (rndr->cb.list) rndr->cb.list(ob, work, flags, rndr->opaque); rndr_popbuf(rndr, BUFFER_BLOCK); return i; } /* parse_atxheader • parsing of atx-style headers */ static size_t parse_atxheader(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t level = 0; size_t i, end, skip; while (level < size && level < 6 && data[level] == '#') level++; for (i = level; i < size && data[i] == ' '; i++); for (end = i; end < size && data[end] != '\n'; end++); skip = end; while (end && data[end - 1] == '#') end--; while (end && data[end - 1] == ' ') end--; if (end > i) { struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN); parse_inline(work, rndr, data + i, end - i); if (rndr->cb.header) rndr->cb.header(ob, work, (int)level, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); } return skip; } /* htmlblock_end • checking end of HTML block : [ \t]*\n[ \t*]\n */ /* returns the length on match, 0 otherwise */ static size_t htmlblock_end_tag( const char *tag, size_t tag_len, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t i, w; /* checking if tag is a match */ if (tag_len + 3 >= size || strncasecmp((char *)data + 2, tag, tag_len) != 0 || data[tag_len + 2] != '>') return 0; /* checking white lines */ i = tag_len + 3; w = 0; if (i < size && (w = is_empty(data + i, size - i)) == 0) return 0; /* non-blank after tag */ i += w; w = 0; if (i < size) w = is_empty(data + i, size - i); return i + w; } static size_t htmlblock_end(const char *curtag, struct sd_markdown *rndr, uint8_t *data, size_t size, int start_of_line) { size_t tag_size = strlen(curtag); size_t i = 1, end_tag; int block_lines = 0; while (i < size) { i++; while (i < size && !(data[i - 1] == '<' && data[i] == '/')) { if (data[i] == '\n') block_lines++; i++; } /* If we are only looking for unindented tags, skip the tag * if it doesn't follow a newline. * * The only exception to this is if the tag is still on the * initial line; in that case it still counts as a closing * tag */ if (start_of_line && block_lines > 0 && data[i - 2] != '\n') continue; if (i + 2 + tag_size >= size) break; end_tag = htmlblock_end_tag(curtag, tag_size, rndr, data + i - 1, size - i + 1); if (end_tag) return i + end_tag - 1; } return 0; } /* parse_htmlblock • parsing of inline HTML block */ static size_t parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render) { size_t i, j = 0, tag_end; const char *curtag = NULL; struct buf work = { 0, 0, 0, 0 }; work.data = data; /* identification of the opening tag */ if (size < 2 || data[0] != '<') return 0; i = 1; while (i < size && data[i] != '>' && data[i] != ' ') i++; if (i < size) curtag = find_block_tag((char *)data + 1, (int)i - 1); /* handling of special cases */ if (!curtag) { /* HTML comment, laxist form */ if (size > 5 && data[1] == '!' && data[2] == '-' && data[3] == '-') { i = 5; while (i < size && !(data[i - 2] == '-' && data[i - 1] == '-' && data[i] == '>')) i++; i++; if (i < size) j = is_empty(data + i, size - i); if (j) { work.size = i + j; if (do_render && rndr->cb.blockhtml) rndr->cb.blockhtml(ob, &work, rndr->opaque); return work.size; } } /* HR, which is the only self-closing block tag considered */ if (size > 4 && (data[1] == 'h' || data[1] == 'H') && (data[2] == 'r' || data[2] == 'R')) { i = 3; while (i < size && data[i] != '>') i++; if (i + 1 < size) { i++; j = is_empty(data + i, size - i); if (j) { work.size = i + j; if (do_render && rndr->cb.blockhtml) rndr->cb.blockhtml(ob, &work, rndr->opaque); return work.size; } } } /* no special case recognised */ return 0; } /* looking for an unindented matching closing tag */ /* followed by a blank line */ tag_end = htmlblock_end(curtag, rndr, data, size, 1); /* if not found, trying a second pass looking for indented match */ /* but not if tag is "ins" or "del" (following original Markdown.pl) */ if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) { tag_end = htmlblock_end(curtag, rndr, data, size, 0); } if (!tag_end) return 0; /* the end of the block has been found */ work.size = tag_end; if (do_render && rndr->cb.blockhtml) rndr->cb.blockhtml(ob, &work, rndr->opaque); return tag_end; } static void parse_table_row( struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, size_t columns, int *col_data, int header_flag) { size_t i = 0, col; struct buf *row_work = 0; if (!rndr->cb.table_cell || !rndr->cb.table_row) return; row_work = rndr_newbuf(rndr, BUFFER_SPAN); if (i < size && data[i] == '|') i++; for (col = 0; col < columns && i < size; ++col) { size_t cell_start, cell_end; struct buf *cell_work; cell_work = rndr_newbuf(rndr, BUFFER_SPAN); while (i < size && _isspace(data[i])) i++; cell_start = i; while (i < size && data[i] != '|') i++; cell_end = i - 1; while (cell_end > cell_start && _isspace(data[cell_end])) cell_end--; parse_inline(cell_work, rndr, data + cell_start, 1 + cell_end - cell_start); rndr->cb.table_cell(row_work, cell_work, col_data[col] | header_flag, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); i++; } for (; col < columns; ++col) { struct buf empty_cell = { 0, 0, 0, 0 }; rndr->cb.table_cell(row_work, &empty_cell, col_data[col] | header_flag, rndr->opaque); } rndr->cb.table_row(ob, row_work, rndr->opaque); rndr_popbuf(rndr, BUFFER_SPAN); } static size_t parse_table_header( struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, size_t *columns, int **column_data) { int pipes; size_t i = 0, col, header_end, under_end; pipes = 0; while (i < size && data[i] != '\n') if (data[i++] == '|') pipes++; if (i == size || pipes == 0) return 0; header_end = i; while (header_end > 0 && _isspace(data[header_end - 1])) header_end--; if (data[0] == '|') pipes--; if (header_end && data[header_end - 1] == '|') pipes--; *columns = pipes + 1; *column_data = calloc(*columns, sizeof(int)); /* Parse the header underline */ i++; if (i < size && data[i] == '|') i++; under_end = i; while (under_end < size && data[under_end] != '\n') under_end++; for (col = 0; col < *columns && i < under_end; ++col) { size_t dashes = 0; while (i < under_end && data[i] == ' ') i++; if (data[i] == ':') { i++; (*column_data)[col] |= MKD_TABLE_ALIGN_L; dashes++; } while (i < under_end && data[i] == '-') { i++; dashes++; } if (i < under_end && data[i] == ':') { i++; (*column_data)[col] |= MKD_TABLE_ALIGN_R; dashes++; } while (i < under_end && data[i] == ' ') i++; if (i < under_end && data[i] != '|') break; if (dashes < 3) break; i++; } if (col < *columns) return 0; parse_table_row( ob, rndr, data, header_end, *columns, *column_data, MKD_TABLE_HEADER ); return under_end + 1; } static size_t parse_table( struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t i; struct buf *header_work = 0; struct buf *body_work = 0; size_t columns; int *col_data = NULL; header_work = rndr_newbuf(rndr, BUFFER_SPAN); body_work = rndr_newbuf(rndr, BUFFER_BLOCK); i = parse_table_header(header_work, rndr, data, size, &columns, &col_data); if (i > 0) { while (i < size) { size_t row_start; int pipes = 0; row_start = i; while (i < size && data[i] != '\n') if (data[i++] == '|') pipes++; if (pipes == 0 || i == size) { i = row_start; break; } parse_table_row( body_work, rndr, data + row_start, i - row_start, columns, col_data, 0 ); i++; } if (rndr->cb.table) rndr->cb.table(ob, header_work, body_work, rndr->opaque); } free(col_data); rndr_popbuf(rndr, BUFFER_SPAN); rndr_popbuf(rndr, BUFFER_BLOCK); return i; } /* parse_block • parsing of one block, returning next uint8_t to parse */ static void parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size) { size_t beg, end, i; uint8_t *txt_data; beg = 0; if (rndr->work_bufs[BUFFER_SPAN].size + rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting) return; while (beg < size) { txt_data = data + beg; end = size - beg; if (is_atxheader(rndr, txt_data, end)) beg += parse_atxheader(ob, rndr, txt_data, end); else if (data[beg] == '<' && rndr->cb.blockhtml && (i = parse_htmlblock(ob, rndr, txt_data, end, 1)) != 0) beg += i; else if ((i = is_empty(txt_data, end)) != 0) beg += i; else if (is_hrule(txt_data, end)) { if (rndr->cb.hrule) rndr->cb.hrule(ob, rndr->opaque); while (beg < size && data[beg] != '\n') beg++; beg++; } else if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && (i = parse_fencedcode(ob, rndr, txt_data, end)) != 0) beg += i; else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 && (i = parse_table(ob, rndr, txt_data, end)) != 0) beg += i; else if (prefix_quote(txt_data, end)) beg += parse_blockquote(ob, rndr, txt_data, end); else if (prefix_code(txt_data, end)) beg += parse_blockcode(ob, rndr, txt_data, end); else if (prefix_uli(txt_data, end)) beg += parse_list(ob, rndr, txt_data, end, 0); else if (prefix_oli(txt_data, end)) beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); else beg += parse_paragraph(ob, rndr, txt_data, end); } } /********************* * REFERENCE PARSING * *********************/ /* is_ref • returns whether a line is a reference or not */ static int is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_ref **refs) { /* int n; */ size_t i = 0; size_t id_offset, id_end; size_t link_offset, link_end; size_t title_offset, title_end; size_t line_end; /* up to 3 optional leading spaces */ if (beg + 3 >= end) return 0; if (data[beg] == ' ') { i = 1; if (data[beg + 1] == ' ') { i = 2; if (data[beg + 2] == ' ') { i = 3; if (data[beg + 3] == ' ') return 0; } } } i += beg; /* id part: anything but a newline between brackets */ if (data[i] != '[') return 0; i++; id_offset = i; while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') i++; if (i >= end || data[i] != ']') return 0; id_end = i; /* spacer: colon (space | tab)* newline? (space | tab)* */ i++; if (i >= end || data[i] != ':') return 0; i++; while (i < end && data[i] == ' ') i++; if (i < end && (data[i] == '\n' || data[i] == '\r')) { i++; if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; } while (i < end && data[i] == ' ') i++; if (i >= end) return 0; /* link: whitespace-free sequence, optionally between angle brackets */ if (data[i] == '<') i++; link_offset = i; while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r') i++; if (data[i - 1] == '>') link_end = i - 1; else link_end = i; /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ while (i < end && data[i] == ' ') i++; if (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(') return 0; line_end = 0; /* computing end-of-line */ if (i >= end || data[i] == '\r' || data[i] == '\n') line_end = i; if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') line_end = i + 1; /* optional (space|tab)* spacer after a newline */ if (line_end) { i = line_end + 1; while (i < end && data[i] == ' ') i++; } /* optional title: any non-newline sequence enclosed in '"() alone on its line */ title_offset = title_end = 0; if (i + 1 < end && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { i++; title_offset = i; /* looking for EOL */ while (i < end && data[i] != '\n' && data[i] != '\r') i++; if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') title_end = i + 1; else title_end = i; /* stepping back */ i -= 1; while (i > title_offset && data[i] == ' ') i -= 1; if (i > title_offset && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { line_end = title_end; title_end = i; } } if (!line_end || link_end == link_offset) return 0; /* garbage after the link empty link */ /* a valid ref has been found, filling-in return structures */ if (last) *last = line_end; if (refs) { struct link_ref *ref; ref = add_link_ref(refs, data + id_offset, id_end - id_offset); if (!ref) return 0; ref->link = bufnew(link_end - link_offset); bufput(ref->link, data + link_offset, link_end - link_offset); if (title_end > title_offset) { ref->title = bufnew(title_end - title_offset); bufput(ref->title, data + title_offset, title_end - title_offset); } } return 1; } static void expand_tabs(struct buf *ob, const uint8_t *line, size_t size) { size_t i = 0, tab = 0; while (i < size) { size_t org = i; while (i < size && line[i] != '\t') { i++; tab++; } if (i > org) bufput(ob, line + org, i - org); if (i >= size) break; do { bufputc(ob, ' '); tab++; } while (tab % 4); i++; } } /********************** * EXPORTED FUNCTIONS * **********************/ struct sd_markdown * sd_markdown_new( unsigned int extensions, size_t max_nesting, const struct sd_callbacks *callbacks, void *opaque) { struct sd_markdown *md = NULL; assert(max_nesting > 0 && callbacks); md = malloc(sizeof(struct sd_markdown)); if (!md) return NULL; memcpy(&md->cb, callbacks, sizeof(struct sd_callbacks)); stack_init(&md->work_bufs[BUFFER_BLOCK], 4); stack_init(&md->work_bufs[BUFFER_SPAN], 8); memset(md->active_char, 0x0, 256); if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) { md->active_char['*'] = MD_CHAR_EMPHASIS; md->active_char['_'] = MD_CHAR_EMPHASIS; if (extensions & MKDEXT_STRIKETHROUGH) md->active_char['~'] = MD_CHAR_EMPHASIS; } if (md->cb.codespan) md->active_char['`'] = MD_CHAR_CODESPAN; if (md->cb.linebreak) md->active_char['\n'] = MD_CHAR_LINEBREAK; if (md->cb.image || md->cb.link) md->active_char['['] = MD_CHAR_LINK; md->active_char['<'] = MD_CHAR_LANGLE; md->active_char['\\'] = MD_CHAR_ESCAPE; md->active_char['&'] = MD_CHAR_ENTITITY; if (extensions & MKDEXT_AUTOLINK) { md->active_char[':'] = MD_CHAR_AUTOLINK_URL; md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; md->active_char['w'] = MD_CHAR_AUTOLINK_WWW; } if (extensions & MKDEXT_SUPERSCRIPT) md->active_char['^'] = MD_CHAR_SUPERSCRIPT; if (extensions & MKDEXT_LATEX_MATH) md->active_char['$'] = MD_CHAR_DOLLAR; /* Extension data */ md->ext_flags = extensions; md->opaque = opaque; md->max_nesting = max_nesting; md->in_link_body = 0; return md; } void sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md) { #define MARKDOWN_GROW(x) ((x) + ((x) >> 1)) static const uint8_t UTF8_BOM[] = {0xEF, 0xBB, 0xBF}; struct buf *text; size_t beg, end; text = bufnew(64); if (!text) return; /* Preallocate enough space for our buffer to avoid expanding while copying */ bufgrow(text, doc_size); /* reset the references table */ memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); /* first pass: looking for references, copying everything else */ beg = 0; /* Skip a possible UTF-8 BOM, even though the Unicode standard * discourages having these in UTF-8 documents */ if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0) beg += 3; while (beg < doc_size) /* iterating over lines */ if (is_ref(document, beg, doc_size, &end, md->refs)) beg = end; else { /* skipping to the next line */ end = beg; while (end < doc_size && document[end] != '\n' && document[end] != '\r') end++; /* adding the line body if present */ if (end > beg) expand_tabs(text, document + beg, end - beg); while (end < doc_size && (document[end] == '\n' || document[end] == '\r')) { /* add one \n per newline */ if (document[end] == '\n' || (end + 1 < doc_size && document[end + 1] != '\n')) bufputc(text, '\n'); end++; } beg = end; } /* pre-grow the output buffer to minimize allocations */ bufgrow(ob, MARKDOWN_GROW(text->size)); /* second pass: actual rendering */ if (md->cb.doc_header) md->cb.doc_header(ob, md->opaque); if (text->size) { /* adding a final newline if not already present */ if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r') bufputc(text, '\n'); parse_block(ob, md, text->data, text->size); } if (md->cb.doc_footer) md->cb.doc_footer(ob, md->opaque); /* clean-up */ bufrelease(text); free_link_refs(md->refs); assert(md->work_bufs[BUFFER_SPAN].size == 0); assert(md->work_bufs[BUFFER_BLOCK].size == 0); } void sd_markdown_free(struct sd_markdown *md) { size_t i; for (i = 0; i < (size_t)md->work_bufs[BUFFER_SPAN].asize; ++i) bufrelease(md->work_bufs[BUFFER_SPAN].item[i]); for (i = 0; i < (size_t)md->work_bufs[BUFFER_BLOCK].asize; ++i) bufrelease(md->work_bufs[BUFFER_BLOCK].item[i]); stack_free(&md->work_bufs[BUFFER_SPAN]); stack_free(&md->work_bufs[BUFFER_BLOCK]); free(md); } void sd_version(int *ver_major, int *ver_minor, int *ver_revision) { *ver_major = SUNDOWN_VER_MAJOR; *ver_minor = SUNDOWN_VER_MINOR; *ver_revision = SUNDOWN_VER_REVISION; } /* vim: set filetype=c: */ markdown/src/autolink.c0000644000175100001440000001303213075742411014676 0ustar hornikusers/* * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "buffer.h" #include #include #include #include #if defined(_WIN32) #define strncasecmp _strnicmp #endif int sd_autolink_issafe(const uint8_t *link, size_t link_len) { static const size_t valid_uris_count = 5; static const char *valid_uris[] = { "/", "http://", "https://", "ftp://", "mailto:" }; size_t i; for (i = 0; i < valid_uris_count; ++i) { size_t len = strlen(valid_uris[i]); if (link_len > len && strncasecmp((char *)link, valid_uris[i], len) == 0 && isalnum(link[len])) return 1; } return 0; } static size_t autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size) { uint8_t cclose, copen = 0; size_t i; for (i = 0; i < link_end; ++i) if (data[i] == '<') { link_end = i; break; } while (link_end > 0) { if (strchr("?!.,", data[link_end - 1]) != NULL) link_end--; else if (data[link_end - 1] == ';') { size_t new_end = link_end - 2; while (new_end > 0 && isalpha(data[new_end])) new_end--; if (new_end < link_end - 2 && data[new_end] == '&') link_end = new_end; else link_end--; } else break; } if (link_end == 0) return 0; cclose = data[link_end - 1]; switch (cclose) { case '"': copen = '"'; break; case '\'': copen = '\''; break; case ')': copen = '('; break; case ']': copen = '['; break; case '}': copen = '{'; break; } if (copen != 0) { size_t closing = 0; size_t opening = 0; size_t i = 0; /* Try to close the final punctuation sign in this same line; * if we managed to close it outside of the URL, that means that it's * not part of the URL. If it closes inside the URL, that means it * is part of the URL. * * Examples: * * foo http://www.pokemon.com/Pikachu_(Electric) bar * => http://www.pokemon.com/Pikachu_(Electric) * * foo (http://www.pokemon.com/Pikachu_(Electric)) bar * => http://www.pokemon.com/Pikachu_(Electric) * * foo http://www.pokemon.com/Pikachu_(Electric)) bar * => http://www.pokemon.com/Pikachu_(Electric)) * * (foo http://www.pokemon.com/Pikachu_(Electric)) bar * => foo http://www.pokemon.com/Pikachu_(Electric) */ while (i < link_end) { if (data[i] == copen) opening++; else if (data[i] == cclose) closing++; i++; } if (closing != opening) link_end--; } return link_end; } static size_t check_domain(uint8_t *data, size_t size) { size_t i, np = 0; if (!isalnum(data[0])) return 0; for (i = 1; i < size - 1; ++i) { if (data[i] == '.') np++; else if (!isalnum(data[i]) && data[i] != '-') break; } /* a valid domain needs to have at least a dot. * that's as far as we get */ return np ? i : 0; } size_t sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { size_t link_end; if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1])) return 0; if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) return 0; link_end = check_domain(data, size); if (link_end == 0) return 0; while (link_end < size && !isspace(data[link_end])) link_end++; link_end = autolink_delim(data, link_end, offset, size); if (link_end == 0) return 0; bufput(link, data, link_end); *rewind_p = 0; return (int)link_end; } size_t sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { size_t link_end, rewind; int nb = 0, np = 0; for (rewind = 0; rewind < offset; ++rewind) { uint8_t c = data[-rewind - 1]; if (isalnum(c)) continue; if (strchr(".+-_", c) != NULL) continue; break; } if (rewind == 0) return 0; for (link_end = 0; link_end < size; ++link_end) { uint8_t c = data[link_end]; if (isalnum(c)) continue; if (c == '@') nb++; else if (c == '.' && link_end < size - 1) np++; else if (c != '-' && c != '_') break; } if (link_end < 2 || nb != 1 || np == 0) return 0; link_end = autolink_delim(data, link_end, offset, size); if (link_end == 0) return 0; bufput(link, data - rewind, link_end + rewind); *rewind_p = rewind; return link_end; } size_t sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { size_t link_end, rewind = 0, domain_len; if (size < 4 || data[1] != '/' || data[2] != '/') return 0; while (rewind < offset && isalpha(data[-rewind - 1])) rewind++; if (!sd_autolink_issafe(data - rewind, size + rewind)) return 0; link_end = strlen("://"); domain_len = check_domain(data + link_end, size - link_end); if (domain_len == 0) return 0; link_end += domain_len; while (link_end < size && !isspace(data[link_end])) link_end++; link_end = autolink_delim(data, link_end, offset, size); if (link_end == 0) return 0; bufput(link, data - rewind, link_end + rewind); *rewind_p = rewind; return link_end; } markdown/src/houdini_html_e.c0000644000175100001440000000377513075742411016054 0ustar hornikusers#include #include #include #include "houdini.h" #define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) /* this is very scientific, yes */ /** * According to the OWASP rules: * * & --> & * < --> < * > --> > * " --> " * ' --> ' ' is not recommended * / --> / forward slash is included as it helps end an HTML entity * */ static const char HTML_ESCAPE_TABLE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const char *HTML_ESCAPES[] = { "", """, "&", "'", "/", "<", ">" }; void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure) { size_t i = 0, org, esc = 0; bufgrow(ob, ESCAPE_GROW_FACTOR(size)); while (i < size) { org = i; while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) i++; if (i > org) bufput(ob, src + org, i - org); /* escaping */ if (i >= size) break; /* The forward slash is only escaped in secure mode */ if (src[i] == '/' && !secure) { bufputc(ob, '/'); } else { bufputs(ob, HTML_ESCAPES[esc]); } i++; } } void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size) { houdini_escape_html0(ob, src, size, 1); } markdown/src/html_blocks.h0000644000175100001440000001532213075742411015362 0ustar hornikusers/* C code produced by gperf version 3.0.3 */ /* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */ /* Computed positions: -k'1-2' */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) /* The character set is not based on ISO-646. */ error "gperf generated tables don't work with this execution character set. Please report a bug to ." #endif /* maximum key range = 37, duplicates = 0 */ #ifndef GPERF_DOWNCASE #define GPERF_DOWNCASE 1 static unsigned char gperf_downcase[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; #endif #ifndef GPERF_CASE_STRNCMP #define GPERF_CASE_STRNCMP 1 static int gperf_case_strncmp (s1, s2, n) register const char *s1; register const char *s2; register unsigned int n; { for (; n > 0;) { unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; if (c1 != 0 && c1 == c2) { n--; continue; } return (int)c1 - (int)c2; } return 0; } #endif #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static unsigned int hash_block_tag (str, len) register const char *str; register unsigned int len; { static const unsigned char asso_values[] = { 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 8, 30, 25, 20, 15, 10, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 0, 38, 0, 38, 5, 5, 5, 15, 0, 38, 38, 0, 15, 10, 0, 38, 38, 15, 0, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 0, 38, 0, 38, 5, 5, 5, 15, 0, 38, 38, 0, 15, 10, 0, 38, 38, 15, 0, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38 }; register int hval = len; switch (hval) { default: hval += asso_values[(unsigned char)str[1]+1]; /*FALLTHROUGH*/ case 1: hval += asso_values[(unsigned char)str[0]]; break; } return hval; } #ifdef __GNUC__ __inline #ifdef __GNUC_STDC_INLINE__ __attribute__ ((__gnu_inline__)) #endif #endif const char * find_block_tag (str, len) register const char *str; register unsigned int len; { enum { TOTAL_KEYWORDS = 24, MIN_WORD_LENGTH = 1, MAX_WORD_LENGTH = 10, MIN_HASH_VALUE = 1, MAX_HASH_VALUE = 37 }; static const char * const wordlist[] = { "", "p", "dl", "div", "math", "table", "", "ul", "del", "form", "blockquote", "figure", "ol", "fieldset", "", "h1", "", "h6", "pre", "", "", "script", "h5", "noscript", "", "style", "iframe", "h4", "ins", "", "", "", "h3", "", "", "", "", "h2" }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { register int key = hash_block_tag (str, len); if (key <= MAX_HASH_VALUE && key >= 0) { register const char *s = wordlist[key]; if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') return s; } } return 0; } markdown/src/stack.h0000644000175100001440000000064213075742411014165 0ustar hornikusers#ifndef STACK_H__ #define STACK_H__ #include #ifdef __cplusplus extern "C" { #endif struct stack { void **item; size_t size; size_t asize; }; void stack_free(struct stack *); int stack_grow(struct stack *, size_t); int stack_init(struct stack *, size_t); int stack_push(struct stack *, void *); void *stack_pop(struct stack *); void *stack_top(struct stack *); #ifdef __cplusplus } #endif #endif markdown/src/html_smartypants.c0000644000175100001440000002514213075742411016466 0ustar hornikusers/* * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "buffer.h" #include "html.h" #include #include #include #include #if defined(_WIN32) #define snprintf _snprintf #endif struct smartypants_data { int in_squote; int in_dquote; }; static size_t smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t smartypants_cb__escape(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size); static size_t (*smartypants_cb_ptrs[]) (struct buf *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) = { NULL, /* 0 */ smartypants_cb__dash, /* 1 */ smartypants_cb__parens, /* 2 */ smartypants_cb__squote, /* 3 */ smartypants_cb__dquote, /* 4 */ smartypants_cb__amp, /* 5 */ smartypants_cb__period, /* 6 */ smartypants_cb__number, /* 7 */ smartypants_cb__ltag, /* 8 */ smartypants_cb__backtick, /* 9 */ smartypants_cb__escape, /* 10 */ }; static const uint8_t smartypants_cb_chars[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static inline int word_boundary(uint8_t c) { return c == 0 || isspace(c) || ispunct(c); } static int smartypants_quotes(struct buf *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open) { char ent[8]; if (*is_open && !word_boundary(next_char)) return 0; if (!(*is_open) && !word_boundary(previous_char)) return 0; snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote); *is_open = !(*is_open); bufputs(ob, ent); return 1; } static size_t smartypants_cb__squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size >= 2) { uint8_t t1 = tolower(text[1]); if (t1 == '\'') { if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) return 1; } if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (size == 3 || word_boundary(text[2]))) { BUFPUTSL(ob, "’"); return 0; } if (size >= 3) { uint8_t t2 = tolower(text[2]); if (((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) && (size == 4 || word_boundary(text[3]))) { BUFPUTSL(ob, "’"); return 0; } } } if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote)) return 0; bufputc(ob, text[0]); return 0; } static size_t smartypants_cb__parens(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size >= 3) { uint8_t t1 = tolower(text[1]); uint8_t t2 = tolower(text[2]); if (t1 == 'c' && t2 == ')') { BUFPUTSL(ob, "©"); return 2; } if (t1 == 'r' && t2 == ')') { BUFPUTSL(ob, "®"); return 2; } if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') { BUFPUTSL(ob, "™"); return 3; } } bufputc(ob, text[0]); return 0; } static size_t smartypants_cb__dash(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size >= 3 && text[1] == '-' && text[2] == '-') { BUFPUTSL(ob, "—"); return 2; } if (size >= 2 && text[1] == '-') { BUFPUTSL(ob, "–"); return 1; } bufputc(ob, text[0]); return 0; } static size_t smartypants_cb__amp(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size >= 6 && memcmp(text, """, 6) == 0) { if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote)) return 5; } if (size >= 4 && memcmp(text, "�", 4) == 0) return 3; bufputc(ob, '&'); return 0; } static size_t smartypants_cb__period(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size >= 3 && text[1] == '.' && text[2] == '.') { BUFPUTSL(ob, "…"); return 2; } if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') { BUFPUTSL(ob, "…"); return 4; } bufputc(ob, text[0]); return 0; } static size_t smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size >= 2 && text[1] == '`') { if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote)) return 1; } return 0; } static size_t smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (word_boundary(previous_char) && size >= 3) { if (text[0] == '1' && text[1] == '/' && text[2] == '2') { if (size == 3 || word_boundary(text[3])) { BUFPUTSL(ob, "½"); return 2; } } if (text[0] == '1' && text[1] == '/' && text[2] == '4') { if (size == 3 || word_boundary(text[3]) || (size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) { BUFPUTSL(ob, "¼"); return 2; } } if (text[0] == '3' && text[1] == '/' && text[2] == '4') { if (size == 3 || word_boundary(text[3]) || (size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) { BUFPUTSL(ob, "¾"); return 2; } } } bufputc(ob, text[0]); return 0; } static size_t smartypants_cb__dquote(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote)) BUFPUTSL(ob, """); return 0; } static size_t smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { static const char *skip_tags[] = { "pre", "code", "var", "samp", "kbd", "math", "script", "style" }; static const size_t skip_tags_count = 8; size_t tag, i = 0; while (i < size && text[i] != '>') i++; for (tag = 0; tag < skip_tags_count; ++tag) { if (sdhtml_is_tag(text, size, skip_tags[tag]) == HTML_TAG_OPEN) break; } if (tag < skip_tags_count) { for (;;) { while (i < size && text[i] != '<') i++; if (i == size) break; if (sdhtml_is_tag(text + i, size - i, skip_tags[tag]) == HTML_TAG_CLOSE) break; i++; } while (i < size && text[i] != '>') i++; } bufput(ob, text, i + 1); return i; } static size_t smartypants_cb__escape(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size) { if (size < 2) return 0; switch (text[1]) { case '\\': case '"': case '\'': case '.': case '-': case '`': bufputc(ob, text[1]); return 1; default: bufputc(ob, '\\'); return 0; } } #if 0 static struct { uint8_t c0; const uint8_t *pattern; const uint8_t *entity; int skip; } smartypants_subs[] = { { '\'', "'s>", "’", 0 }, { '\'', "'t>", "’", 0 }, { '\'', "'re>", "’", 0 }, { '\'', "'ll>", "’", 0 }, { '\'', "'ve>", "’", 0 }, { '\'', "'m>", "’", 0 }, { '\'', "'d>", "’", 0 }, { '-', "--", "—", 1 }, { '-', "<->", "–", 0 }, { '.', "...", "…", 2 }, { '.', ". . .", "…", 4 }, { '(', "(c)", "©", 2 }, { '(', "(r)", "®", 2 }, { '(', "(tm)", "™", 3 }, { '3', "<3/4>", "¾", 2 }, { '3', "<3/4ths>", "¾", 2 }, { '1', "<1/2>", "½", 2 }, { '1', "<1/4>", "¼", 2 }, { '1', "<1/4th>", "¼", 2 }, { '&', "�", 0, 3 }, }; #endif void sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size) { size_t i; struct smartypants_data smrt = {0, 0}; if (!text) return; bufgrow(ob, size); for (i = 0; i < size; ++i) { size_t org; uint8_t action = 0; org = i; while (i < size && (action = smartypants_cb_chars[text[i]]) == 0) i++; if (i > org) bufput(ob, text + org, i - org); if (i < size) { i += smartypants_cb_ptrs[(int)action] (ob, &smrt, i ? text[i - 1] : 0, text + i, size - i); } } } markdown/src/html.h0000644000175100001440000000367313075742411014033 0ustar hornikusers/* * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef UPSKIRT_HTML_H #define UPSKIRT_HTML_H #include "markdown.h" #include "buffer.h" #include #ifdef __cplusplus extern "C" { #endif struct html_renderopt { struct { int header_count; int current_level; int level_offset; } toc_data; unsigned int flags; /* extra callbacks */ void (*link_attributes)(struct buf *ob, const struct buf *url, void *self); }; typedef enum { HTML_SKIP_HTML = (1 << 0), HTML_SKIP_STYLE = (1 << 1), HTML_SKIP_IMAGES = (1 << 2), HTML_SKIP_LINKS = (1 << 3), HTML_EXPAND_TABS = (1 << 4), HTML_SAFELINK = (1 << 5), HTML_TOC = (1 << 6), HTML_HARD_WRAP = (1 << 7), HTML_USE_XHTML = (1 << 8), HTML_ESCAPE = (1 << 9) } html_render_mode; typedef enum { HTML_TAG_NONE = 0, HTML_TAG_OPEN, HTML_TAG_CLOSE } html_tag; int sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname); extern void sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags); extern void sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr); extern void sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size); #ifdef __cplusplus } #endif #endif markdown/src/autolink.h0000644000175100001440000000252113075742411014704 0ustar hornikusers/* * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef UPSKIRT_AUTOLINK_H #define UPSKIRT_AUTOLINK_H #include "buffer.h" #ifdef __cplusplus extern "C" { #endif extern int sd_autolink_issafe(const uint8_t *link, size_t link_len); extern size_t sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); extern size_t sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); extern size_t sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size); #ifdef __cplusplus } #endif #endif /* vim: set filetype=c: */ markdown/src/html.c0000644000175100001440000003462113075742411014023 0ustar hornikusers/* * Copyright (c) 2009, Natacha Porté * Copyright (c) 2011, Vicent Marti * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "markdown.h" #include "html.h" #include #include #include #include #include "houdini.h" #define USE_XHTML(opt) (opt->flags & HTML_USE_XHTML) int sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname) { size_t i; int closed = 0; if (tag_size < 3 || tag_data[0] != '<') return HTML_TAG_NONE; i = 1; if (tag_data[i] == '/') { closed = 1; i++; } for (; i < tag_size; ++i, ++tagname) { if (*tagname == 0) break; if (tag_data[i] != *tagname) return HTML_TAG_NONE; } if (i == tag_size) return HTML_TAG_NONE; if (isspace(tag_data[i]) || tag_data[i] == '>') return closed ? HTML_TAG_CLOSE : HTML_TAG_OPEN; return HTML_TAG_NONE; } static inline void escape_html(struct buf *ob, const uint8_t *source, size_t length) { houdini_escape_html0(ob, source, length, 0); } static inline void escape_href(struct buf *ob, const uint8_t *source, size_t length) { houdini_escape_href(ob, source, length); } /******************** * GENERIC RENDERER * ********************/ static int rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque) { struct html_renderopt *options = opaque; if (!link || !link->size) return 0; if ((options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size) && type != MKDA_EMAIL) return 0; BUFPUTSL(ob, "data, link->size); if (options->link_attributes) { bufputc(ob, '\"'); options->link_attributes(ob, link, opaque); bufputc(ob, '>'); } else { BUFPUTSL(ob, "\">"); } /* * Pretty printing: if we get an email address as * an actual URI, e.g. `mailto:foo@bar.com`, we don't * want to print the `mailto:` prefix */ if (bufprefix(link, "mailto:") == 0) { escape_html(ob, link->data + 7, link->size - 7); } else { escape_html(ob, link->data, link->size); } BUFPUTSL(ob, ""); return 1; } static void rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque) { if (ob->size) bufputc(ob, '\n'); if (lang && lang->size) { size_t i, cls; BUFPUTSL(ob, "
    size; ++i, ++cls) {
    			while (i < lang->size && isspace(lang->data[i]))
    				i++;
    
    			if (i < lang->size) {
    				size_t org = i;
    				while (i < lang->size && !isspace(lang->data[i]))
    					i++;
    
    				if (lang->data[org] == '.')
    					org++;
    
    				if (cls) bufputc(ob, ' ');
    				escape_html(ob, lang->data + org, i - org);
    			}
    		}
    
    		BUFPUTSL(ob, "\">");
    	} else
    		BUFPUTSL(ob, "
    ");
    
    	if (text)
    		escape_html(ob, text->data, text->size);
    
    	BUFPUTSL(ob, "
    \n"); } static void rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque) { if (ob->size) bufputc(ob, '\n'); BUFPUTSL(ob, "
    \n"); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "
    \n"); } static int rndr_displayedmath(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "\\["); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "\\]"); return 1; } static int rndr_inlinemath(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "\\("); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "\\)"); return 1; } static int rndr_codespan(struct buf *ob, const struct buf *text, void *opaque) { BUFPUTSL(ob, ""); if (text) escape_html(ob, text->data, text->size); BUFPUTSL(ob, ""); return 1; } static int rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, ""); bufput(ob, text->data, text->size); BUFPUTSL(ob, ""); return 1; } static int rndr_double_emphasis(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, ""); bufput(ob, text->data, text->size); BUFPUTSL(ob, ""); return 1; } static int rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, ""); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, ""); return 1; } static int rndr_linebreak(struct buf *ob, void *opaque) { struct html_renderopt *options = opaque; bufputs(ob, USE_XHTML(options) ? "
    \n" : "
    \n"); return 1; } static void rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque) { struct html_renderopt *options = opaque; if (ob->size) bufputc(ob, '\n'); if (options->flags & HTML_TOC) bufprintf(ob, "", level, options->toc_data.header_count++); else bufprintf(ob, "", level); if (text) bufput(ob, text->data, text->size); bufprintf(ob, "\n", level); } static int rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) { struct html_renderopt *options = opaque; if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size)) return 0; BUFPUTSL(ob, "size) escape_href(ob, link->data, link->size); if (title && title->size) { BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } if (options->link_attributes) { bufputc(ob, '\"'); options->link_attributes(ob, link, opaque); bufputc(ob, '>'); } else { BUFPUTSL(ob, "\">"); } if (content && content->size) bufput(ob, content->data, content->size); BUFPUTSL(ob, ""); return 1; } static void rndr_list(struct buf *ob, const struct buf *text, int flags, void *opaque) { if (ob->size) bufputc(ob, '\n'); bufput(ob, flags & MKD_LIST_ORDERED ? "
      \n" : "
        \n", 5); if (text) bufput(ob, text->data, text->size); bufput(ob, flags & MKD_LIST_ORDERED ? "
    \n" : "\n", 6); } static void rndr_listitem(struct buf *ob, const struct buf *text, int flags, void *opaque) { BUFPUTSL(ob, "
  • "); if (text) { size_t size = text->size; while (size && text->data[size - 1] == '\n') size--; bufput(ob, text->data, size); } BUFPUTSL(ob, "
  • \n"); } static void rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque) { struct html_renderopt *options = opaque; size_t i = 0; if (ob->size) bufputc(ob, '\n'); if (!text || !text->size) return; while (i < text->size && isspace(text->data[i])) i++; if (i == text->size) return; BUFPUTSL(ob, "

    "); if (options->flags & HTML_HARD_WRAP) { size_t org; while (i < text->size) { org = i; while (i < text->size && text->data[i] != '\n') i++; if (i > org) bufput(ob, text->data + org, i - org); /* * do not insert a line break if this newline * is the last character on the paragraph */ if (i >= text->size - 1) break; rndr_linebreak(ob, opaque); i++; } } else { bufput(ob, &text->data[i], text->size - i); } BUFPUTSL(ob, "

    \n"); } static void rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque) { size_t org, sz; if (!text) return; sz = text->size; while (sz > 0 && text->data[sz - 1] == '\n') sz--; org = 0; while (org < sz && text->data[org] == '\n') org++; if (org >= sz) return; if (ob->size) bufputc(ob, '\n'); bufput(ob, text->data + org, sz - org); bufputc(ob, '\n'); } static int rndr_triple_emphasis(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, ""); bufput(ob, text->data, text->size); BUFPUTSL(ob, ""); return 1; } static void rndr_hrule(struct buf *ob, void *opaque) { struct html_renderopt *options = opaque; if (ob->size) bufputc(ob, '\n'); bufputs(ob, USE_XHTML(options) ? "
    \n" : "
    \n"); } static int rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque) { struct html_renderopt *options = opaque; if (!link || !link->size) return 0; BUFPUTSL(ob, "data, link->size); BUFPUTSL(ob, "\" alt=\""); if (alt && alt->size) escape_html(ob, alt->data, alt->size); if (title && title->size) { BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">"); return 1; } static int rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque) { struct html_renderopt *options = opaque; /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES * It doens't see if there are any valid tags, just escape all of them. */ if((options->flags & HTML_ESCAPE) != 0) { escape_html(ob, text->data, text->size); return 1; } if ((options->flags & HTML_SKIP_HTML) != 0) return 1; if ((options->flags & HTML_SKIP_STYLE) != 0 && sdhtml_is_tag(text->data, text->size, "style")) return 1; if ((options->flags & HTML_SKIP_LINKS) != 0 && sdhtml_is_tag(text->data, text->size, "a")) return 1; if ((options->flags & HTML_SKIP_IMAGES) != 0 && sdhtml_is_tag(text->data, text->size, "img")) return 1; bufput(ob, text->data, text->size); return 1; } static void rndr_table(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque) { if (ob->size) bufputc(ob, '\n'); BUFPUTSL(ob, "\n"); if (header) bufput(ob, header->data, header->size); BUFPUTSL(ob, "\n"); if (body) bufput(ob, body->data, body->size); BUFPUTSL(ob, "
    \n"); } static void rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque) { BUFPUTSL(ob, "\n"); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "\n"); } static void rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque) { if (flags & MKD_TABLE_HEADER) { BUFPUTSL(ob, ""); break; case MKD_TABLE_ALIGN_L: BUFPUTSL(ob, " align=\"left\">"); break; case MKD_TABLE_ALIGN_R: BUFPUTSL(ob, " align=\"right\">"); break; default: BUFPUTSL(ob, ">"); } if (text) bufput(ob, text->data, text->size); if (flags & MKD_TABLE_HEADER) { BUFPUTSL(ob, "\n"); } else { BUFPUTSL(ob, "\n"); } } static int rndr_superscript(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, ""); bufput(ob, text->data, text->size); BUFPUTSL(ob, ""); return 1; } static void rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque) { if (text) escape_html(ob, text->data, text->size); } static void toc_header(struct buf *ob, const struct buf *text, int level, void *opaque) { struct html_renderopt *options = opaque; /* set the level offset if this is the first header * we're parsing for the document */ if (options->toc_data.current_level == 0) { options->toc_data.level_offset = level - 1; } level -= options->toc_data.level_offset; if (level > options->toc_data.current_level) { while (level > options->toc_data.current_level) { BUFPUTSL(ob, "
      \n
    • \n"); options->toc_data.current_level++; } } else if (level < options->toc_data.current_level) { BUFPUTSL(ob, "
    • \n"); while (level < options->toc_data.current_level) { BUFPUTSL(ob, "
    \n
  • \n"); options->toc_data.current_level--; } BUFPUTSL(ob,"
  • \n"); } else { BUFPUTSL(ob,"
  • \n
  • \n"); } bufprintf(ob, "", options->toc_data.header_count++); if (text) escape_html(ob, text->data, text->size); BUFPUTSL(ob, "\n"); } static int toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) { if (content && content->size) bufput(ob, content->data, content->size); return 1; } static void toc_finalize(struct buf *ob, void *opaque) { struct html_renderopt *options = opaque; while (options->toc_data.current_level > 0) { BUFPUTSL(ob, "
  • \n\n"); options->toc_data.current_level--; } } void sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options) { static const struct sd_callbacks cb_default = { NULL, NULL, NULL, toc_header, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, rndr_codespan, rndr_double_emphasis, rndr_emphasis, NULL, NULL, toc_link, NULL, rndr_triple_emphasis, rndr_strikethrough, rndr_superscript, NULL, NULL, NULL, NULL, NULL, toc_finalize, }; memset(options, 0x0, sizeof(struct html_renderopt)); options->flags = HTML_TOC; memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); } void sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags) { static const struct sd_callbacks cb_default = { rndr_blockcode, rndr_blockquote, rndr_raw_block, rndr_header, rndr_hrule, rndr_list, rndr_listitem, rndr_paragraph, rndr_table, rndr_tablerow, rndr_tablecell, rndr_autolink, rndr_codespan, rndr_double_emphasis, rndr_emphasis, rndr_image, rndr_linebreak, rndr_link, rndr_raw_html, rndr_triple_emphasis, rndr_strikethrough, rndr_superscript, rndr_inlinemath, rndr_displayedmath, NULL, rndr_normal_text, NULL, NULL, }; /* Prepare the options pointer */ memset(options, 0x0, sizeof(struct html_renderopt)); options->flags = render_flags; /* Prepare the callbacks */ memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks)); if (render_flags & HTML_SKIP_IMAGES) callbacks->image = NULL; if (render_flags & HTML_SKIP_LINKS) { callbacks->link = NULL; callbacks->autolink = NULL; } if (render_flags & HTML_SKIP_HTML || render_flags & HTML_ESCAPE) callbacks->blockhtml = NULL; } markdown/src/Rinit.c0000644000175100001440000000323213075742411014136 0ustar hornikusers/* * Rinit.c * * Copyright (C) 2009-2013 by RStudio, Inc. * * This program is licensed to you under the terms of version 2 of the * GNU General Public License. This program is distributed WITHOUT ANY * EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details. * */ #include #include "markdown.h" #include "Rmarkdown.h" #define CALLDEF(name, n) {#name,(DL_FUNC) &name, n} static R_CallMethodDef CallEntries[] = { CALLDEF(rmd_render_markdown,6), CALLDEF(rmd_registered_renderers,0), CALLDEF(rmd_render_smartypants,3), CALLDEF(rmd_b64encode_data,1), {NULL,NULL,0} }; void R_init_markdown(DllInfo *dll) { R_registerRoutines(dll,NULL,CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); rmd_init_renderer_list(); /* Callable functions from other packages' C code */ #define RREGDEF(name) R_RegisterCCallable("markdown", #name, (DL_FUNC) name) RREGDEF(bufgrow); RREGDEF(bufnew); RREGDEF(bufcstr); RREGDEF(bufprefix); RREGDEF(bufput); RREGDEF(bufputs); RREGDEF(bufputc); RREGDEF(bufrelease); RREGDEF(bufreset); RREGDEF(bufslurp); RREGDEF(bufprintf); RREGDEF(sd_autolink_issafe); RREGDEF(sd_autolink__www); RREGDEF(sd_autolink__email); RREGDEF(sd_autolink__url); RREGDEF(sd_markdown_new); RREGDEF(sd_markdown_render); RREGDEF(sd_markdown_free); RREGDEF(sd_version); /* markdown C calls */ RREGDEF(rmd_register_renderer); RREGDEF(rmd_renderer_exists); RREGDEF(rmd_input_to_buf); RREGDEF(rmd_buf_to_output); } markdown/src/buffer.h0000644000175100001440000000552213075742411014333 0ustar hornikusers/* * Copyright (c) 2008, Natacha Porté * Copyright (c) 2011, Vicent Martí * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef BUFFER_H__ #define BUFFER_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif typedef enum { BUF_OK = 0, BUF_ENOMEM = -1 } buferror_t; /* struct buf: character array buffer */ struct buf { uint8_t *data; /* actual character data */ size_t size; /* size of the string */ size_t asize; /* allocated size (0 = volatile buffer) */ size_t unit; /* reallocation unit size (0 = read-only buffer) */ }; /* CONST_BUF: global buffer from a string litteral */ #define BUF_STATIC(string) \ { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 } /* VOLATILE_BUF: macro for creating a volatile buffer on the stack */ #define BUF_VOLATILE(strname) \ { (uint8_t *)strname, strlen(strname), 0, 0, 0 } /* BUFPUTSL: optimized bufputs of a string litteral */ #define BUFPUTSL(output, literal) \ bufput(output, literal, sizeof literal - 1) /* bufgrow: increasing the allocated size to the given value */ int bufgrow(struct buf *, size_t); /* bufnew: allocation of a new buffer */ struct buf *bufnew(size_t) __attribute__ ((malloc)); /* bufnullterm: NUL-termination of the string array (making a C-string) */ const char *bufcstr(struct buf *); /* bufprefix: compare the beginning of a buffer with a string */ int bufprefix(const struct buf *buf, const char *prefix); /* bufput: appends raw data to a buffer */ void bufput(struct buf *, const void *, size_t); /* bufputs: appends a NUL-terminated string to a buffer */ void bufputs(struct buf *, const char *); /* bufputc: appends a single char to a buffer */ void bufputc(struct buf *, int); /* bufrelease: decrease the reference count and free the buffer if needed */ void bufrelease(struct buf *); /* bufreset: frees internal data of the buffer */ void bufreset(struct buf *); /* bufslurp: removes a given number of bytes from the head of the array */ void bufslurp(struct buf *, size_t); /* bufprintf: formatted printing to a buffer */ void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); #ifdef __cplusplus } #endif #endif markdown/src/Rmarkdown.c0000644000175100001440000003164313075742411015024 0ustar hornikusers/* * Rmarkdown.c * * Copyright (C) 2009-2013 by RStudio, Inc. * * This program is licensed to you under the terms of version 2 of the * GNU General Public License. This program is distributed WITHOUT ANY * EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details. * */ #include "Rmarkdown.h" #define NREND 8 static struct rmd_renderer RENDERERS[NREND]; static struct rmd_renderer *renderer(const char *name); static Rboolean render_to_html(struct buf *ib, struct buf *ob, SEXP Soptions, SEXP Sextensions) { struct sd_callbacks callbacks; struct html_renderopt renderopt; unsigned int exts=0, options=0; struct sd_markdown *markdown; struct buf *htmlbuf; Rboolean toc = FALSE, smarty = FALSE; /* Marshal extensions */ if (isString(Sextensions)) { int i; for (i = 0; i < LENGTH(Sextensions); i++) { if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "NO_INTRA_EMPHASIS") == 0) exts |= MKDEXT_NO_INTRA_EMPHASIS; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "TABLES") == 0) exts |= MKDEXT_TABLES; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "FENCED_CODE") == 0) exts |= MKDEXT_FENCED_CODE; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "AUTOLINK") == 0) exts |= MKDEXT_AUTOLINK; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "STRIKETHROUGH") == 0) exts |= MKDEXT_STRIKETHROUGH; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "LAX_SPACING") == 0) exts |= MKDEXT_LAX_SPACING; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "SPACE_HEADERS") == 0) exts |= MKDEXT_SPACE_HEADERS; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "SUPERSCRIPT") == 0) exts |= MKDEXT_SUPERSCRIPT; else if (strcasecmp(CHAR(STRING_ELT(Sextensions,i)), "LATEX_MATH") == 0) exts |= MKDEXT_LATEX_MATH; } } /* Marshal HTML options */ if (isString(Soptions)) { int i; for (i = 0; i < LENGTH(Soptions); i++) { if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "SKIP_HTML") == 0) options |= HTML_SKIP_HTML; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "SKIP_STYLE") == 0) options |= HTML_SKIP_STYLE; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "SKIP_IMAGES") == 0) options |= HTML_SKIP_IMAGES; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "SKIP_LINKS") == 0) options |= HTML_SKIP_LINKS; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "SAFELINK") == 0) options |= HTML_SAFELINK; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "TOC") == 0) { options |= HTML_TOC; toc = TRUE; } else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "HARD_WRAP") == 0) options |= HTML_HARD_WRAP; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "USE_XHTML") == 0) options |= HTML_USE_XHTML; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "ESCAPE") == 0) options |= HTML_ESCAPE; else if (strcasecmp(CHAR(STRING_ELT(Soptions,i)), "SMARTYPANTS") == 0) smarty = TRUE; } } htmlbuf = bufnew(OUTPUT_UNIT); if (!htmlbuf) { RMD_WARNING_NOMEM; return FALSE; } if (toc==TRUE) { struct buf *tocbuf = bufnew(OUTPUT_UNIT); if (!tocbuf) { RMD_WARNING_NOMEM; return FALSE; } sdhtml_toc_renderer(&callbacks, &renderopt); markdown = sd_markdown_new(exts,16,&callbacks,(void *)&renderopt); if (!markdown) { RMD_WARNING_NOMEM; return FALSE; } sd_markdown_render(tocbuf, ib->data, ib->size, markdown); sd_markdown_free(markdown); bufputs(htmlbuf,"
    \n"); bufputs(htmlbuf,"
    Table of Contents
    \n"); bufput(htmlbuf,tocbuf->data,tocbuf->size); bufputs(htmlbuf,"
    \n"); bufputs(htmlbuf,"\n"); bufrelease(tocbuf); } sdhtml_renderer(&callbacks, &renderopt, options); markdown = sd_markdown_new(exts,16,&callbacks,(void *)&renderopt); if (!markdown) { RMD_WARNING_NOMEM; return FALSE; } sd_markdown_render(htmlbuf, ib->data, ib->size, markdown); sd_markdown_free(markdown); if (smarty==TRUE) { struct buf *smartybuf = bufnew(OUTPUT_UNIT); if (!smartybuf) { RMD_WARNING_NOMEM; return FALSE; } sdhtml_smartypants(smartybuf,htmlbuf->data,htmlbuf->size); bufrelease(htmlbuf); htmlbuf = smartybuf; } bufput(ob,htmlbuf->data,htmlbuf->size); bufrelease(htmlbuf); return TRUE; } void rmd_init_renderer_list() { int i; struct rmd_renderer *html; for (i=0;iname = "HTML"; html->render = render_to_html; html->output_type = "character"; } Rboolean rmd_renderer_exists(const char *name) { return (renderer(name) != NULL)? TRUE: FALSE; } Rboolean rmd_register_renderer(struct rmd_renderer *renderer) { int i, empty_slot = -1, name_exists = -1; if (!renderer) return FALSE; for (i=0;iname)==0) name_exists = i; } /* replace old renderer without warning */ if (name_exists>=0) empty_slot = name_exists; if (empty_slot>=0) { if (RENDERERS[empty_slot].name != NULL) { free(RENDERERS[empty_slot].name); free(RENDERERS[empty_slot].output_type); } RENDERERS[empty_slot].name = strdup(renderer->name); RENDERERS[empty_slot].render = renderer->render; RENDERERS[empty_slot].output_type = strdup(renderer->output_type); } else { error("Renderer list full!"); return FALSE; } return TRUE; } SEXP rmd_registered_renderers(void) { SEXP ans; SEXP names; char *name, *output_type; int i; PROTECT(ans = allocVector(STRSXP,NREND)); PROTECT(names = allocVector(STRSXP,NREND)); for (i=0;i 0) { bufgrow(ib,len); bufput(ib,(const void *)text,len); } else { warning("Input text is zero length!"); return FALSE; } } else { FILE *in; size_t ret; const char *file = CHAR(STRING_ELT(Sfile,0)); in = fopen(file,"r"); if (!in) { warning("Cannot open %s!", file); return FALSE; } bufgrow(ib, READ_UNIT); while ((ret = fread(ib->data + ib->size, 1, ib->asize - ib->size, in)) > 0) { ib->size += ret; bufgrow(ib, ib->size + READ_UNIT); } fclose(in); } return TRUE; } Rboolean rmd_buf_to_output(struct buf *ob, SEXP Soutput, SEXP *raw_vec) { /* Output */ if (isNull(Soutput)) { PROTECT(*raw_vec = allocVector(RAWSXP, ob->size)); memcpy(RAW(*raw_vec),ob->data,ob->size); UNPROTECT(1); } else { const char *filename = CHAR(STRING_ELT(Soutput,0)); FILE *out = fopen(filename,"w"); if (!out) { warning("Cannot save output to %s!", filename); return FALSE; } fwrite(ob->data, 1, ob->size, out); fclose(out); if (ferror (out)) { warning("Error occurred writing to %s!", filename); return FALSE; } } return TRUE; } /* Pandoc title blocks are prepended with percents '%'. They start on the * first line of the document and contain 3 elements: 'title','author', * and date. Both 'title' and 'author' can extend to multiple lines so * long as that line starts with a space, but 'date' cannot. */ void skip_pandoc_title_block(struct buf *ib){ int i = 0; size_t pos = 0; /* pandoc 1.9.1.1 expects title blocks to start on the first line */ if (ib->data[0] != '%') return; /* We search for at most 3 elements: title, author, and date */ for (i = 0; i < 3; i++){ if (ib->data[pos] != '%') break; /* Search for end of line */ while (pos < ib->size && ib->data[pos] != '\n') pos++; if (pos < ib->size) pos++; else break; do { /* Only title and author can contain continuation lines, * e.g. i < 2 */ if (ib->data[pos] == ' ' && i < 2){ while (pos < ib->size && ib->data[pos] != '\n') pos++; if (pos < ib->size) pos++; else break; } else { break; } } while(1); } /* If we've seen a title block, we'll take it off * the beginning of our buffer by slurping up pos bytes. */ if (pos > 0) bufslurp(ib,pos); } /* Jekyll front matter begins on the first line and the first three characters * of the line are '---'. Front matter ends when a line is started with '---'. * We skip everything in between including the ending '---'. */ void skip_jekyll_front_matter(struct buf *ib){ int front_matter_found = 0; size_t pos = 0; /* Jekyll 0.12.0 expects front matter to start on the first line */ if (ib->size < 3 || !(ib->data[0] == '-' && ib->data[1] == '-' && ib->data[2] == '-') ) return; pos = 3; do { while (pos < ib->size && ib->data[pos] != '\n') pos++; if (pos == ib->size) break; if (pos+3 < ib->size){ if (ib->data[pos+1] == '-' && ib->data[pos+2] == '-' && ib->data[pos+3] == '-'){ front_matter_found = 1; pos += 4; break; } else { pos++; } } else { break; } } while(1); if (front_matter_found && pos > 0) bufslurp(ib,pos); } SEXP rmd_render_markdown(SEXP Sfile, SEXP Soutput, SEXP Stext, SEXP Srenderer, SEXP Soptions, SEXP Sextensions) { const char *name; struct buf *ib, *ob; SEXP ret_val = R_NilValue; Rboolean success; name = CHAR(STRING_ELT(Srenderer,0)); if (!rmd_renderer_exists(name)) { error("Renderer '%s' not registered!",name); return R_NilValue; } ib = bufnew(READ_UNIT); if (!ib) error("Out of memory!"); success = rmd_input_to_buf(Sfile,Stext,ib); if (!success) { bufrelease(ib); error("Input error!"); } skip_pandoc_title_block(ib); skip_jekyll_front_matter(ib); ob = bufnew(OUTPUT_UNIT); if (!ob) error("Out of memory!"); success = renderer(name)->render(ib,ob,Soptions,Sextensions); if (!success) { bufrelease(ib); bufrelease(ob); error("Render error!"); } success = rmd_buf_to_output(ob,Soutput,&ret_val); bufrelease(ib); bufrelease(ob); if (!success) error("Output error!"); return ret_val; } SEXP rmd_render_smartypants(SEXP Sfile, SEXP Soutput, SEXP Stext) { struct buf *ib, *ob; SEXP ret_val = R_NilValue; Rboolean success; ib = bufnew(READ_UNIT); if (!ib) error("Out of memory!"); success = rmd_input_to_buf(Sfile, Stext, ib); if (!success) { bufrelease(ib); error("Input error!"); } ob = bufnew(OUTPUT_UNIT); if (!ob) error("Out of memory!"); sdhtml_smartypants(ob,ib->data,ib->size); success = rmd_buf_to_output(ob,Soutput,&ret_val); bufrelease(ib); bufrelease(ob); if (!success) error("Output error!"); return ret_val; } markdown/src/sundown_version.h0000644000175100001440000000011113075742411016311 0ustar hornikusers#define RSTUDIO_SUNDOWN_VERSION 07d0d98cec0df93e07debbcf562cac9eaca998f8 markdown/NAMESPACE0000644000175100001440000000051713073476144013345 0ustar hornikusers# Generated by roxygen2: do not edit by hand export(markdownExtensions) export(markdownHTMLOptions) export(markdownToHTML) export(registeredRenderers) export(renderMarkdown) export(rendererExists) export(rendererOutputType) export(rpubsUpload) export(smartypants) importFrom(utils,URLdecode) useDynLib(markdown, .registration = TRUE) markdown/NEWS0000644000175100001440000001464113075731222012621 0ustar hornikusers CHANGES IN markdown VERSION 0.8 MINOR CHANGES o the MathJax CDN URL was replaced by http://www.bootcdn.cn/mathjax/ BUG FIXES o fixed https://github.com/rstudio/htmltools/issues/30: markdownToHTML() did not work with empty files (thanks, @VermillionAzure) CHANGES IN markdown VERSION 0.7.7 BUG FIXES o renderMarkdown() works now even if text = character(0) or "" o added an `encoding` argument to renderMarkdown() since multi-byte characters in renderMarkdown() did not work on Windows (thanks, Kohske Takahashi, #63) o fixed #64: invalid 'n' argument in rpubsUpload() (thanks, Wouter van Atteveldt) MAJOR CHANGES o if renderMarkdown() returns a character vector, it will be marked with the UTF-8 encoding if it contains multi-byte characters CHANGES IN markdown VERSION 0.7.4 NEW FEATURES o when an image is the only element of its parent node in the HTML output document, it is automatically centered on the page MINOR CHANGES o images that have already been base64 encoded will not be encoded again (#61) o the URL of the MathJax CDN was updated to cdn.mathjax.org CHANGES IN markdown VERSION 0.7.2 BUG FIXES o fixed #60: MathJax may be included even if it is unnecessary when syntax highlighting is enabled (thanks, @aoles) o fixed a bug which may hang R when building R Markdown vignettes in a wrong locale (thanks, Dan Tenenbaum, yihui/knitr#782) CHANGES IN markdown VERSION 0.7 BUG FIXES o if both the 'file' and 'text' arguments are provided but file = NULL, e.g. markdownToHTML(file = NULL, text = ?), markdownToHTML() can throw an error indicating the file is invalid (thanks, Tyler Rinker, hadley/staticdocs#66) o markdownToHTML(text = ?, output = ?) was broken (#54) CHANGES IN markdown VERSION 0.6.5 NEW FEATURES o added an argument 'encoding' to markdownToHTML() to specify the character encoding of the input markdown file, and the HTML output file is always encoded in UTF-8 now (thanks, Kohske Takahashi, #50) CHANGES IN markdown VERSION 0.6.4 NEW FEATURES o added 'mathjax_embed' to HTML options for embedding the MathJax JavaScript in the HTML document rather than linking to it online. Note the JavaScript code is read from the http instead of https MathJax URL. Contributed by Henrik Bengtsson. o added another vignette to show the HTML output of the original vignette (see browseVignettes('markdown')) o the default CSS style was tweaked (major changes include: page width is at most 800px, more line height, slightly larger fonts, and a different syntax highlighting theme) CHANGES IN markdown VERSION 0.6.3 NEW FEATURES o added a new argument 'template' to markdownToHTML() so that we can customize the HTML template (by default, it uses the template 'resources/markdown.html' in this package); thanks, Nacho Caballero o the options markdown.HTML.stylesheet and markdown.HTML.header used in markdownToHTML() can be character vectors (they will be processed by paste(x, collapse = '\n') MAJOR CHANGES o the 'text' argument in markdownToHTML() and renderMarkdown() is treated as lines of input now, i.e. if 'text' is provided, it is passed to the markdown renderer as paste(text, collapse = '\n'); in the previous versions, it was processed by paste(text, collapse = '') CHANGES IN markdown VERSION 0.6 DOCUMENTATION o added a package vignette; see browseVignettes(package = 'markdown') CHANGES IN markdown VERSION 0.5.5 NEW FEATURES o added a new argument 'header' to markdownToHTML() to insert code into the HTML header (e.g. custom CSS styles) BUG FIXES o fixed #25 and #27: minor documentation problems o fixed #26: the HTML output file will be written relative to the current working directory now when it contains images that need to be base64 encoded o fixed #28: the image URL should be decoded before the image is based64 encoded MISC o Yihui Xie has taken over the maintainership for this package from Jeffrey Horner CHANGES IN markdown VERSION 0.5.4 NEW FEATURES o Both Pandoc title blocks and Jekyll front matter sections are skipped when rendering markdown documents. CHANGES IN markdown VERSION 0.5.3 NEW FEATURES o C/C++ is now a supported language for code block highlighting. MAJOR CHANGES o 'hard_wrap' has been dropped while 'mathjax' and 'highlight_code' have been added to the default list of html options. BUG FIXES o fixed parsing of math equations when located at the end of a line. CHANGES IN markdown VERSION 0.5.2 NEW FEATURES o with the new 'latex_math' markdown extensions, users can include math equations using several syntaxes. For block level equations, use $$latex ... $$, $$ ... $$, or \[ ... \]. For inline equations, use $latex...$, $...$, or \( ... \). MAJOR CHANGES o the markdown extension 'ingore_math' was replaced with 'latex_math'. o users can now use the markdown.HTML.stylesheet option to override the package default stylesheet. o setting the fragment_only rendering option or the fragment.only parameter to markdownToHTML will base64 encode images if applicable. version 0.5.1 did not. CHANGES IN markdown VERSION 0.5.1 BUG FIXES o fixed a GUIDgenerator bug; for escaping math equations before markdown parsing begins. o image encoding was fixed for the case when there are more than one included in a markdown document. CHANGES IN markdown VERSION 0.5 NEW FEATURES o added fragment.only parameter to markdownToHTML o added new html rendering options base64_images, fragment_only, mathjax, and highlight_code o added new markdown extension ignore_math MAJOR CHANGES o removed safelink from default html rendering options o the default html rendering options are now hard_wrap, use_xhtml, smartypants, and base64_images. BUG FIXES o fixed syntax errors in C exports CHANGES IN markdown VERSION 0.4 NEW FEATURES o added support for post-processing HTML using smartypants filter o added optional support for rendering a table of contents MAJOR CHANGES o changed exported C functions to use an rmd_ prefix (eliminating potential symbol conflicts with other packages) o changed default html rendering options to use_xhtml, hard_wrap, safelink, and smartypants BUG FIXES o eliminated name collision with render_markdown function in knitr markdown/R/0000755000175100001440000000000012561032655012320 5ustar hornikusersmarkdown/R/markdown-package.R0000644000175100001440000000176412330062343015655 0ustar hornikusers#' Markdown rendering for R #' #' \pkg{Markdown} is a plain-text formatting syntax that can be converted to #' XHTML or other formats. This package provides R bindings to the Sundown #' (\url{https://github.com/vmg/sundown}) markdown rendering library. #' #' The R function \code{\link{markdownToHTML}} renders a markdown file to HTML #' (respecting the specified \code{\link{markdownExtensions}} and #' \code{\link{markdownHTMLOptions}}). #' #' The package also exports the underlying Sundown C extension API which enables #' creating and calling custom renderers using the \code{\link{renderMarkdown}} #' function. #' #' To learn more about markdown syntax see: #' #' \url{http://en.wikipedia.org/wiki/Markdown} #' @name markdown #' @docType package #' @author JJ Allaire, Jeffrey Horner, Vicent Marti, and Natacha Porte #' #' Maintainer: Yihui Xie #' @seealso \code{\link{markdownToHTML}} \code{\link{renderMarkdown}} #' @useDynLib markdown, .registration = TRUE #' @keywords package NULL markdown/R/renderMarkdown.R0000644000175100001440000005556213073476143015445 0ustar hornikusers# # renderMarkdown.R # # Copyright (C) 2009-2014 by RStudio, Inc. # # This program is licensed to you under the terms of version 2 of the # GNU General Public License. This program is distributed WITHOUT ANY # EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the # GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details. # # #' List of Registered Markdown Renderers #' #' \code{registeredRenderers} returns a named character vector listing all the #' registered renderers known to the \pkg{markdown} package. \pkg{markdown} #' allows up to seven renderers to be registered by users; HTML is provided by #' the package. #' @return A named \code{character} vector listing all available renderers. #' Vector value contain renderer names, and named values contain the renderer #' output type, either \code{character} or \code{raw}. #' @seealso \link{markdownToHTML}, \link{rendererOutputType} #' @export registeredRenderers #' @examples #' # List all available renderers #' registeredRenderers() registeredRenderers <- function() .Call(rmd_registered_renderers) #' Testing for existence of a markdown renderer #' #' \code{rendererExists} determines whether or not a certain renderer exists in #' the markdown library. #' @param name name of renderer. #' @return \code{TRUE} or \code{FALSE} for whether or not the renderer exists. #' @export rendererExists #' @examples rendererExists("HTML") rendererExists <- function(name) name[1] %in% registeredRenderers() #' Fetch the Renderer Output Type #' #' \pkg{markdown} allows up to seven renderers to be registered by users, and #' each must provide the type of output returned, either \code{character} or #' \code{raw} for binary output. HTML is provided by the package and outputs #' \code{character}. #' @param name a character string naming the renderer. #' @return The character string with a value of either \code{character} or #' \code{raw}. #' @seealso \link{markdownToHTML}, \link{registeredRenderers} #' @export rendererOutputType #' @examples #' # List all available renderers #' rendererOutputType("HTML") rendererOutputType <- function(name) { rnds <- registeredRenderers() if (!name[1] %in% rnds) { warning('Renderer is not registered!') return('') } names(which(rnds == name[1])) } #' Render markdown to an HTML fragment #' #' \code{renderMarkdown} transforms the \emph{markdown} text provided by the #' user in either the \code{file} or \code{text} variable. The transformation is #' either written to the \code{output} file or returned to the user. The default #' rendering target is "HTML". #' #' \pkg{markdown} uses (and ships with) the popular Sundown library provided by #' GitHub. C stubs are available to implement new renderers. #' @inheritParams markdownToHTML #' @param renderer the name of the renderer that will be used to transform the #' \code{file} or \code{text}. #' @param renderer.options options that are passed to the renderer. For #' \code{HTML} renderer options see \code{\link{markdownHTMLOptions}}. #' @return \code{renderMarkdown} returns NULL invisibly when output is to a #' file, and either \code{character} (with the UTF-8 encoding) or \code{raw} #' vector depending on the renderer output type. #' @seealso \code{\link{markdownExtensions}}, \code{\link{markdownHTMLOptions}}, #' \code{\link{markdownToHTML}}. #' #' For a description of the original \emph{markdown} version: #' \url{http://daringfireball.net/projects/markdown/} #' #' The original Sundown library on github: #' \url{https://github.com/vmg/sundown} #' #' C stubs for writing new renders are in inst/include/markdown_rstubs.[ch]. #' @export renderMarkdown #' @examples #' (renderMarkdown(text = "Hello World!")) #' # a few corner cases #' (renderMarkdown(text = character(0))) #' (renderMarkdown(text = '')) renderMarkdown <- function( file, output = NULL, text = NULL, renderer = 'HTML', renderer.options = NULL, extensions = getOption('markdown.extensions'), encoding = getOption('encoding') ) { if (!rendererExists(renderer)) stop("Renderer '", renderer, "' is not registered!") # Input from either a file or character vector if (!is.character(text)) { # If input is file, it needs to be read with the appropriate encoding. Here, # instead of tweaking rmd_render_markdown in Rmarkdown.c, read a file with # the encoding and convert it to UTF-8. Finally, output will be marked as # UTF-8 as well. con <- base::file(file, encoding = encoding) text <- tryCatch(readLines(con), finally = close(con)) } text <- enc2utf8(text) if (length(text) > 1) text <- paste(text, collapse = '\n') file <- NULL # Options if (is.null(renderer.options)) renderer.options <- getOption(paste('markdown', renderer, 'options', sep = '.')) # HTML options must be a character vector. if (renderer == 'HTML') { if (!is.null(renderer.options) && !is.character(renderer.options)) stop('HTML options must be a character vector') } if (length(text) == 0 || text == '') { if (is.null(output)) return(invisible(character(length(text)))) file.create(output) return() } ret <- .Call(rmd_render_markdown, file, output, text, renderer, renderer.options, extensions) if (is.raw(ret) && rendererOutputType(renderer) == 'character') { ret <- rawToChar(ret) Encoding(ret) <- 'UTF-8' } invisible(ret) } .b64EncodeFile <- function(inFile) { fileSize <- file.info(inFile)$size if (fileSize <= 0) { warning(inFile, 'is empty!') return(inFile) } paste( 'data:', mime::guess_type(inFile), ';base64,', .Call(rmd_b64encode_data, readBin(inFile, 'raw', n = fileSize)), sep = '') } #' @importFrom utils URLdecode .b64EncodeImages <- function(html) { if (length(html) == 0) return(html) reg <- "<\\s*[Ii][Mm][Gg]\\s+[Ss][Rr][Cc]\\s*=\\s*[\"']([^\"']+)[\"']" m <- gregexpr(reg, html, perl = TRUE) if (m[[1]][1] != -1) { .b64EncodeImgSrc <- function(imgSrc) { src <- sub(reg, '\\1', imgSrc) # already base64 encoded? if (grepl('^data:.+;base64,.+', src)) return(imgSrc) inFile <- URLdecode(src) if (length(inFile) && file.exists(inFile)) imgSrc <- sub(src, .b64EncodeFile(inFile), imgSrc, fixed = TRUE) imgSrc } regmatches(html, m) <- list(unlist(lapply(regmatches(html, m)[[1]], .b64EncodeImgSrc))) } html } .mathJax <- local({ js <- NULL function(embed=FALSE, force=FALSE) { if (!embed) return(paste(readLines(system.file( 'resources', 'mathjax.html', package = 'markdown' )), collapse = '\n')) url <- 'https://cdn.bootcss.com/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML' # Insert or link to MathJax script? html <- c('', if (embed) { # Already in cache? if (force || is.null(js)) { js <<- readLines(url, warn=FALSE) } c('') paste(html, collapse="\n") } }) .requiresMathJax <- function(html) { regs <- c('\\\\\\(([\\s\\S]+?)\\\\\\)', '\\\\\\[([\\s\\S]+?)\\\\\\]') for (i in regs) if (any(grepl(i, html, perl = TRUE))) return(TRUE) FALSE } .requiresHighlighting <- function(html) any(grepl('
     tag will be base64 encoded and
    #' included in the output HTML.
    #'
    #' }
    #'
    #' See the DETAILS section below and \code{\link{markdownHTMLOptions}} for more
    #' information.
    #'
    #' There are two basic modes to \code{markdownToHTML} determined by the value of
    #' the \code{fragment.only} argument:
    #'
    #' When \code{FALSE}, \code{markdownToHTML} creates well-formed stand-alone HTML
    #' pages complete with HTML header, title, and body tags. The default template
    #' used for this mode may be found here:
    #'
    #' \code{system.file('resources', 'markdown.html', package = 'markdown')}
    #'
    #' Also, \code{markdownToHTML} will automatically determine whether or not
    #' mathjax and R code highlighting are needed and will include the appropriate
    #' Javascript libraries in the output. Thus, there's no need to explicitly set
    #' the \code{'mathjax'} or \code{'highlight_code'} options (see
    #' \code{\link{markdownHTMLOptions}} for more details).
    #'
    #' When \code{fragment.only} is TRUE, nothing extra is added.
    #'
    #' @param file a character string giving the pathname of the file to read from.
    #'   If it is omitted from the argument list, then it is presumed that the
    #'   \code{text} argument will be used instead.
    #' @param output a character string giving the pathname of the file to write to.
    #'   If it is omitted (\code{NULL}), then it is presumed that the user expects
    #'   the results returned as a \code{character} vector.
    #' @param text a character vector containing the \emph{markdown} text to
    #'   transform (each element of this vector is treated as a line in a file).
    #' @param options options that are passed to the renderer.  see
    #'   \code{\link{markdownHTMLOptions}}.
    #' @param extensions options that are passed to the \emph{markdown} engine. See
    #'   \code{\link{markdownExtensions}}.
    #' @param title The HTML title.
    #' @param stylesheet either valid CSS or a file containing CSS. will be included
    #'   in the output.
    #' @param header either valid HTML or a file containing HTML will be included in
    #'   the header of the output.
    #' @param template an HTML file used as template.
    #' @param fragment.only Whether or not to produce an HTML fragment without the
    #'   HTML header and body tags, CSS, and Javascript components.
    #' @param encoding the encoding of the input file; see \code{\link{file}}
    #' @return Invisible \code{NULL} when output is to a file, and a character
    #'   vector otherwise.
    #' @seealso \code{\link{markdownExtensions}}, \code{\link{markdownHTMLOptions}},
    #'   \code{\link{renderMarkdown}}.
    #' @export
    #' @examples
    #' (markdownToHTML(text = "Hello World!", fragment.only = TRUE))
    #' (markdownToHTML(file = NULL, text = "_text_ will override _file_",
    #'   fragment.only = TRUE))
    #' # write HTML to an output file
    #' markdownToHTML(text = "_Hello_, **World**!", output = "test.html")
    markdownToHTML <- function(
      file, output = NULL, text = NULL, options = getOption('markdown.HTML.options'),
      extensions = getOption('markdown.extensions'),
      title = '',
      stylesheet = getOption('markdown.HTML.stylesheet'),
      header = getOption('markdown.HTML.header'),
      template = getOption('markdown.HTML.template'),
      fragment.only = FALSE,
      encoding = getOption('encoding')
    ) {
      if (fragment.only) options <- c(options, 'fragment_only')
    
      ret <- renderMarkdown(
        file, output = NULL, text, renderer = 'HTML',
        renderer.options = options, extensions = extensions, encoding = encoding
      )
      ret <- enc2native(ret)
    
      if ('base64_images' %in% options) {
        filedir <- if (!missing(file) && is.character(file) && file.exists(file)) {
          dirname(file)
        } else '.'
        ret <- local({
          oldwd <- setwd(filedir)
          on.exit(setwd(oldwd))
          .b64EncodeImages(ret)
        })
      }
    
      if (!'fragment_only' %in% options) {
        if (is.null(template))
          template <- system.file('resources', 'markdown.html', package = 'markdown')
        html <- paste(readLines(template), collapse = '\n')
        html <- sub('#!html_output#', if (length(ret)) ret else '', html, fixed = TRUE)
    
        if (is.character(stylesheet)) {
          html <- sub('#!markdown_css#', option2char(stylesheet), html, fixed = TRUE)
        } else {
          warning('stylesheet must either be valid CSS or a file containing CSS!')
        }
    
        html <- sub('#!header#', option2char(header), html, fixed = TRUE)
    
        if (!is.character(title) || title == '') {
          # Guess title
          m <- regexpr('<[Hh][1-6].*?>(.*)', html, perl = TRUE)
          if (m > -1) {
            title <- regmatches(html, m)
            title <- sub('<[Hh][1-6].*?>', '', title)
            title <- sub('', '', title)
          } else {
            title <- ''
          }
        }
    
        # Need to scrub title more, e.g. strip html, etc.
        html <- sub('#!title#', title, html, fixed = TRUE)
    
        if ('mathjax' %in% options && .requiresMathJax(html)) {
          mathjax <- .mathJax(embed = 'mathjax_embed' %in% options)
        } else mathjax <- ''
        html <- sub('#!mathjax#', mathjax, html, fixed = TRUE)
    
        if ('highlight_code' %in% options && .requiresHighlighting(html)) {
          highlight <- paste(readLines(system.file(
            'resources', 'r_highlight.html', package = 'markdown'
          )), collapse = '\n')
        } else highlight <- ''
        html <- sub('#!r_highlight#', highlight, html, fixed = TRUE)
    
        ret <- html
      }
    
      if (is.character(output)) {
        # Output should be always UTF8 in accordance with HTML charset
        ret2 <- iconv(ret, to = 'UTF-8')
        if (any(is.na(ret2))) {
          warning('failed to convert output to UTF-8; wrong input encoding or locale?')
        } else ret <- ret2
        writeLines(ret, output, useBytes = TRUE)
        ret <- NULL
      }
    
      invisible(ret)
    }
    
    # from an option to an appropriate character string of CSS/header/...
    option2char <- function(x) {
      if (!is.character(x)) return('')
      paste(if (length(x) == 1 && file.exists(x)) readLines(x) else x, collapse = '\n')
    }
    
    #' smartypants: ASCII punctuation to HTML entities
    #'
    #' \code{smartypants} transforms plain ASCII punctuation characters into
    #' \emph{smart} typographic punctuation HTML entities.
    #' @param file a character string giving the pathname of the file to read from.
    #'   If it is omitted from the argument list, then it is presumed that the
    #'   \code{text} argument will be used instead.
    #' @param output a character string giving the pathname of the file to write to.
    #'   If it is omitted, then it is presumed that the user expects the results
    #'   returned as a character string.
    #' @param text a character vector containing the \emph{markdown} text to
    #'   transform.
    #' @return \code{smartypants} returns NULL invisibly when output is to a file,
    #'   and a character string otherwise.
    #' @seealso \code{\link{markdownExtensions}}, \code{\link{markdownHTMLOptions}},
    #'   \code{\link{markdownToHTML}}.
    #'
    #'   For a description of the original \emph{markdown} version:
    #'
    #'   \url{http://daringfireball.net/projects/markdown/}
    #'
    #'   The original Sundown library on github:
    #'
    #'   \url{https://github.com/vmg/sundown}
    #'
    #'   C stubs for writing new renders are in inst/include/markdown_rstubs.[ch].
    #' @export smartypants
    #' @examples
    #' cat(smartypants(text = "1/2 (c)\n"))
    smartypants <- function(file, output, text) {
      # Input from either a file or character vector
      if (!missing(file) && is.character(file) && file.exists(file)) {
        text <- NULL
      } else if (!missing(text) && !is.null(text) && is.character(text)) {
        file <- NULL
        if (length(text) > 1) text <- paste(text, collapse = '')
      } else stop('Need input from either a file or a text string')
    
      # Output is either returned or written to a file
      if (missing(output)) output <- NULL else if (!is.character(output))
        stop('output variable must be a file name!');
    
      ret <- .Call(rmd_render_smartypants, file, output, text)
      if (is.raw(ret)) ret <- rawToChar(ret)
    
      invisible(ret)
    }
    
    # Markdown extensions.
    #
    # To turn on all extensions:
    #
    # options(markdown.extensions = markdownExtensions())
    #
    # To turn off all extensions:
    #
    # options(markdown.extensions = c())
    #
    
    
    #' Markdown extensions
    #'
    #' \code{markdownExtensions} returns a character vector listing all the
    #' extensions that are available in the \pkg{markdown} package.
    #'
    #' They are all ON by default.
    #'
    #' The \pkg{Sundown} library (upon which \pkg{markdown} is built) has optional
    #' support for several extensions described below. To turn these on globally in
    #' the \pkg{markdown} package, simply place some or all of them in a character
    #' vector and assign to the global option \code{markdown.extensions} like so:
    #'
    #' \code{options(markdown.extensions = markdownExtensions())}
    #'
    #' To override the global option, pass the \code{extensions} as an argument to
    #' one of the render functions, e.g.:
    #'
    #' \code{markdownToHTML(..., extensions = c('no_intra_emphasis'))}
    #'
    #' Description of all extensions:
    #'
    #' \describe{
    #'
    #' \item{\code{'no_intra_emphasis'}}{ skip markdown embedded in words.  }
    #'
    #' \item{\code{'tables'}}{ create HTML tables (see Examples). }
    #'
    #' \item{\code{'fenced_code'}}{ treat text as verbatim when surrounded with
    #' begin and ending lines with three ~ or \emph{`} characters.  }
    #'
    #' \item{\code{'autolink'}}{ create HTML links from urls and email addresses. }
    #'
    #' \item{\code{'strikethrough'}}{ create strikethroughs by surrounding text with
    #' ~~.  }
    #'
    #' \item{\code{'lax_spacing'}}{ allow HTML tags inside paragraphs without being
    #' surrounded by newlines.  }
    #'
    #' \item{\code{'space_headers'}}{ add a space between header hashes and the
    #' header itself.  }
    #'
    #' \item{\code{'superscript'}}{ translate ^ and subsequent text into HTML
    #' superscript. }
    #'
    #' \item{\code{'latex_math'}}{ transforms all math equations into syntactically
    #' correct MathJax equations.  }
    #'
    #' }
    #'
    #' See the EXAMPLES section to see the output of each extension turned on or
    #' off.
    #' @return A \code{character} vector listing all available extensions.
    #' @seealso \link{markdownHTMLOptions}
    #' @export markdownExtensions
    #' @examples
    #' # List all available extensions:
    #' markdownExtensions()
    #'
    #' # To turn on all markdown extensions globally:
    #' options(markdown.extensions = markdownExtensions())
    #'
    #' # To turn off all markdown extensions globally:
    #' options(markdown.extensions = NULL)
    #'
    #' @example inst/examples/markdownExtensions.R
    markdownExtensions <- function()
      c('no_intra_emphasis', 'tables', 'fenced_code', 'autolink', 'strikethrough',
        'lax_spacing', 'space_headers', 'superscript', 'latex_math')
    
    # HTML renderer options.
    #
    # To turn on all options:
    #
    # options(markdown.HTML.options = markdownHTMLOptions())
    #
    # To turn on default options:
    #
    # options(markdown.HTML.options = markdownHTMLOptions(defaults = TRUE))
    #
    # To turn off all options:
    #
    # options(markdown.HTML.options = c())
    #
    
    
    #' Markdown HTML rendering options
    #'
    #' \code{markdownHTMLOptions} returns a character vector listing all the options
    #' that are available for the HTML renderer in the \pkg{markdown} package. As a
    #' convenience, the package default options were chosen to render well-formed
    #' stand-alone HTML pages when using \code{\link{markdownToHTML}()}. The default
    #' options are \code{'use_xhtml'}, \code{'smartypants'}, \code{'base64_images'},
    #' \code{'mathjax'}, and \code{'highlight_code'}.
    #'
    #' The HTML renderer provides several options described below. To turn these on
    #' globally in the \pkg{markdown} package, simply place some or all of them in a
    #' character vector and assign to the global option \code{markdown.HTML.options}
    #' like so:
    #'
    #' \code{options(markdown.HTML.options = markdownHTMLOptions())}
    #'
    #' To reset the options to package default, use:
    #'
    #' \code{options(markdown.HTML.options = markdownHTMLOptions(default = TRUE))}
    #'
    #' To override the global option, pass the \code{options} as an argument:
    #'
    #' \code{markdownToHTML(..., options = c('skip_images'))}
    #'
    #' Description of all options:
    #'
    #' \describe{
    #'
    #' \item{\code{'skip_html'}}{ suppress output of all HTML tags in the document.}
    #'
    #' \item{\code{'skip_style'}}{ suppress output of HTML style tags.}
    #'
    #' \item{\code{'skip_images'}}{ suppress output of HTML image tags.}
    #'
    #' \item{\code{'skip_links'}}{ suppress output of HTML anchor tags.}
    #'
    #' \item{\code{'safelink'}}{ only create links for known url types, e.g. http,
    #' ftp, http, etc.}
    #'
    #' \item{\code{'toc'}}{ assigns an HTML id to each header of the form 'toc_%d'
    #' where '%d' is replaced with the position of the header within the document
    #' (starting at 0), and creates the table of contents.}
    #'
    #' \item{\code{'hard_wrap'}}{ adds an HTML br tag for every newline (excluding
    #' trailing) found within a paragraph.}
    #'
    #' \item{\code{'use_xhtml'}}{ create XHMTL 1.0 compliant HTML tags.}
    #'
    #' \item{\code{'escape'}}{ escape all HTML found within the \emph{markdown}.
    #' Overrides all of the \code{'skip_*'} options mentioned above.}
    #'
    #' \item{\code{'smartypants'}}{ translates plain ASCII punctuation characters
    #' into \emph{smart} typographic punctuation HTML entities. }
    #'
    #' \item{\code{'fragment_only'}}{ eliminates the inclusion of any HTML header or
    #' body tags, CSS, or Javascript components. }
    #'
    #' \item{\code{'base64_images'}}{ Any local images linked with the
    #' \code{''} tag to the output HTML will automatically be converted to
    #' base64 and included along with output. }
    #'
    #' \item{\code{'mathjax'}}{ includes appropriate Javascript libraries to render
    #' math markup.}
    #'
    #' \item{\code{'highlight_code'}}{ includes appropriate Javascript libraries to
    #' highlight code chunks.}
    #'
    #' }
    #'
    #' See the EXAMPLES section to see the output of each option turned on or off.
    #' @param defaults If \code{TRUE}, then only the default options are returned.
    #'   Otherwise all options are returned.
    #' @return A \code{character} vector listing either all available options or
    #'   just the default options.
    #' @seealso \link{markdownToHTML}
    #' @export
    #' @examples
    #' # List all available extensions:
    #' markdownHTMLOptions()
    #'
    #' # To turn on all HTML options globally:
    #' options(markdown.HTML.options = markdownHTMLOptions())
    #'
    #' # To turn off all HTML options globally:
    #' options(markdown.HTML.options = NULL)
    #'
    #' # To turn on package default HTML options globally:
    #' options(markdown.HTML.options = markdownHTMLOptions(default = TRUE))
    #'
    #' @example inst/examples/HTMLOptions.R
    markdownHTMLOptions <- function(defaults = FALSE) {
      allOptions <- c(
        'skip_html', 'skip_style', 'skip_images', 'skip_links', 'safelink', 'toc',
        'escape', 'fragment_only', 'hard_wrap', 'use_xhtml', 'smartypants',
        'base64_images', 'mathjax', 'highlight_code'
      )
      if (defaults) allOptions[10:14] else allOptions
    }
    
    .onLoad <- function(libname, pkgname) {
    
      if (is.null(getOption('markdown.extensions')))
        options(markdown.extensions = markdownExtensions())
    
      if (is.null(getOption('markdown.HTML.options')))
        options(markdown.HTML.options = markdownHTMLOptions(defaults = TRUE))
    
      if (is.null(getOption('markdown.HTML.stylesheet'))) {
        sheet <- system.file('resources', 'markdown.css', package = 'markdown')
        options(markdown.HTML.stylesheet = sheet)
      }
    }
    markdown/R/rpubsUpload.R0000644000175100001440000003447112514634366014761 0ustar  hornikusers# Copyright (C) 2009-2014 by RStudio, Inc.
    #
    # This program is licensed to you under the terms of version 2 of the
    # GNU General Public License. This program is distributed WITHOUT ANY
    # EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
    # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
    # GPL (http://www.gnu.org/licenses/gpl-2.0.txt) for more details.
    #
    #
    
    #' Upload an HTML file to RPubs
    #'
    #' This function uploads an HTML file to rpubs.com. If the upload succeeds a
    #' list that includes an \code{id} and \code{continueUrl} is returned. A browser
    #' should be opened to the \code{continueUrl} to complete publishing of the
    #' document. If an error occurs then a diagnostic message is returned in the
    #' \code{error} element of the list.
    #' @param title The title of the document.
    #' @param htmlFile The path to the HTML file to upload.
    #' @param id If this upload is an update of an existing document then the id
    #'   parameter should specify the document id to update. Note that the id is
    #'   provided as an element of the list returned by successful calls to
    #'   \code{rpubsUpload}.
    #' @param properties A named list containing additional document properties
    #'   (RPubs doesn't currently expect any additional properties, this parameter
    #'   is reserved for future use).
    #' @param method Method to be used for uploading. "internal" uses a plain http
    #'   socket connection; "curl" uses the curl binary to do an https upload;
    #'   "rcurl" uses the RCurl package to do an https upload; and "auto" uses the
    #'   best available method searched for in the following order: "curl", "rcurl",
    #'   and then "internal". The global default behavior can be configured by
    #'   setting the \code{rpubs.upload.method} option (the default is "auto").
    #' @return A named list. If the upload was successful then the list contains a
    #'   \code{id} element that can be used to subsequently update the document as
    #'   well as a \code{continueUrl} element that provides a URL that a browser
    #'   should be opened to in order to complete publishing of the document. If the
    #'   upload fails then the list contains an \code{error} element which contains
    #'   an explanation of the error that occurred.
    #' @export
    #' @examples
    #' \dontrun{
    #' # upload a document
    #' result <- rpubsUpload("My document title", "Document.html")
    #' if (!is.null(result$continueUrl))
    #'     browseURL(result$continueUrl) else stop(result$error)
    #'
    #' # update the same document with a new title
    #' updateResult <- rpubsUpload("My updated title", "Document.html", result$id)
    #' }
    rpubsUpload <- function(title,
                            htmlFile,
                            id = NULL,
                            properties = list(),
                            method = getOption("rpubs.upload.method", "auto")) {
    
       # validate inputs
       if (!is.character(title))
          stop("title must be specified")
       if (nzchar(title) == FALSE)
          stop("title must be a non-empty string")
       if (!is.character(htmlFile))
          stop("htmlFile parameter must be specified")
       if (!file.exists(htmlFile))
          stop("specified htmlFile does not exist")
       if (!is.list(properties))
          stop("properties paramater must be a named list")
    
       parseHeader <- function(header) {
          split <- strsplit(header, ": ")[[1]]
          if (length(split) == 2)
             list(name = split[1], value = split[2])
       }
    
       jsonEscapeString <- function(value) {
          chars <- strsplit(value, "")[[1]]
          chars <- vapply(chars, function(x) {
             if (x %in% c('"', '\\', '/'))
                paste('\\', x, sep='')
             else if (charToRaw(x) < 20)
                paste('\\u', toupper(format(as.hexmode(as.integer(charToRaw(x))),
                                            width=4)),
                      sep='')
             else x
          }, character(1))
          paste(chars, sep="", collapse="")
       }
    
       jsonProperty <- function(name, value) {
          paste("\"",
                jsonEscapeString(enc2utf8(name)),
                "\" : \"",
                jsonEscapeString(enc2utf8(value)),
                "\"",
                sep="")
       }
    
       regexExtract <- function(re, input) {
          match <- regexec(re, input)
          matchLoc <- match[1][[1]]
          if (length(matchLoc) > 1) {
             matchLen <-attributes(matchLoc)$match.length
             url <- substr(input, matchLoc[2], matchLoc[2] + matchLen[2]-1)
             url
          }
       }
    
       # NOTE: we parse the json naively using a regex because:
       #  - We don't want to take a dependency on a json library for just this case
       #  - We know the payload is an ascii url so we don't need a robust parser
       parseContinueUrl <- function(continueUrl) {
          regexExtract("\\{\\s*\"continueUrl\"\\s*:\\s*\"([^\"]+)\"\\s*\\}",
                       continueUrl)
       }
    
       parseHttpStatusCode <- function(statusLine) {
          statusCode <- regexExtract("HTTP/[0-9]+\\.[0-9]+ ([0-9]+).*", statusLine)
          if (is.null(statusCode)) -1 else as.integer(statusCode)
       }
    
       pathFromId <- function(id) {
          split <- strsplit(id, "^https?://[^/]+")[[1]]
          if (length(split) == 2) split[2]
       }
    
       buildPackage <- function(title,
                                htmlFile,
                                properties = list()) {
    
          # build package.json
          packageJson <- "{"
          packageJson <- paste(packageJson, jsonProperty("title", title), ",")
          for (name in names(properties)) {
             if (nzchar(name) == FALSE)
                stop("all properties must be named")
             value <- properties[[name]]
             packageJson <- paste(packageJson, jsonProperty(name, value), ",")
          }
          packageJson <- substr(packageJson, 1, nchar(packageJson)-1)
          packageJson <- paste(packageJson,"}")
    
          # create a tempdir to build the package in and copy the files to it
          fileSep <- .Platform$file.sep
          packageDir <- tempfile()
          dir.create(packageDir)
          packageFile <- function(fileName) {
             paste(packageDir,fileName,sep=fileSep)
          }
          writeLines(packageJson, packageFile("package.json"))
          file.copy(htmlFile, packageFile("index.html"))
    
          # switch to the package dir for building
          oldWd <- getwd()
          setwd(packageDir)
          on.exit(setwd(oldWd))
    
          # create the tarball
          tarfile <- tempfile("package", fileext = ".tar.gz")
          utils::tar(tarfile, files = ".", compression = "gzip")
    
          # return the full path to the tarball
          return (tarfile)
       }
    
       # Use skipDecoding=TRUE if transfer-encoding: chunked but the
       # chunk decoding has already been performed on conn
       readResponse <- function(conn, skipDecoding) {
          # read status code
          resp <- readLines(conn, 1)
          statusCode <- parseHttpStatusCode(resp[1])
    
          # read response headers
          contentLength <- NULL
          location <- NULL
          transferEncoding <- NULL
          repeat {
             resp <- readLines(conn, 1)
             if (nzchar(resp) == 0)
                break
    
             header <- parseHeader(resp)
             # Case insensitive header name comparison
             headerName <- tolower(header$name)
             if (!is.null(header)) {
                if (identical(headerName, "content-type"))
                   contentType <- header$value
                if (identical(headerName, "content-length"))
                   contentLength <- as.integer(header$value)
                if (identical(headerName, "location"))
                   location <- header$value
                if (identical(headerName, "transfer-encoding"))
                   transferEncoding <- tolower(header$value)
             }
          }
    
          # read the response content
          content <- if (is.null(transferEncoding) || skipDecoding) {
             if (!is.null(contentLength)) {
                rawToChar(readBin(conn, what = 'raw', n=contentLength))
             }
             else {
                paste(readLines(conn, warn = FALSE), collapse = "\r\n")
             }
          } else if (identical(transferEncoding, "chunked")) {
             accum <- ""
             repeat {
                resp <- readLines(conn, 1)
                resp <- sub(";.*", "", resp) # Ignore chunk extensions
                chunkLen <- as.integer(paste("0x", resp, sep = ""))
                if (is.na(chunkLen)) {
                   stop("Unexpected chunk length")
                }
                if (identical(chunkLen, 0L)) {
                   break
                }
                accum <- paste0(accum, rawToChar(readBin(conn, what = 'raw', n=chunkLen)))
                # Eat CRLF
                if (!identical("\r\n", rawToChar(readBin(conn, what = 'raw', n=2)))) {
                   stop("Invalid chunk encoding: missing CRLF")
                }
             }
             accum
          } else {
             stop("Unexpected transfer encoding")
          }
    
          # return list
          list(status = statusCode,
               location = location,
               contentType = contentType,
               content = content)
       }
    
       # internal sockets implementation of upload (supports http-only)
       internalUpload <- function(path,
                                  contentType,
                                  headers,
                                  packageFile) {
    
          # read file in binary mode
          fileLength <- file.info(packageFile)$size
          fileContents <- readBin(packageFile, what="raw", n=fileLength)
    
          # build http request
          request <- NULL
          request <- c(request, paste("POST ", path, " HTTP/1.1\r\n", sep=""))
          request <- c(request, "User-Agent: RStudio\r\n")
          request <- c(request, "Host: api.rpubs.com\r\n")
          request <- c(request, "Accept: */*\r\n")
          request <- c(request, paste("Content-Type: ", contentType, "\r\n", sep=""))
          request <- c(request, paste("Content-Length: ", fileLength, "\r\n", sep=""))
          for (name in names(headers)) {
             request <- c(request,
                          paste(name, ": ", headers[[name]], "\r\n", sep=""))
          }
          request <- c(request, "\r\n")
    
          # open socket connection
          conn <- socketConnection(host="api.rpubs.com",
                                   port=80,
                                   open="w+b",
                                   blocking=TRUE)
          on.exit(close(conn))
    
          # write the request header and file payload
          writeBin(charToRaw(paste(request,collapse="")), conn, size=1)
          writeBin(fileContents, conn, size=1)
    
          # read the response
          readResponse(conn, skipDecoding = FALSE)
       }
    
    
       rcurlUpload <- function(path,
                               contentType,
                               headers,
                               packageFile) {
    
          # url to post to
          url <- paste("https://api.rpubs.com", path, sep = "")
    
          # upload package file
          params <- list(file = RCurl::fileUpload(filename = packageFile,
                                           contentType = contentType))
    
          # use custom header and text gatherers
          sslpath <- system.file("CurlSSL", "cacert.pem", package = "RCurl")
          options <- RCurl::curlOptions(url, cainfo = sslpath)
          headerGatherer <- RCurl::basicHeaderGatherer()
          options$headerfunction <- headerGatherer$update
          textGatherer <- RCurl::basicTextGatherer()
          options$writefunction <- textGatherer$update
    
          # add extra headers
          extraHeaders <- as.character(headers)
          names(extraHeaders) <- names(headers)
          options$httpheader <- extraHeaders
    
          # post the form
          RCurl::postForm(paste("https://api.rpubs.com", path, sep=""),
                               .params = params,
                               .opts = options,
                               useragent = "RStudio")
    
          # return list
          headers <- headerGatherer$value()
          location <- if ("Location" %in% names(headers)) headers[["Location"]]
          list(status = as.integer(headers[["status"]]),
               location = location,
               contentType <- headers[["Content-Type"]],
               content = textGatherer$value())
    
       }
    
       curlUpload <- function(path,
                              contentType,
                              headers,
                              packageFile) {
    
          fileLength <- file.info(packageFile)$size
    
          extraHeaders <- character()
          for (header in names(headers)) {
             extraHeaders <- paste(extraHeaders, "--header")
             extraHeaders <- paste(extraHeaders,
                                   paste(header,":",headers[[header]], sep=""))
          }
    
          outputFile <- tempfile()
    
          command <- paste("curl",
                           "-X",
                           "POST",
                           "--data-binary",
                           shQuote(paste("@", packageFile, sep="")),
                           "-i",
                           "--header", paste("Content-Type:",contentType, sep=""),
                           "--header", paste("Content-Length:", fileLength, sep=""),
                           extraHeaders,
                           "--header", "Expect:",
                           "--silent",
                           "--show-error",
                           "-o", shQuote(outputFile),
                           paste("https://api.rpubs.com", path, sep=""))
    
          result <- system(command)
    
          if (result == 0) {
            fileConn <- file(outputFile, "rb")
            on.exit(close(fileConn))
            readResponse(fileConn, skipDecoding = TRUE)
          } else {
            stop(paste("Upload failed (curl error", result, "occurred)"))
          }
       }
    
       uploadFunction <- if (is.function(method)) {
          method
       } else switch(
         method,
         "auto" = {
           if (nzchar(Sys.which("curl"))) curlUpload else {
             if (suppressWarnings(requireNamespace("RCurl", quietly = TRUE))) {
               rcurlUpload
             } else internalUpload
           }
         },
         "internal" = internalUpload,
         "curl"     = curlUpload,
         "rcurl"    = rcurlUpload,
          stop(paste("Invalid upload method specified:",method))
       )
    
       # build the package
       packageFile <- buildPackage(title, htmlFile, properties)
    
       # determine whether this is a new doc or an update
       isUpdate <- FALSE
       path <- "/api/v1/document"
       headers <- list()
       headers$Connection <- "close"
       if (!is.null(id)) {
          isUpdate <- TRUE
          path <- pathFromId(id)
          headers$`X-HTTP-Method-Override` <- "PUT"
       }
    
    
       # send the request
       result <- uploadFunction(path,
                                "application/x-compressed",
                                headers,
                                packageFile)
    
       # check for success
       succeeded <- (isUpdate && (result$status == 200)) || (result$status == 201)
    
       # mark content as UTF-8
       content <- result$content
       Encoding(content) <- "UTF-8"
    
       # return either id & continueUrl or error
       if (succeeded) {
         list(id = ifelse(isUpdate, id, result$location),
              continueUrl = parseContinueUrl(content))
       } else list(error = content)
    }
    markdown/vignettes/0000755000175100001440000000000013075742411014126 5ustar  hornikusersmarkdown/vignettes/markdown-examples.Rmd0000644000175100001440000000133412330062343020221 0ustar  hornikusers
    
    This vignette shows some examples for different Markdown extensions and HTML options.
    
    ```{r read-code, include=FALSE}
    library(knitr)
    opts_chunk$set(tidy = FALSE)  # otherwise \n will cause problems
    read_chunk(system.file('examples', 'markdownExtensions.R', package = 'markdown'),
               labels = 'md-extensions')
    read_chunk(system.file('examples', 'HTMLOptions.R', package = 'markdown'),
               labels = 'html-options')
    ```
    
    ```{r}
    library(markdown)
    ```
    
    # Markdown Extensions
    
    ```{r md-extensions}
    ```
    
    # HTML Options
    
    ```{r html-options}
    ```
    
    
    ```{r include=FALSE}
    options(markdown.HTML.options=markdownHTMLOptions(defaults=TRUE))
    ```
    markdown/vignettes/markdown-output.Rmd0000644000175100001440000000070512330062343017744 0ustar  hornikusers
    
    This vignette shows how the output looks like in HTML from the other vignette `markdown-examples.Rmd`, in which the literal HTML code was shown.
    
    ```{r read, include=FALSE}
    library(knitr)
    opts_chunk$set(results = 'asis')
    out = knit_child(text = scan('markdown-examples.Rmd', what = 'character', skip = 7, sep = '\n'))
    ```
    
    `r paste(out, collapse = '\n')`
    markdown/README.md0000644000175100001440000000300412416357710013374 0ustar  hornikusersMarkdown rendering for R
    =============================================================================
    
    [![Build Status](https://travis-ci.org/rstudio/markdown.svg)](https://travis-ci.org/rstudio/markdown)
    
    Overview
    -----------------------------------------------------------------------------
    
    *Markdown* is a plain-text formatting syntax that can be converted
    to XHTML or other formats. This package provides R bindings to the
    [Sundown](https://github.com/vmg/sundown) markdown rendering library.
    
    The R function `markdownToHTML` renders a markdown file to HTML. Options
    controlling HTML output and supported markdown extensions can be optionally
    specified.
    
    The package also exports the underlying Sundown C extension API which
    enables creating and calling custom renderers using the `renderMarkdown`
    function.
    
    To learn more about markdown syntax see: 
    
    This package is referred to as _R Markdown v1_ when combined with **knitr**. The
    primary output format is HTML. Now we have introduced [_R Markdown
    v2_](http://blog.rstudio.org/2014/06/18/r-markdown-v2/), which is based on
    Pandoc and **knitr**, and supports much more types of output formats. Please see
    http://rmarkdown.rstudio.com for details.
    
    License
    -----------------------------------------------------------------------------
    
    The markdown package is licensed under the GPLv2. See these files for
    additional details:
    
    - inst/COPYING - Markdown package license (GPLv2)
    - inst/NOTICE  - Copyright notices for additional included software
    markdown/MD50000644000175100001440000000655613076075152012444 0ustar  hornikusers6c409ef8e37e0936e6df3ac8931940ff *DESCRIPTION
    0138c297e1c17cef31fd4275e5d2058f *NAMESPACE
    8bebd8e5cef0eaa470d5a86387286b08 *NEWS
    0a375621b5466aaa55827331b7a54aba *R/markdown-package.R
    4c0c2582a89ace3512ccd0b7d077e6d1 *R/renderMarkdown.R
    9c15b355037cc2e11df80d660e0e6e3f *R/rpubsUpload.R
    8d8e54509fc3fe29397a945c23015784 *README.md
    a4565ca643b20915c2c92c21f6f674e9 *build/vignette.rds
    603dd5a44125bb3c7f2595c87c048d93 *inst/COPYING
    4907458964894cb1dcc67c4f5690a48b *inst/NOTICE
    5f8881b49f2c520da450f8705916e906 *inst/doc/markdown-examples.R
    29668370a07ca593fad4e953674716cc *inst/doc/markdown-examples.Rmd
    f056c2f77c81043d19e3ccd603311576 *inst/doc/markdown-examples.html
    e850a3b8329628f9290591680017e8ad *inst/doc/markdown-output.R
    09998ddcbdaa092c32cfedd3d12e11a2 *inst/doc/markdown-output.Rmd
    7df763793845ad59bb79246d00bea681 *inst/doc/markdown-output.html
    97a8de7bcac5a0cfd539d80c098f91a3 *inst/examples/HTMLOptions.R
    fc33aa286a619e7be798b864d8e4e0ac *inst/examples/markdownExtensions.R
    4ba2610d0919031a909bf50306bfc533 *inst/include/autolink.h
    510d81c5e25bd88608f06afea594adfa *inst/include/buffer.h
    23ed959ea9845e0877d824fdd081b11a *inst/include/markdown.h
    9f130bbcd1a33d16d655c5b3bc10917c *inst/include/markdown_rstubs.c
    8edae02d2442e7abc13b9118a16c70c7 *inst/include/markdown_rstubs.h
    ab9c98860a3e321c58fcb1d75f9f45ba *inst/resources/markdown.css
    5ffdc57da02ee2c6a28e4b2d6053c7ac *inst/resources/markdown.html
    df7f3ca066d8f72ff1f72d4906280030 *inst/resources/mathjax.html
    e25f1ac72fe309c072cd9aa836c631a6 *inst/resources/r_highlight.html
    033c64ff011f088f0bc28d4e250dabaf *man/markdown.Rd
    ab14ba32c922022de7befc1f9f7d4efe *man/markdownExtensions.Rd
    b8bba863334d0c0224fb75813f6ab3c6 *man/markdownHTMLOptions.Rd
    152b64499b20d7429ebd9038c4bcf0ef *man/markdownToHTML.Rd
    ce150e104348b5d753fea95d11a1aa04 *man/registeredRenderers.Rd
    349886947c404ea6b5a9c74acac46de5 *man/renderMarkdown.Rd
    2ffe48c7a8aa9e7cea56c7724711b840 *man/rendererExists.Rd
    ab2f9d2a23a7d8a18310d813c2411657 *man/rendererOutputType.Rd
    ed3baf556e92dd865ac36deb217cebe5 *man/rpubsUpload.Rd
    f171794e13c464eefc8cff95e088ee80 *man/smartypants.Rd
    5b8ccd8ec39ce84c2cdcf97ea96a575d *src/Rbase64.c
    6ef3854b1cc4f5b7122638960ffe8591 *src/Rinit.c
    2ea7823363be5db032986e8bb22d2f73 *src/Rmarkdown.c
    be6889a7e0acbbc26cebd8b379efae40 *src/Rmarkdown.h
    26fcef5aabe22c64142adb48c2a87cf5 *src/autolink.c
    4ba2610d0919031a909bf50306bfc533 *src/autolink.h
    51bbdc8afb4d77aa10e71e48fa67bd76 *src/buffer.c
    468151555424b7d222a1a64d0cbc7a69 *src/buffer.h
    6cc1bd118177be4dac56e0e7698470f1 *src/houdini.h
    327ac86078b740183d9484bf9b65b719 *src/houdini_href_e.c
    ad4e12539e64e6e7685a89b206d2e469 *src/houdini_html_e.c
    9b88ce919aa9ec23b4b9dce71696c8da *src/html.c
    4500e9bf93a1990f6e504a03d32e7178 *src/html.h
    a49ff5141e373322137dd2a8ce07ecf5 *src/html_blocks.h
    c437cef296ff77dced3f8dfce7c1fdcc *src/html_smartypants.c
    d7c1cac650658c15073aeeecf8117cac *src/markdown.c
    8c222ccb74fa0e73f6ba0394bedbe3fc *src/markdown.h
    0ac4251d8cb2f229de24efbe501f2a4a *src/stack.c
    cd51442c3d728d42342e57467dcd5ad5 *src/stack.h
    ecd33756b1689d8da494c69bea7a7ca6 *src/sundown_version.h
    db1aa5d45dbadf89ef24ddec5b4f35ff *tests/b64EncodeFile.R
    1f82a1dc0ed1faf6cfe247d37ad78638 *tests/empty.R
    44ebcfa56c4b699099a0b74fd32474f7 *tests/tests.R
    7f1dec0d46dcf4e910dc1b0d3f8119ca *tests/tests.Rout.save
    29668370a07ca593fad4e953674716cc *vignettes/markdown-examples.Rmd
    09998ddcbdaa092c32cfedd3d12e11a2 *vignettes/markdown-output.Rmd
    markdown/build/0000755000175100001440000000000013075742411013215 5ustar  hornikusersmarkdown/build/vignette.rds0000644000175100001440000000036613075742411015561 0ustar  hornikusersuP]0-DBŻ
    DB൱
    KUƛ_n]lsݷBU1FUVNWj<`D\|cz',
    0H;#MF7pu= 2.11.1)
    Imports: utils, mime (>= 0.3)
    Suggests: knitr, RCurl
    License: GPL-2
    URL: https://github.com/rstudio/markdown
    BugReports: https://github.com/rstudio/markdown/issues
    VignetteBuilder: knitr
    RoxygenNote: 6.0.1
    NeedsCompilation: yes
    Packaged: 2017-04-19 20:14:01 UTC; yihui
    Author: JJ Allaire [aut],
      Jeffrey Horner [aut],
      Henrik Bengtsson [ctb],
      Jim Hester [ctb],
      Yixuan Qiu [ctb],
      Kohske Takahashi [ctb],
      Adam November [ctb],
      Nacho Caballero [ctb],
      Jeroen Ooms [ctb],
      Thomas Leeper [ctb],
      Joe Cheng [ctb],
      Andrzej Oles [ctb],
      Vicent Marti [aut, cph] (The Sundown library),
      Natacha Porte [aut, cph] (The Sundown library),
      RStudio [cph],
      Yihui Xie [cre, ctb]
    Maintainer: Yihui Xie 
    Repository: CRAN
    Date/Publication: 2017-04-20 09:07:54 UTC
    markdown/man/0000755000175100001440000000000013073476144012676 5ustar  hornikusersmarkdown/man/markdownHTMLOptions.Rd0000644000175100001440000001260513075741517017055 0ustar  hornikusers% Generated by roxygen2: do not edit by hand
    % Please edit documentation in R/renderMarkdown.R
    \name{markdownHTMLOptions}
    \alias{markdownHTMLOptions}
    \title{Markdown HTML rendering options}
    \usage{
    markdownHTMLOptions(defaults = FALSE)
    }
    \arguments{
    \item{defaults}{If \code{TRUE}, then only the default options are returned.
    Otherwise all options are returned.}
    }
    \value{
    A \code{character} vector listing either all available options or
      just the default options.
    }
    \description{
    \code{markdownHTMLOptions} returns a character vector listing all the options
    that are available for the HTML renderer in the \pkg{markdown} package. As a
    convenience, the package default options were chosen to render well-formed
    stand-alone HTML pages when using \code{\link{markdownToHTML}()}. The default
    options are \code{'use_xhtml'}, \code{'smartypants'}, \code{'base64_images'},
    \code{'mathjax'}, and \code{'highlight_code'}.
    }
    \details{
    The HTML renderer provides several options described below. To turn these on
    globally in the \pkg{markdown} package, simply place some or all of them in a
    character vector and assign to the global option \code{markdown.HTML.options}
    like so:
    
    \code{options(markdown.HTML.options = markdownHTMLOptions())}
    
    To reset the options to package default, use:
    
    \code{options(markdown.HTML.options = markdownHTMLOptions(default = TRUE))}
    
    To override the global option, pass the \code{options} as an argument:
    
    \code{markdownToHTML(..., options = c('skip_images'))}
    
    Description of all options:
    
    \describe{
    
    \item{\code{'skip_html'}}{ suppress output of all HTML tags in the document.}
    
    \item{\code{'skip_style'}}{ suppress output of HTML style tags.}
    
    \item{\code{'skip_images'}}{ suppress output of HTML image tags.}
    
    \item{\code{'skip_links'}}{ suppress output of HTML anchor tags.}
    
    \item{\code{'safelink'}}{ only create links for known url types, e.g. http,
    ftp, http, etc.}
    
    \item{\code{'toc'}}{ assigns an HTML id to each header of the form 'toc_%d'
    where '%d' is replaced with the position of the header within the document
    (starting at 0), and creates the table of contents.}
    
    \item{\code{'hard_wrap'}}{ adds an HTML br tag for every newline (excluding
    trailing) found within a paragraph.}
    
    \item{\code{'use_xhtml'}}{ create XHMTL 1.0 compliant HTML tags.}
    
    \item{\code{'escape'}}{ escape all HTML found within the \emph{markdown}.
    Overrides all of the \code{'skip_*'} options mentioned above.}
    
    \item{\code{'smartypants'}}{ translates plain ASCII punctuation characters
    into \emph{smart} typographic punctuation HTML entities. }
    
    \item{\code{'fragment_only'}}{ eliminates the inclusion of any HTML header or
    body tags, CSS, or Javascript components. }
    
    \item{\code{'base64_images'}}{ Any local images linked with the
    \code{''} tag to the output HTML will automatically be converted to
    base64 and included along with output. }
    
    \item{\code{'mathjax'}}{ includes appropriate Javascript libraries to render
    math markup.}
    
    \item{\code{'highlight_code'}}{ includes appropriate Javascript libraries to
    highlight code chunks.}
    
    }
    
    See the EXAMPLES section to see the output of each option turned on or off.
    }
    \examples{
    # List all available extensions:
    markdownHTMLOptions()
    
    # To turn on all HTML options globally:
    options(markdown.HTML.options = markdownHTMLOptions())
    
    # To turn off all HTML options globally:
    options(markdown.HTML.options = NULL)
    
    # To turn on package default HTML options globally:
    options(markdown.HTML.options = markdownHTMLOptions(default = TRUE))
    
    # HTML OPTIONS
    
    # The following examples are short, so we allways add the HTML option 'fragment_only'
    tOpt <- "fragment_only"
    
    # skip_html example
    mkd = 'Hello'
    cat(markdownToHTML(text = mkd, options = c(tOpt)))
    cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))
    
    # skip_style example
    cat(markdownToHTML(text = mkd, options = c(tOpt)))
    cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_style")))
    
    # skip_images example
    cat(markdownToHTML(text = mkd, options = c(tOpt)))
    cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_images")))
    
    # skip_links example
    cat(markdownToHTML(text = mkd, options = c(tOpt)))
    cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_links")))
    
    # safelink example
    cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt)))
    cat(markdownToHTML(text = '[foo](http://google.com "baz")', options = c(tOpt, "safelink")))
    
    # toc example
    mkd <- paste(c("# Header 1", "p1", "## Header 2", "p2"), collapse = "\\n")
    
    cat(markdownToHTML(text = mkd, options = c(tOpt)))
    cat(markdownToHTML(text = mkd, options = c(tOpt, "toc")))
    
    # hard_wrap example
    cat(markdownToHTML(text = "foo\\nbar\\n", options = c(tOpt)))
    cat(markdownToHTML(text = "foo\\nbar\\n", options = c(tOpt, "hard_wrap")))
    
    # use_xhtml example
    cat(markdownToHTML(text = "foo\\nbar\\n", options = c(tOpt, "hard_wrap")))
    cat(markdownToHTML(text = "foo\\nbar\\n", options = c(tOpt, "hard_wrap", "use_xhtml")))
    
    # escape example
    mkd = 'Hello'
    cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html")))
    # overrides all 'skip_*' options
    cat(markdownToHTML(text = mkd, options = c(tOpt, "skip_html", "escape")))
    
    # smartypants example
    cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt)))
    cat(markdownToHTML(text = "1/2 (c)", options = c(tOpt, "smartypants")))
    
    cat(smartypants(text = "1/2 (c)\\n"))
    }
    \seealso{
    \link{markdownToHTML}
    }
    markdown/man/registeredRenderers.Rd0000644000175100001440000000145713075741517017204 0ustar  hornikusers% Generated by roxygen2: do not edit by hand
    % Please edit documentation in R/renderMarkdown.R
    \name{registeredRenderers}
    \alias{registeredRenderers}
    \title{List of Registered Markdown Renderers}
    \usage{
    registeredRenderers()
    }
    \value{
    A named \code{character} vector listing all available renderers.
      Vector value contain renderer names, and named values contain the renderer
      output type, either \code{character} or \code{raw}.
    }
    \description{
    \code{registeredRenderers} returns a named character vector listing all the
    registered renderers known to the \pkg{markdown} package. \pkg{markdown}
    allows up to seven renderers to be registered by users; HTML is provided by
    the package.
    }
    \examples{
    # List all available renderers
    registeredRenderers()
    }
    \seealso{
    \link{markdownToHTML}, \link{rendererOutputType}
    }
    markdown/man/rendererExists.Rd0000644000175100001440000000076213075741517016201 0ustar  hornikusers% Generated by roxygen2: do not edit by hand
    % Please edit documentation in R/renderMarkdown.R
    \name{rendererExists}
    \alias{rendererExists}
    \title{Testing for existence of a markdown renderer}
    \usage{
    rendererExists(name)
    }
    \arguments{
    \item{name}{name of renderer.}
    }
    \value{
    \code{TRUE} or \code{FALSE} for whether or not the renderer exists.
    }
    \description{
    \code{rendererExists} determines whether or not a certain renderer exists in
    the markdown library.
    }
    \examples{
    rendererExists("HTML")
    }
    markdown/man/markdownToHTML.Rd0000644000175100001440000000764313075741517016012 0ustar  hornikusers% Generated by roxygen2: do not edit by hand
    % Please edit documentation in R/renderMarkdown.R
    \name{markdownToHTML}
    \alias{markdownToHTML}
    \title{Render markdown to HTML}
    \usage{
    markdownToHTML(file, output = NULL, text = NULL,
      options = getOption("markdown.HTML.options"),
      extensions = getOption("markdown.extensions"), title = "",
      stylesheet = getOption("markdown.HTML.stylesheet"),
      header = getOption("markdown.HTML.header"),
      template = getOption("markdown.HTML.template"), fragment.only = FALSE,
      encoding = getOption("encoding"))
    }
    \arguments{
    \item{file}{a character string giving the pathname of the file to read from.
    If it is omitted from the argument list, then it is presumed that the
    \code{text} argument will be used instead.}
    
    \item{output}{a character string giving the pathname of the file to write to.
    If it is omitted (\code{NULL}), then it is presumed that the user expects
    the results returned as a \code{character} vector.}
    
    \item{text}{a character vector containing the \emph{markdown} text to
    transform (each element of this vector is treated as a line in a file).}
    
    \item{options}{options that are passed to the renderer.  see
    \code{\link{markdownHTMLOptions}}.}
    
    \item{extensions}{options that are passed to the \emph{markdown} engine. See
    \code{\link{markdownExtensions}}.}
    
    \item{title}{The HTML title.}
    
    \item{stylesheet}{either valid CSS or a file containing CSS. will be included
    in the output.}
    
    \item{header}{either valid HTML or a file containing HTML will be included in
    the header of the output.}
    
    \item{template}{an HTML file used as template.}
    
    \item{fragment.only}{Whether or not to produce an HTML fragment without the
    HTML header and body tags, CSS, and Javascript components.}
    
    \item{encoding}{the encoding of the input file; see \code{\link{file}}}
    }
    \value{
    Invisible \code{NULL} when output is to a file, and a character
      vector otherwise.
    }
    \description{
    \code{markdownToHTML} transforms the \emph{markdown} text provided by the
    user in either the \code{file} or \code{text} variable. The HTML
    transformation is either written to the \code{output} file or returned to the
    user as a \code{character} vector.
    }
    \details{
    Three notable HTML options have been added to support collaborative
    reproducible research. They are as follows:
    
    \itemize{
    
    \item Latex math expressions enclosed by one of the block level syntaxes,
    $latex ... $ , $$ ... $$, or \[ ... \], or one of the inline syntaxes, $...$,
    or \( ... \), will be rendered in real-time by the MathJax Javascript
    library.
    
    \item \emph{R} code blocks enclosed between \verb{```r} and \verb{```} will
    automatically be syntax highlighted.
    
    \item Any local images linked using the  tag will be base64 encoded and
    included in the output HTML.
    
    }
    
    See the DETAILS section below and \code{\link{markdownHTMLOptions}} for more
    information.
    
    There are two basic modes to \code{markdownToHTML} determined by the value of
    the \code{fragment.only} argument:
    
    When \code{FALSE}, \code{markdownToHTML} creates well-formed stand-alone HTML
    pages complete with HTML header, title, and body tags. The default template
    used for this mode may be found here:
    
    \code{system.file('resources', 'markdown.html', package = 'markdown')}
    
    Also, \code{markdownToHTML} will automatically determine whether or not
    mathjax and R code highlighting are needed and will include the appropriate
    Javascript libraries in the output. Thus, there's no need to explicitly set
    the \code{'mathjax'} or \code{'highlight_code'} options (see
    \code{\link{markdownHTMLOptions}} for more details).
    
    When \code{fragment.only} is TRUE, nothing extra is added.
    }
    \examples{
    (markdownToHTML(text = "Hello World!", fragment.only = TRUE))
    (markdownToHTML(file = NULL, text = "_text_ will override _file_", fragment.only = TRUE))
    # write HTML to an output file
    markdownToHTML(text = "_Hello_, **World**!", output = "test.html")
    }
    \seealso{
    \code{\link{markdownExtensions}}, \code{\link{markdownHTMLOptions}},
      \code{\link{renderMarkdown}}.
    }
    markdown/man/markdown.Rd0000644000175100001440000000206413075741516015011 0ustar  hornikusers% Generated by roxygen2: do not edit by hand
    % Please edit documentation in R/markdown-package.R
    \docType{package}
    \name{markdown}
    \alias{markdown}
    \alias{markdown-package}
    \title{Markdown rendering for R}
    \description{
    \pkg{Markdown} is a plain-text formatting syntax that can be converted to
    XHTML or other formats. This package provides R bindings to the Sundown
    (\url{https://github.com/vmg/sundown}) markdown rendering library.
    }
    \details{
    The R function \code{\link{markdownToHTML}} renders a markdown file to HTML
    (respecting the specified \code{\link{markdownExtensions}} and
    \code{\link{markdownHTMLOptions}}).
    
    The package also exports the underlying Sundown C extension API which enables
    creating and calling custom renderers using the \code{\link{renderMarkdown}}
    function.
    
    To learn more about markdown syntax see:
    
    \url{http://en.wikipedia.org/wiki/Markdown}
    }
    \seealso{
    \code{\link{markdownToHTML}} \code{\link{renderMarkdown}}
    }
    \author{
    JJ Allaire, Jeffrey Horner, Vicent Marti, and Natacha Porte
    
      Maintainer: Yihui Xie 
    }
    \keyword{package}
    markdown/man/markdownExtensions.Rd0000644000175100001440000001066713075741516017101 0ustar  hornikusers% Generated by roxygen2: do not edit by hand
    % Please edit documentation in R/renderMarkdown.R
    \name{markdownExtensions}
    \alias{markdownExtensions}
    \title{Markdown extensions}
    \usage{
    markdownExtensions()
    }
    \value{
    A \code{character} vector listing all available extensions.
    }
    \description{
    \code{markdownExtensions} returns a character vector listing all the
    extensions that are available in the \pkg{markdown} package.
    }
    \details{
    They are all ON by default.
    
    The \pkg{Sundown} library (upon which \pkg{markdown} is built) has optional
    support for several extensions described below. To turn these on globally in
    the \pkg{markdown} package, simply place some or all of them in a character
    vector and assign to the global option \code{markdown.extensions} like so:
    
    \code{options(markdown.extensions = markdownExtensions())}
    
    To override the global option, pass the \code{extensions} as an argument to
    one of the render functions, e.g.:
    
    \code{markdownToHTML(..., extensions = c('no_intra_emphasis'))}
    
    Description of all extensions:
    
    \describe{
    
    \item{\code{'no_intra_emphasis'}}{ skip markdown embedded in words.  }
    
    \item{\code{'tables'}}{ create HTML tables (see Examples). }
    
    \item{\code{'fenced_code'}}{ treat text as verbatim when surrounded with
    begin and ending lines with three ~ or \emph{`} characters.  }
    
    \item{\code{'autolink'}}{ create HTML links from urls and email addresses. }
    
    \item{\code{'strikethrough'}}{ create strikethroughs by surrounding text with
    ~~.  }
    
    \item{\code{'lax_spacing'}}{ allow HTML tags inside paragraphs without being
    surrounded by newlines.  }
    
    \item{\code{'space_headers'}}{ add a space between header hashes and the
    header itself.  }
    
    \item{\code{'superscript'}}{ translate ^ and subsequent text into HTML
    superscript. }
    
    \item{\code{'latex_math'}}{ transforms all math equations into syntactically
    correct MathJax equations.  }
    
    }
    
    See the EXAMPLES section to see the output of each extension turned on or
    off.
    }
    \examples{
    # List all available extensions:
    markdownExtensions()
    
    # To turn on all markdown extensions globally:
    options(markdown.extensions = markdownExtensions())
    
    # To turn off all markdown extensions globally:
    options(markdown.extensions = NULL)
    
    # The following examples are short, so we set the HTML option 'fragment_only'
    
    options(markdown.HTML.options = "fragment_only")
    
    # no_intra_emphasis example
    cat(markdownToHTML(text = "foo_bar_function", extensions = c()))
    cat(markdownToHTML(text = "foo_bar_function", extensions = c("no_intra_emphasis")))
    
    # tables example (need 4 spaces at beginning of line here)
    cat(markdownToHTML(text = "
        First Header  | Second Header
        ------------- | -------------
        Content Cell  | Content Cell
        Content Cell  | Content Cell
    ", 
        extensions = c()))
    
    # but not here
    cat(markdownToHTML(text = "
    First Header  | Second Header
    ------------- | -------------
    Content Cell  | Content Cell
    Content Cell  | Content Cell
    ", 
        extensions = c("tables")))
    
    # fenced_code example (need at least three leading ~ or `)
    fenced_block <- function(text, x = "`", n = 3) {
        fence <- paste(rep(x, n), collapse = "")
        paste(fence, text, fence, sep = "")
    }
    cat(markdownToHTML(text = fenced_block("
    preformatted text here without having to indent
    first line.
    "), 
        extensions = c()))
    
    cat(markdownToHTML(text = fenced_block("
    preformatted text here without having to indent
    first line.
    "), 
        extensions = c("fenced_code")))
    
    # autolink example
    cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c()))
    cat(markdownToHTML(text = "https://www.r-project.org/", extensions = c("autolink")))
    
    # strikethrough example
    cat(markdownToHTML(text = "~~awesome~~", extensions = c()))
    cat(markdownToHTML(text = "~~awesome~~", extensions = c("strikethrough")))
    
    # lax_spacing
    cat(markdownToHTML(text = "
    Embedding html without surrounding with empty newline.
    
    _markdown_
    extra text. ", extensions = c(""))) cat(markdownToHTML(text = " Embedding html without surrounding with empty newline.
    _markdown_
    extra text. ", extensions = c("lax_spacing"))) # space_headers example cat(markdownToHTML(text = "#A Header\\neven though there is no space between # and A", extensions = c(""))) cat(markdownToHTML(text = "#Not A Header\\nbecause there is no space between # and N", extensions = c("space_headers"))) # superscript example cat(markdownToHTML(text = "2^10", extensions = c())) cat(markdownToHTML(text = "2^10", extensions = c("superscript"))) } \seealso{ \link{markdownHTMLOptions} } markdown/man/renderMarkdown.Rd0000644000175100001440000000471713075741517016161 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/renderMarkdown.R \name{renderMarkdown} \alias{renderMarkdown} \title{Render markdown to an HTML fragment} \usage{ renderMarkdown(file, output = NULL, text = NULL, renderer = "HTML", renderer.options = NULL, extensions = getOption("markdown.extensions"), encoding = getOption("encoding")) } \arguments{ \item{file}{a character string giving the pathname of the file to read from. If it is omitted from the argument list, then it is presumed that the \code{text} argument will be used instead.} \item{output}{a character string giving the pathname of the file to write to. If it is omitted (\code{NULL}), then it is presumed that the user expects the results returned as a \code{character} vector.} \item{text}{a character vector containing the \emph{markdown} text to transform (each element of this vector is treated as a line in a file).} \item{renderer}{the name of the renderer that will be used to transform the \code{file} or \code{text}.} \item{renderer.options}{options that are passed to the renderer. For \code{HTML} renderer options see \code{\link{markdownHTMLOptions}}.} \item{extensions}{options that are passed to the \emph{markdown} engine. See \code{\link{markdownExtensions}}.} \item{encoding}{the encoding of the input file; see \code{\link{file}}} } \value{ \code{renderMarkdown} returns NULL invisibly when output is to a file, and either \code{character} (with the UTF-8 encoding) or \code{raw} vector depending on the renderer output type. } \description{ \code{renderMarkdown} transforms the \emph{markdown} text provided by the user in either the \code{file} or \code{text} variable. The transformation is either written to the \code{output} file or returned to the user. The default rendering target is "HTML". } \details{ \pkg{markdown} uses (and ships with) the popular Sundown library provided by GitHub. C stubs are available to implement new renderers. } \examples{ (renderMarkdown(text = "Hello World!")) # a few corner cases (renderMarkdown(text = character(0))) (renderMarkdown(text = "")) } \seealso{ \code{\link{markdownExtensions}}, \code{\link{markdownHTMLOptions}}, \code{\link{markdownToHTML}}. For a description of the original \emph{markdown} version: \url{http://daringfireball.net/projects/markdown/} The original Sundown library on github: \url{https://github.com/vmg/sundown} C stubs for writing new renders are in inst/include/markdown_rstubs.[ch]. } markdown/man/rpubsUpload.Rd0000644000175100001440000000446113075741517015473 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rpubsUpload.R \name{rpubsUpload} \alias{rpubsUpload} \title{Upload an HTML file to RPubs} \usage{ rpubsUpload(title, htmlFile, id = NULL, properties = list(), method = getOption("rpubs.upload.method", "auto")) } \arguments{ \item{title}{The title of the document.} \item{htmlFile}{The path to the HTML file to upload.} \item{id}{If this upload is an update of an existing document then the id parameter should specify the document id to update. Note that the id is provided as an element of the list returned by successful calls to \code{rpubsUpload}.} \item{properties}{A named list containing additional document properties (RPubs doesn't currently expect any additional properties, this parameter is reserved for future use).} \item{method}{Method to be used for uploading. "internal" uses a plain http socket connection; "curl" uses the curl binary to do an https upload; "rcurl" uses the RCurl package to do an https upload; and "auto" uses the best available method searched for in the following order: "curl", "rcurl", and then "internal". The global default behavior can be configured by setting the \code{rpubs.upload.method} option (the default is "auto").} } \value{ A named list. If the upload was successful then the list contains a \code{id} element that can be used to subsequently update the document as well as a \code{continueUrl} element that provides a URL that a browser should be opened to in order to complete publishing of the document. If the upload fails then the list contains an \code{error} element which contains an explanation of the error that occurred. } \description{ This function uploads an HTML file to rpubs.com. If the upload succeeds a list that includes an \code{id} and \code{continueUrl} is returned. A browser should be opened to the \code{continueUrl} to complete publishing of the document. If an error occurs then a diagnostic message is returned in the \code{error} element of the list. } \examples{ \dontrun{ # upload a document result <- rpubsUpload("My document title", "Document.html") if (!is.null(result$continueUrl)) browseURL(result$continueUrl) else stop(result$error) # update the same document with a new title updateResult <- rpubsUpload("My updated title", "Document.html", result$id) } } markdown/man/rendererOutputType.Rd0000644000175100001440000000137713075741517017067 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/renderMarkdown.R \name{rendererOutputType} \alias{rendererOutputType} \title{Fetch the Renderer Output Type} \usage{ rendererOutputType(name) } \arguments{ \item{name}{a character string naming the renderer.} } \value{ The character string with a value of either \code{character} or \code{raw}. } \description{ \pkg{markdown} allows up to seven renderers to be registered by users, and each must provide the type of output returned, either \code{character} or \code{raw} for binary output. HTML is provided by the package and outputs \code{character}. } \examples{ # List all available renderers rendererOutputType("HTML") } \seealso{ \link{markdownToHTML}, \link{registeredRenderers} } markdown/man/smartypants.Rd0000644000175100001440000000256413075741517015562 0ustar hornikusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/renderMarkdown.R \name{smartypants} \alias{smartypants} \title{smartypants: ASCII punctuation to HTML entities} \usage{ smartypants(file, output, text) } \arguments{ \item{file}{a character string giving the pathname of the file to read from. If it is omitted from the argument list, then it is presumed that the \code{text} argument will be used instead.} \item{output}{a character string giving the pathname of the file to write to. If it is omitted, then it is presumed that the user expects the results returned as a character string.} \item{text}{a character vector containing the \emph{markdown} text to transform.} } \value{ \code{smartypants} returns NULL invisibly when output is to a file, and a character string otherwise. } \description{ \code{smartypants} transforms plain ASCII punctuation characters into \emph{smart} typographic punctuation HTML entities. } \examples{ cat(smartypants(text = "1/2 (c)\\n")) } \seealso{ \code{\link{markdownExtensions}}, \code{\link{markdownHTMLOptions}}, \code{\link{markdownToHTML}}. For a description of the original \emph{markdown} version: \url{http://daringfireball.net/projects/markdown/} The original Sundown library on github: \url{https://github.com/vmg/sundown} C stubs for writing new renders are in inst/include/markdown_rstubs.[ch]. }