smu-noxz

[fork] simple markup - markdown like syntax
git clone git://git.noxz.tech/smu-noxz
Log | Files | Refs | LICENSE

commit 0d5c6e340c134c2ee58e0e8715a7cbaae7895ad0
Author: Chris Noxz <chris@noxz.tech>
Date:   Thu, 19 Sep 2019 14:08:43 +0200

Initial commit of fork of smu

Diffstat:
ALICENSE | 21+++++++++++++++++++++
AMakefile | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.mk | 20++++++++++++++++++++
Adocumentation | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asmu.1 | 23+++++++++++++++++++++++
Asmu.c | 624+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asmu.h | 19+++++++++++++++++++
Atestdoc | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 1043 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +(c) 2007-2014 Enno Boland <g s01 de> + +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. diff --git a/Makefile b/Makefile @@ -0,0 +1,55 @@ +# libsmu - simple markup +# (c) 2007, 2008 Enno Boland + +include config.mk + +SRC = smu.c +OBJ = ${SRC:.c=.o} + +all: options smu + +options: + @echo smu build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +smu: ${OBJ} + @echo LD $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f smu ${OBJ} ${LIBOBJ} smu-${VERSION}.tar.gz + +dist: clean + @echo creating dist tarball + @mkdir -p smu-${VERSION} + @cp -R LICENSE Makefile config.mk smu.1 ${SRC} smu-${VERSION} + @tar -cf smu-${VERSION}.tar smu-${VERSION} + @gzip smu-${VERSION}.tar + @rm -rf smu-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f smu ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/smu + @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 + @mkdir -p ${DESTDIR}${MANPREFIX}/man1 + @sed "s/VERSION/${VERSION}/g" < smu.1 > ${DESTDIR}${MANPREFIX}/man1/smu.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/smu.1 + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/smu + @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 + @rm -f ${DESTDIR}${MANPREFIX}/man1/smu.1 + +.PHONY: all options clean dist install uninstall diff --git a/config.mk b/config.mk @@ -0,0 +1,20 @@ +# smu version +VERSION = 1.4 + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +# includes and libs +INCS = -I. -I/usr/include +LIBS = -L/usr/lib + +# flags +CFLAGS = -g -O0 -Wall -Werror -ansi ${INCS} -DVERSION=\"${VERSION}\" +#CFLAGS = -fprofile-arcs -ftest-coverage -pg -g -O0 -Wall -Werror -ansi ${INCS} -DVERSION=\"${VERSION}\" +#CFLAGS = -Os -Wall -Werror -ansi ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = -fprofile-arcs -ftest-coverage -pg ${LIBS} +LDFLAGS = ${LIBS} + +# compiler +CC = cc diff --git a/documentation b/documentation @@ -0,0 +1,201 @@ +smu - a Simple Markup Language +============================== + +_smu_ is a very simple and minimal markup language. It is designed for use in +wiki-like environments. smu makes it very easy to write your documents on the +fly and convert them into HTML. + +smu is capable of parsing very large documents. It scales just great as long +as you avoid a huge amount of indents (this will be fixed in future releases +of smu). + +Syntax +====== + +smu was started as a rewrite of +[markdown](http://daringfireball.net/projects/markdown/) but became something +more lightweight and consistent. The biggest difference between markdown and smu +is that smu doesn't support _reference style links_ + +Inline pattern +-------------- + +There are several pattern you can use to highlight your text: + +* Emphasis + * Surround your text with `*` or `_` to get *emphasised* text: + This *is* cool. + This _is_ cool, too. + * Surround your text with `**` or `__` to get **strong** text: + This **is** cool. + This __is__ cool, too. + * Surround your text with `***` or `___` to get ***strong and emphasised*** text: + This ***is*** cool. + This ___is___ cool, too. + * But this example won't work as expected: + ***Hello** you* + This is a wontfix bug because it would make the source too complex. + Use this instead: + ***Hello*** *you* + +* inline Code + + You can produce inline code with surrounding `\`` or `\`\`` + + Use `rm -rf /` if you're a N00b. + + Use ``rm -rf /`` if you're a N00b. + + `\`\`ABC\`\`` makes it possible to use Backticks without backslashing them. + + +Titles +------ + +Creating titles in smu is very easy. There are two different syntax styles. The +first is underlining: + + Heading + ======= + + Topic + ----- + +This is very intuitive and self explaining. The resulting sourcecode looks like +this: + + <h1>Heading</h1> + <h2>Topic</h2> + +Use the following prefixes if you don't like underlining: + + # h1 + ## h2 + ### h3 + #### h4 + ##### h5 + ###### h6 + +Links +----- + +The simplest way to define a link is with simple `<>`. + + <http://s01.de> + +You can do the same for E-Mail addresses: + + <yourname@s01.de> + +If you want to define a label for the url, you have to use a different syntax + + [smu - simple mark up](http://s01.de/~gottox/index.cgi/proj_smu) + +The resulting HTML-Code + + <a href="http://s01.de/~gottox/index.cgi/proj_smu">smu - simple mark up</a></p> + +Lists +----- + +Defining lists is very straightforward: + + * Item 1 + * Item 2 + * Item 3 + +Result: + + <ul> + <li>Item 1</li> + <li>Item 2</li> + <li>Item 3</li> + </ul> + +Defining ordered lists is also very easy: + + 1. Item 1 + 2. Item 2 + 3. Item 3 + +It is possible to use any leading number you want. So if you don't want to keep +your list synchronised, you simple can use any number. In this case it's +recommended to use `0.`, but it isn't mandatory. + + 0. Item 1 + 0. Item 2 + 0. Item 3 + +Both examples will cause the same result. Even this is possible: + + 1000. Item 1 + 432. Item 2 + 0. Item 3 + +This will be the result in these example: + + <ol> + <li>Item 1</li> + <li>Item 2</li> + <li>Item 3</li> + </ol> + +Code & Blockquote +----------------- + +Use the `> ` as a line prefix for defining blockquotes. Blockquotes are +interpreted as well. This makes it possible to embed links, headings and even +other quotes into a quote: + + > Hello + > This is a quote with a [link](http://s01.de/~gottox) + +Result: + <blockquote><p> + Hello + This is a quote with a <a href="http://s01.de/~gottox">link</a></p> + </blockquote> + + +You can define block code with a leading Tab or with __3__ leading spaces + + this.is(code) + + this.is(code, too) + +Result: + <pre><code>this.is(code)</code></pre> + <pre><code>this.is(code, too) + </code></pre> + +Please note that you can't use HTML or smu syntax in a code block. + +Other interesting stuff +----------------------- + +* to insert a horizontal rule simple add `- - -` into an empty line: + + Hello + - - - + Hello2 + + Result: + <p> + Hello + <hr /> + + Hello2</p> + +* You can escape the following pattern to avoid them from being interpreted: + + \ ` * _ { } [ ] ( ) # + - . ! + +* To force a linebreak simple add two spaces to the end of the line: + + No linebreak + here. + But here is + one. + +embed HTML +---------- diff --git a/smu.1 b/smu.1 @@ -0,0 +1,23 @@ +.TH smu 1 smu\-VERSION +.SH NAME +smu \- simple markup +.SH SYNOPSIS +.B smu +.RB [ \-h ] +.RB [ \-v ] +.RB [ \-n ] +.RB [ file ] +.SH DESCRIPTION +smu is a simple interpreter for a simplified markdown dialect. +.SH OPTIONS +.TP +.B \-v +prints version information to standard error, then exits. +.TP +.B \-h +prints usage information to standard error, then exits. +.TP +.B \-n +escapes all HTML Tags. +.SH BUGS +Please report any Bugs to https://github.com/Gottox/smu/issues or via mail. diff --git a/smu.c b/smu.c @@ -0,0 +1,624 @@ +/* smu - simple markup + * Copyright (C) <2007, 2008> Enno Boland <g s01 de> + * + * See LICENSE for further informations + */ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#define LENGTH(x) sizeof(x)/sizeof(x[0]) +#define ADDC(b,i) if(i % BUFSIZ == 0) { b = realloc(b, (i + BUFSIZ) * sizeof(char)); if(!b) eprint("Malloc failed."); } b[i] + +typedef int (*Parser)(const char *, const char *, int); +typedef struct { + char *search; + int process; + char *before, *after; +} Tag; + +static int doamp(const char *begin, const char *end, int newblock); /* Parser for & */ +static int docomment(const char *begin, const char *end, int newblock); /* Parser for html-comments */ +static int dogtlt(const char *begin, const char *end, int newblock); /* Parser for < and > */ +static int dohtml(const char *begin, const char *end, int newblock); /* Parser for html */ +static int dolineprefix(const char *begin, const char *end, int newblock);/* Parser for line prefix tags */ +static int dolink(const char *begin, const char *end, int newblock); /* Parser for links and images */ +static int dolist(const char *begin, const char *end, int newblock); /* Parser for lists */ +static int doparagraph(const char *begin, const char *end, int newblock); /* Parser for paragraphs */ +static int doreplace(const char *begin, const char *end, int newblock); /* Parser for simple replaces */ +static int doshortlink(const char *begin, const char *end, int newblock); /* Parser for links and images */ +static int dosurround(const char *begin, const char *end, int newblock); /* Parser for surrounding tags */ +static int dounderline(const char *begin, const char *end, int newblock); /* Parser for underline tags */ +static void *ereallocz(void *p, size_t size); +static void hprint(const char *begin, const char *end); /* escapes HTML and prints it to output */ +static void process(const char *begin, const char *end, int isblock); /* Processes range between begin and end. */ + +/* list of parsers */ +static Parser parsers[] = { dounderline, docomment, dolineprefix, + dolist, doparagraph, dogtlt, dosurround, dolink, + doshortlink, dohtml, doamp, doreplace }; +static int nohtml = 0; + +static Tag lineprefix[] = { + { " ", 0, "<pre><code>", "</code></pre>" }, + { "\t", 0, "<pre><code>", "</code></pre>" }, + { "> ", 2, "<blockquote>", "</blockquote>" }, + { "###### ", 1, "<h6>", "</h6>" }, + { "##### ", 1, "<h5>", "</h5>" }, + { "#### ", 1, "<h4>", "</h4>" }, + { "### ", 1, "<h3>", "</h3>" }, + { "## ", 1, "<h2>", "</h2>" }, + { "# ", 1, "<h1>", "</h1>" }, + { "- - -\n", 1, "<hr />", ""}, +}; + +static Tag underline[] = { + { "=", 1, "<h1>", "</h1>\n" }, + { "-", 1, "<h2>", "</h2>\n" }, +}; + +static Tag surround[] = { + { "``", 0, "<code>", "</code>" }, + { "`", 0, "<code>", "</code>" }, + { "___", 1, "<strong><em>", "</em></strong>" }, + { "***", 1, "<strong><em>", "</em></strong>" }, + { "__", 1, "<strong>", "</strong>" }, + { "**", 1, "<strong>", "</strong>" }, + { "_", 1, "<em>", "</em>" }, + { "*", 1, "<em>", "</em>" }, +}; + +static const char *replace[][2] = { + { "\\\\", "\\" }, + { "\\`", "`" }, + { "\\*", "*" }, + { "\\_", "_" }, + { "\\{", "{" }, + { "\\}", "}" }, + { "\\[", "[" }, + { "\\]", "]" }, + { "\\(", "(" }, + { "\\)", ")" }, + { "\\#", "#" }, + { "\\+", "+" }, + { "\\-", "-" }, + { "\\.", "." }, + { "\\!", "!" }, +}; + +static const char *insert[][2] = { + { " \n", "<br />" }, +}; + +void +eprint(const char *format, ...) { + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +int +doamp(const char *begin, const char *end, int newblock) { + const char *p; + + if(*begin != '&') + return 0; + if(!nohtml) { + for(p = begin + 1; p != end && !strchr("; \\\n\t", *p); p++); + if(p == end || *p == ';') + return 0; + } + fputs("&amp;", stdout); + return 1; +} + +int +dogtlt(const char *begin, const char *end, int newblock) { + int brpos; + char c; + + if(nohtml || begin + 1 >= end) + return 0; + brpos = begin[1] == '>'; + if(!brpos && *begin != '<') + return 0; + c = begin[brpos ? 0 : 1]; + if(!brpos && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) { + fputs("&lt;", stdout); + return 1; + } + else if(brpos && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && !strchr("/\"'",c)) { + fprintf(stdout, "%c&gt;",c); + return 2; + } + return 0; +} + +int +docomment(const char *begin, const char *end, int newblock) { + char *p; + + if(nohtml || strncmp("<!--", begin, 4)) + return 0; + p = strstr(begin, "-->"); + if(!p || p + 3 >= end) + return 0; + return (p + 3 - begin) * (newblock ? -1 : 1); +} + +int +dohtml(const char *begin, const char *end, int newblock) { + const char *p, *tag, *tagend; + + if(nohtml || begin + 2 >= end) + return 0; + p = begin; + if(p[0] != '<' || !isalpha(p[1])) + return 0; + p++; + tag = p; + for(; isalnum(*p) && p < end; p++); + tagend = p; + if(p > end || tag == tagend) + return 0; + while((p = strstr(p, "</")) && p < end) { + p += 2; + if(strncmp(p, tag, tagend - tag) == 0 && p[tagend - tag] == '>') { + p++; + fwrite(begin, sizeof(char), p - begin + tagend - tag + 1, stdout); + return p - begin + tagend - tag + 1; + } + } + p = strchr(tagend, '>'); + if(p) { + fwrite(begin, sizeof(char), p - begin + 2, stdout); + return p - begin + 2; + } + else + return 0; +} + +int +dolineprefix(const char *begin, const char *end, int newblock) { + unsigned int i, j, l; + char *buffer; + const char *p; + + if(newblock) + p = begin; + else if(*begin == '\n') + p = begin + 1; + else + return 0; + for(i = 0; i < LENGTH(lineprefix); i++) { + l = strlen(lineprefix[i].search); + if(end - p < l) + continue; + if(strncmp(lineprefix[i].search, p, l)) + continue; + if(*begin == '\n') + fputc('\n', stdout); + fputs(lineprefix[i].before, stdout); + if(lineprefix[i].search[l-1] == '\n') { + fputc('\n', stdout); + return l; + } + if(!(buffer = malloc(BUFSIZ))) + eprint("Malloc failed."); + buffer[0] = '\0'; + for(j = 0, p += l; p < end; p++, j++) { + ADDC(buffer, j) = *p; + if(*p == '\n' && p + l < end) { + if(strncmp(lineprefix[i].search, p + 1, l) != 0) + break; + p += l; + } + } + ADDC(buffer, j) = '\0'; + if(lineprefix[i].process) + process(buffer, buffer + strlen(buffer), lineprefix[i].process >= 2); + else + hprint(buffer, buffer + strlen(buffer)); + puts(lineprefix[i].after); + free(buffer); + return -(p - begin); + } + return 0; +} + +int +dolink(const char *begin, const char *end, int newblock) { + int img, len, sep; + const char *desc, *link, *p, *q, *descend, *linkend; + const char *title = NULL, *titleend = NULL; + + if(*begin == '[') + img = 0; + else if(strncmp(begin, "![", 2) == 0) + img = 1; + else + return 0; + p = desc = begin + 1 + img; + if(!(p = strstr(desc, "](")) || p > end) + return 0; + for(q = strstr(desc, "!["); q && q < end && q < p; q = strstr(q + 1, "![")) + if(!(p = strstr(p + 1, "](")) || p > end) + return 0; + descend = p; + link = p + 2; + if(!(q = strchr(link, ')')) || q > end) + return 0; + if((p = strpbrk(link, "\"'")) && p < end && q > p) { + sep = p[0]; /* separator: can be " or ' */ + title = p + 1; + /* strip trailing whitespace */ + for(linkend = p; linkend > link && isspace(*(linkend - 1)); linkend--); + if(!(p = strchr(title, sep)) || q > end || p > q) + return 0; + titleend = p; + len = p + 2 - begin; + } + else { + linkend = q; + len = q + 1 - begin; + } + if(img) { + fputs("<img src=\"", stdout); + hprint(link, linkend); + fputs("\" alt=\"", stdout); + hprint(desc, descend); + fputs("\" ", stdout); + if(title && titleend) { + fputs("title=\"", stdout); + hprint(title, titleend); + fputs("\" ", stdout); + } + fputs("/>", stdout); + } + else { + fputs("<a href=\"", stdout); + hprint(link, linkend); + fputs("\"", stdout); + if(title && titleend) { + fputs(" title=\"", stdout); + hprint(title, titleend); + fputs("\"", stdout); + } + fputs(">", stdout); + process(desc, descend, 0); + fputs("</a>", stdout); + } + return len; +} + +int +dolist(const char *begin, const char *end, int newblock) { + unsigned int i, j, indent, run, ul, isblock; + const char *p, *q; + char *buffer = NULL; + + isblock = 0; + if(newblock) + p = begin; + else if(*begin == '\n') + p = begin + 1; + else + return 0; + q = p; + if(*p == '-' || *p == '*' || *p == '+') + ul = 1; + else { + ul = 0; + for(; p < end && *p >= '0' && *p <= '9'; p++); + if(p >= end || *p != '.') + return 0; + } + p++; + if(p >= end || !(*p == ' ' || *p == '\t')) + return 0; + for(p++; p != end && (*p == ' ' || *p == '\t'); p++); + indent = p - q; + buffer = ereallocz(buffer, BUFSIZ); + if(!newblock) + fputc('\n', stdout); + fputs(ul ? "<ul>\n" : "<ol>\n", stdout); + run = 1; + for(; p < end && run; p++) { + for(i = 0; p < end && run; p++, i++) { + if(*p == '\n') { + if(p + 1 == end) + break; + else if(p[1] == '\n') { + p++; + ADDC(buffer, i) = '\n'; + i++; + run = 0; + isblock++; + } + q = p + 1; + j = 0; + if(ul && (*q == '-' || *q == '*' || *q == '+')) + j = 1; + else if(!ul) { + for(; q + j != end && q[j] >= '0' && q[j] <= '9' && j < indent; j++); + if(q + j == end) + break; + if(j > 0 && q[j] == '.') + j++; + else + j = 0; + } + if(q + indent < end) + for(; (q[j] == ' ' || q[j] == '\t') && j < indent; j++); + if(j == indent) { + ADDC(buffer, i) = '\n'; + i++; + p += indent; + run = 1; + if(*q == ' ' || *q == '\t') + p++; + else + break; + } + } + ADDC(buffer, i) = *p; + } + ADDC(buffer, i) = '\0'; + fputs("<li>", stdout); + process(buffer, buffer + i, isblock > 1 || (isblock == 1 && run)); + fputs("</li>\n", stdout); + } + fputs(ul ? "</ul>\n" : "</ol>\n", stdout); + free(buffer); + p--; + while(*(--p) == '\n'); + return -(p - begin + 1); +} + +int +doparagraph(const char *begin, const char *end, int newblock) { + const char *p; + + if(!newblock) + return 0; + p = strstr(begin, "\n\n"); + if(!p || p > end) + p = end; + if(p - begin <= 1) + return 0; + fputs("<p>", stdout); + process(begin, p, 0); + fputs("</p>\n", stdout); + return -(p - begin); +} + +int +doreplace(const char *begin, const char *end, int newblock) { + unsigned int i, l; + + for(i = 0; i < LENGTH(insert); i++) + if(strncmp(insert[i][0], begin, strlen(insert[i][0])) == 0) + fputs(insert[i][1], stdout); + for(i = 0; i < LENGTH(replace); i++) { + l = strlen(replace[i][0]); + if(end - begin < l) + continue; + if(strncmp(replace[i][0], begin, l) == 0) { + fputs(replace[i][1], stdout); + return l; + } + } + return 0; +} + +int +doshortlink(const char *begin, const char *end, int newblock) { + const char *p, *c; + int ismail = 0; + + if(*begin != '<') + return 0; + for(p = begin + 1; p != end; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + return 0; + case '#': + case ':': + ismail = -1; + break; + case '@': + if(ismail == 0) + ismail = 1; + break; + case '>': + if(ismail == 0) + return 0; + fputs("<a href=\"", stdout); + if(ismail == 1) { + /* mailto: */ + fputs("&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:", stdout); + for(c = begin + 1; *c != '>'; c++) + fprintf(stdout, "&#%u;", *c); + fputs("\">", stdout); + for(c = begin + 1; *c != '>'; c++) + fprintf(stdout, "&#%u;", *c); + } + else { + hprint(begin + 1, p); + fputs("\">", stdout); + hprint(begin + 1, p); + } + fputs("</a>", stdout); + return p - begin + 1; + } + } + return 0; +} + +int +dosurround(const char *begin, const char *end, int newblock) { + unsigned int i, l; + const char *p, *start, *stop; + + for(i = 0; i < LENGTH(surround); i++) { + l = strlen(surround[i].search); + if(end - begin < 2*l || strncmp(begin, surround[i].search, l) != 0) + continue; + start = begin + l; + p = start - 1; + do { + stop = p; + p = strstr(p + 1, surround[i].search); + } while(p && p[-1] == '\\'); + if (p && p[-1] != '\\') + stop = p; + if(!stop || stop < start || stop >= end) + continue; + fputs(surround[i].before, stdout); + if(surround[i].process) + process(start, stop, 0); + else + hprint(start, stop); + fputs(surround[i].after, stdout); + return stop - begin + l; + } + return 0; +} + +int +dounderline(const char *begin, const char *end, int newblock) { + unsigned int i, j, l; + const char *p; + + if(!newblock) + return 0; + p = begin; + for(l = 0; p + l != end && p[l] != '\n'; l++); + p += l + 1; + if(l == 0) + return 0; + for(i = 0; i < LENGTH(underline); i++) { + for(j = 0; p + j != end && p[j] != '\n' && p[j] == underline[i].search[0]; j++); + if(j >= l) { + fputs(underline[i].before, stdout); + if(underline[i].process) + process(begin, begin + l, 0); + else + hprint(begin, begin + l); + fputs(underline[i].after, stdout); + return -(j + p - begin); + } + } + return 0; +} + +void * +ereallocz(void *p, size_t size) { + void *res; + if(p) + res = realloc(p , size); + else + res = calloc(1, size); + + if(!res) + eprint("fatal: could not malloc() %u bytes\n", size); + return res; +} + +void +hprint(const char *begin, const char *end) { + const char *p; + + for(p = begin; p != end; p++) { + if(*p == '&') + fputs("&amp;", stdout); + else if(*p == '"') + fputs("&quot;", stdout); + else if(*p == '>') + fputs("&gt;", stdout); + else if(*p == '<') + fputs("&lt;", stdout); + else + fputc(*p, stdout); + } +} + +void +process(const char *begin, const char *end, int newblock) { + const char *p, *q; + int affected; + unsigned int i; + + for(p = begin; p < end;) { + if(newblock) + while(*p == '\n') + if(++p == end) + return; + affected = 0; + for(i = 0; i < LENGTH(parsers) && !affected; i++) + affected = parsers[i](p, end, newblock); + p += abs(affected); + if(!affected) { + if(nohtml) + hprint(p, p + 1); + else + fputc(*p, stdout); + p++; + } + for(q = p; q != end && *q == '\n'; q++); + if(q == end) + return; + else if(p[0] == '\n' && p + 1 != end && p[1] == '\n') + newblock = 1; + else + newblock = affected < 0; + } +} + +int +main(int argc, char *argv[]) { + char *buffer = NULL; + int s, i; + unsigned long len, bsize; + FILE *source = stdin; + + for(i = 1; i < argc; i++) { + if(!strcmp("-v", argv[i])) + eprint("simple markup %s (C) Enno Boland\n",VERSION); + else if(!strcmp("-n", argv[i])) + nohtml = 1; + else if(argv[i][0] != '-') + break; + else if(!strcmp("--", argv[i])) { + i++; + break; + } + else + eprint("Usage %s [-n] [file]\n -n escape html strictly\n", argv[0]); + } + if(i < argc && !(source = fopen(argv[i], "r"))) + eprint("Cannot open file `%s`\n",argv[i]); + bsize = 2 * BUFSIZ; + buffer = ereallocz(buffer, bsize); + len = 0; + while((s = fread(buffer + len, 1, BUFSIZ, source))) { + len += s; + if(BUFSIZ + len + 1 > bsize) { + bsize += BUFSIZ; + if(!(buffer = realloc(buffer, bsize))) + eprint("realloc failed."); + } + } + buffer[len] = '\0'; + process(buffer, buffer + len, 1); + fclose(source); + free(buffer); + return EXIT_SUCCESS; +} diff --git a/smu.h b/smu.h @@ -0,0 +1,19 @@ +/* libsmu - simple markup library + * Copyright (C) <2007, 2008> Enno Boland <g s01 de> + * + * See LICENSE for further informations + */ +#include <stdio.h> + +/** + * Converts contents of a simple markup stream (in) and prints them to out. + * If suppresshtml == 1, it will create plain text of the simple markup instead + * of HTML. + * + * Returns 0 on success. + */ +int smu_convert(FILE *out, FILE *in, int suppresshtml); + +/** utility */ +void eprint(const char *format, ...); + diff --git a/testdoc b/testdoc @@ -0,0 +1,80 @@ +smu test +======== + +simple tests +------------ + +first paragraph. +testing surround: _emph_ then **strong** and `code`. + +`\`escaped backticks\``. + +`x = *y * 6;` + +horizontal rule: + +- - - + + +blocks and entities +------------------- + +preformatted block: + .'''' .'.'. | | + '''. | ' | | | + '''' ' ' "" + +quoted text: +> When in doubt, +> use brute force. + +list: +* Make each program do one thing well. +* Expect the output of every program to become the input to another, +as yet unknown, program. +* Design and build software, even operating systems, to be tried early, +ideally within weeks. +* Use tools in preference to unskilled help to lighten a programming task. + +list in list: +* a + * b + 1. c + 2. d + * e +* f + +entity: &, <, > + +code: + int powerof2(unsigned int n) { + return !((n - 1) & n) && n > 0; + } + +links +----- + +link: [suckless](http://suckless.org/) + +link with title: [suckless](http://suckless.org/ "software that sucks less") + +link with title (single quote): [suckless](http://suckless.org/ 'software that sucks less') + + +images +------ + +image: ![](http://st.suckless.org/screenshots/20h-2012-s.png) + +image with alt text: ![alt text](http://st.suckless.org/screenshots/20h-2012-s.png) + +image with title: ![alt text](http://st.suckless.org/screenshots/20h-2012-s.png "screenshot of st") + +image with title (single quote): ![alt text](http://st.suckless.org/screenshots/20h-2012-s.png 'screenshot of st') + +inline html +----------- + +<center> + ABC +</center>