diff options
Diffstat (limited to 'cmarkdown.c')
| -rw-r--r-- | cmarkdown.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/cmarkdown.c b/cmarkdown.c new file mode 100644 index 0000000..2b7807c --- /dev/null +++ b/cmarkdown.c @@ -0,0 +1,287 @@ +/* cmarkdown + * Copyright (C) <2007> Enno boland <g@s01.de> + * + * cmarkdown free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * To compile type + * gcc -DVERSION=\"`date +%F`\" -o cmarkdown cmarkdown.c + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#define BUFFERSIZE 1024 +#define ERRMALLOC eprint("malloc failed\n"); +#define LENGTH(x) sizeof(x)/sizeof(x[0]) + +typedef unsigned int (*Parser)(const char *, const char *); +struct Tag { + char *search; + int process; + char *tag; +}; + +void eprint(const char *errstr, ...); /* Prints error and exits */ +void process(const char *begin, const char *end); + /* Processes range between begin and end with parser (NULL = all parsers) */ +unsigned int doreplace(const char *begin, const char *end); + /* Parser for simple replaces */ +unsigned int dolineprefix(const char *begin, const char *end); + /* Parser for line prefix tags */ +unsigned int dosurround(const char *begin, const char *end); + /* Parser for surrounding tags */ +unsigned int dounderline(const char *begin, const char *end); + /* Parser for underline tags */ +unsigned int dolink(const char *begin, const char *end); + /* Parser for links and images */ +Parser parsers[] = { dounderline, dolineprefix, dosurround, dolink, doreplace }; + /* list of parsers */ + +FILE *source; +unsigned int bsize = 0; +struct Tag lineprefix[] = { + { " ", 0, "pre" }, + { "\t", 0, "pre" }, + { "> ", 1, "blockquote" }, +}; +struct Tag underline[] = { + { "=", 1, "h1" }, + { "-", 1, "h2" }, +}; +struct Tag surround[] = { + { "``", 0, "code" }, + { "`", 0, "code" }, + { "__", 1, "strong" }, + { "**", 1, "strong" }, + { "*", 1, "em" }, + { "_", 1, "em" }, +}; +char * replace[][2] = { + { "\n---\n", "\n<hr />\n" }, + { "\n\n", "<br />\n<br />\n" }, + { "<", "<" }, + { ">", ">" }, + { "&", "&" }, + { "\"", """ }, +}; + +void +eprint(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +unsigned int +dolink(const char *begin, const char *end) { + int img; + const char *desc, *link, *p; + unsigned int desclen, linklen; + + if(*begin != '[' && strncmp(begin,") || p > end) + return 0; + desclen = p - desc; + link = p + 2; + if(!(p = strstr(link, ")")) || p > end) + return 0; + linklen = p - link; + + if(img) { + fputs("<img src=\"",stdout); + process(link,link+linklen); + fputs("\" alt=\"",stdout); + process(desc,desc+desclen); + fputs("\" />",stdout); + } + else { + fputs("<a href=\"",stdout); + process(link,link+linklen); + fputs("\">",stdout); + process(desc,desc+desclen); + fputs("</a>",stdout); + } + return p + 1 - begin; +} + +unsigned int +dosurround(const char *begin, const char *end) { + unsigned int i,l; + const char *p,*ps; + + for(i = 0; i < LENGTH(surround); i++) { + l = strlen(surround[i].search); + if(end - begin < l || strncmp(begin,surround[i].search,l) != 0) + continue; + for(ps = surround[i].search; *ps == '\n'; ps++); + l = strlen(ps); + p = begin + strlen(surround[i].search) - 1; + do { + p = strstr(p+1, ps); + } while(p && p[-1] == '\\'); + if(!p || p > end) + continue; + printf("<%s>",surround[i].tag); + if(surround[i].process) + process(begin + strlen(surround[i].search), p); + else + fwrite(begin + strlen(surround[i].search), p - begin - l, sizeof(char), stdout); + printf("</%s>",surround[i].tag); + return p - begin + l; + } + return 0; +} +unsigned int +doreplace(const char *begin, const char *end) { + unsigned int i, l; + + 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; +} + +unsigned int +dolineprefix(const char *begin, const char *end) { + unsigned int i, j, l; + char *buffer; + const char *p; + + if(*begin != '\n' && *begin != '\0') + return 0; + for(i = 0; i < LENGTH(lineprefix); i++) { + l = strlen(lineprefix[i].search); + if(end - begin+1 < l) + continue; + if(strncmp(lineprefix[i].search,begin+1,l)) + continue; + + if(!(buffer = malloc(end - begin+1))) + ERRMALLOC; + printf("<%s>",surround[i].tag); + for(p = begin, j = 0; p != end; p++, j++) { + buffer[j] = *p; + if(*p == '\n') { + if(strncmp(lineprefix[i].search,p+1,l) != 0) + break; + p += l; + } + } + if(lineprefix[i].process) + process(buffer,buffer+strlen(buffer)); + else + fwrite(buffer,strlen(buffer), sizeof(char),stdout); + printf("</%s>",surround[i].tag); + free(buffer); + return p - begin; + } + return 0; +} + +unsigned int +dounderline(const char *begin, const char *end) { + unsigned int i, j, l; + const char *p; + + if(*begin != '\n' && *begin != '\0') + return 0; + for(p = begin+1,l = 0; p[l] != '\n' && p[l] && p+l != end; l++); + p += l + 1; + if(l == 0) + return 0; + for(i = 0; i < LENGTH(underline); i++) { + for(j = 0; p[j] != '\n' && p[j] == underline[i].search[0] && p+j != end; j++); + if(j >= l) { + putchar('\n'); + printf("<%s>",underline[i].tag); + if(underline[i].process) + process(begin+1, begin + l + 1); + else + fwrite(begin+1,l,sizeof(char),stdout); + printf("</%s>",underline[i].tag); + return j + l + 2; + } + } + return 0; +} + +void +process(const char *begin, const char *end) { + const char *p; + int affected; + unsigned int i; + + for(p = begin; *p && p != end;) { + affected = 0; + for(i = 0; i < LENGTH(parsers) && affected == 0; i++) + affected = parsers[i](p, end); + if(affected == 0) { + putchar(*p); + p++; + } + else + p += affected; + } +} + +int +main(int argc, char *argv[]) { + char *p, *buffer; + int s; + + source = stdin; + if(argc > 1 && strcmp("-v", argv[1]) == 0) + eprint("markdown in C "VERSION" (C) Enno Boland\n"); + else if(argc > 1 && strcmp("-h", argv[1]) == 0) + eprint("Usage %s [file]\n",argv[0]); + else if (argc > 1 && strcmp("-", argv[1]) != 0 && !(source = fopen(argv[1],"r"))) + eprint("Cannot open file `%s`\n",argv[1]); + if(!(buffer = malloc(BUFFERSIZE))) + ERRMALLOC; + bsize = BUFFERSIZE; + /* needed to properly process first line */ + strcpy(buffer,"\n"); + + p = buffer+strlen(buffer); + while(s = fread(p, sizeof(char),BUFFERSIZE, source)) { + p += s; + *p = '\0'; + if(BUFFERSIZE + strlen(buffer) > bsize) { + bsize += BUFFERSIZE; + if(!(buffer = realloc(buffer, bsize))) + ERRMALLOC; + } + } + + process(buffer,buffer+strlen(buffer)); + free(buffer); +} |