diff --git a/Makefile b/Makefile index 56e1597..ae5f92c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS = -g -O3 -Wall -Wextra -Wno-unused-parameter -Isrc +CFLAGS = -g -O3 -ansi -pedantic -Wall -Wextra -Wno-unused-parameter -Isrc ifneq ($(OS),Windows_NT) CFLAGS += -fPIC @@ -63,3 +63,6 @@ clean: %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< + +src/html_blocks.o: src/html_blocks.c + $(CC) $(CFLAGS) -Wno-static-in-inline -c -o $@ $< diff --git a/bin/common.h b/bin/common.h index 9074bd6..5d55acc 100644 --- a/bin/common.h +++ b/bin/common.h @@ -11,7 +11,8 @@ #define count_of(arr) (sizeof(arr)/sizeof(0[arr])) int -parseint(const char *string, long *result) { +parseint(const char *string, long *result) +{ char *end; errno = 0; *result = strtol(string, &end, 10); @@ -19,7 +20,8 @@ parseint(const char *string, long *result) { } const char * -strprefix(const char *str, const char *prefix) { +strprefix(const char *str, const char *prefix) +{ while (*prefix) { if (!(*str && *str == *prefix)) return 0; prefix++; str++; @@ -28,7 +30,8 @@ strprefix(const char *str, const char *prefix) { } void -print_option(char short_opt, const char *long_opt, const char *description) { +print_option(char short_opt, const char *long_opt, const char *description) +{ if (short_opt) printf(" -%c, ", short_opt); else @@ -38,8 +41,68 @@ print_option(char short_opt, const char *long_opt, const char *description) { } void -print_version() { - int major, minor, revision; - hoedown_version(&major, &minor, &revision); - printf("Built with Hoedown v%d.%d.%d.\n", major, minor, revision); +print_version() +{ + printf("Built with Hoedown " HOEDOWN_VERSION ".\n"); +} + +int +parse_options( + int argc, char **argv, + int(*parse_short_option)(char opt, char *next, void *opaque), + int(*parse_long_option)(char *opt, char *next, void *opaque), + int(*parse_argument)(int argn, char *arg, int is_forced, void *opaque), + void *opaque) +{ + int result; + int i = 1, regular_args = 0; + + /* Parse options mixed with arguments */ + while (i < argc) { + char *arg = argv[i]; + + if (arg[0] == '-' && arg[1]) { + char *next_arg = (i+1 < argc) ? argv[i+1] : NULL; + + if (arg[1] == '-' && !arg[2]) { + /* '--' signals end of options */ + i++; + break; + } + + if (arg[1] == '-') { + /* Long option */ + result = parse_long_option(arg + 2, next_arg, opaque); + if (!result) return 0; + i += result; + } else { + /* Sequence of short options */ + size_t pos; + for (pos = 1; arg[pos]; pos++) { + char *next = (arg[pos+1]) ? arg + pos+1 : next_arg; + result = parse_short_option(arg[pos], next, opaque); + if (!result) return 0; + if (result == 2) { + i++; + break; + } + } + i++; + } + } else { + /* Argument */ + result = parse_argument(regular_args++, arg, 0, opaque); + if (!result) return 0; + i++; + } + } + + /* Parse rest as forced arguments */ + while (i < argc) { + result = parse_argument(regular_args++, argv[i], 1, opaque); + if (!result) return 0; + i++; + } + + return 1; } diff --git a/bin/hoedown.c b/bin/hoedown.c index 15f2e61..5aac21a 100644 --- a/bin/hoedown.c +++ b/bin/hoedown.c @@ -2,32 +2,16 @@ #include "html.h" #include "common.h" -//#include - -/* NULL RENDERER */ - -enum renderer_type { - RENDERER_HTML, - RENDERER_HTML_TOC, - RENDERER_NULL, -}; - -hoedown_renderer * -null_renderer_new() { - hoedown_renderer *rend = malloc(sizeof(hoedown_renderer)); - if (rend) - memset(rend, 0x00, sizeof(hoedown_renderer)); - return rend; -} - -void -null_renderer_free(hoedown_renderer *rend) { - free(rend); -} +/*#include */ /* FEATURES INFO / DEFAULTS */ +enum renderer_type { + RENDERER_HTML, + RENDERER_HTML_TOC +}; + struct extension_category_info { unsigned int flags; const char *option_name; @@ -91,7 +75,11 @@ static const char *negative_prefix = "no-"; /* PRINT HELP */ void -print_help(const char *basename) { +print_help(const char *basename) +{ + size_t i; + size_t e; + /* usage */ printf("Usage: %s [OPTION]... [FILE]\n\n", basename); @@ -105,7 +93,6 @@ print_help(const char *basename) { print_option('t', "toc-level=N", "Maximum level for headers included in the TOC. Zero disables TOC (the default)."); print_option( 0, "html", "Render (X)HTML. The default."); print_option( 0, "html-toc", "Render the Table of Contents in (X)HTML."); - print_option( 0, "null", "Use a special \"null\" renderer that has no callbacks."); print_option('T', "time", "Show time spent in rendering."); print_option('i', "input-unit=N", "Reading block size. Default is " str(DEF_IUNIT) "."); print_option('o', "output-unit=N", "Writing block size. Default is " str(DEF_OUNIT) "."); @@ -114,8 +101,6 @@ print_help(const char *basename) { printf("\n"); /* extensions */ - size_t i; - size_t e; for (i = 0; i < count_of(categories_info); i++) { struct extension_category_info *category = categories_info+i; printf("%s (--%s%s):\n", category->label, category_prefix, category->option_name); @@ -145,320 +130,320 @@ print_help(const char *basename) { } +/* OPTION PARSING */ + +struct option_data { + char *basename; + int done; + + /* time reporting */ + int show_time; + + /* I/O */ + size_t iunit; + size_t ounit; + const char *filename; + + /* renderer */ + enum renderer_type renderer; + int toc_level; + hoedown_html_flags html_flags; + + /* parsing */ + hoedown_extensions extensions; + size_t max_nesting; +}; + +int +parse_short_option(char opt, char *next, void *opaque) +{ + struct option_data *data = opaque; + long int num; + int isNum = next ? parseint(next, &num) : 0; + + if (opt == 'h') { + print_help(data->basename); + data->done = 1; + return 0; + } + + if (opt == 'v') { + print_version(); + data->done = 1; + return 0; + } + + if (opt == 'T') { + data->show_time = 1; + return 1; + } + + /* options requiring value */ + /* FIXME: add validation */ + + if (opt == 'n' && isNum) { + data->max_nesting = num; + return 2; + } + + if (opt == 't' && isNum) { + data->toc_level = num; + return 2; + } + + if (opt == 'i' && isNum) { + data->iunit = num; + return 2; + } + + if (opt == 'o' && isNum) { + data->ounit = num; + return 2; + } + + fprintf(stderr, "Wrong option '-%c' found.\n", opt); + return 0; +} + +int +parse_category_option(char *opt, struct option_data *data) +{ + size_t i; + const char *name = strprefix(opt, category_prefix); + if (!name) return 0; + + for (i = 0; i < count_of(categories_info); i++) { + struct extension_category_info *category = &categories_info[i]; + if (strcmp(name, category->option_name)==0) { + data->extensions |= category->flags; + return 1; + } + } + + return 0; +} + +int +parse_flag_option(char *opt, struct option_data *data) +{ + size_t i; + + for (i = 0; i < count_of(extensions_info); i++) { + struct extension_info *extension = &extensions_info[i]; + if (strcmp(opt, extension->option_name)==0) { + data->extensions |= extension->flag; + return 1; + } + } + + for (i = 0; i < count_of(html_flags_info); i++) { + struct html_flag_info *html_flag = &html_flags_info[i]; + if (strcmp(opt, html_flag->option_name)==0) { + data->html_flags |= html_flag->flag; + return 1; + } + } + + return 0; +} + +int +parse_negative_option(char *opt, struct option_data *data) +{ + size_t i; + const char *name = strprefix(opt, negative_prefix); + if (!name) return 0; + + for (i = 0; i < count_of(categories_info); i++) { + struct extension_category_info *category = &categories_info[i]; + if (strcmp(name, category->option_name)==0) { + data->extensions &= ~(category->flags); + return 1; + } + } + + for (i = 0; i < count_of(extensions_info); i++) { + struct extension_info *extension = &extensions_info[i]; + if (strcmp(name, extension->option_name)==0) { + data->extensions &= ~(extension->flag); + return 1; + } + } + + for (i = 0; i < count_of(html_flags_info); i++) { + struct html_flag_info *html_flag = &html_flags_info[i]; + if (strcmp(name, html_flag->option_name)==0) { + data->html_flags &= ~(html_flag->flag); + return 1; + } + } + + return 0; +} + +int +parse_long_option(char *opt, char *next, void *opaque) +{ + struct option_data *data = opaque; + long int num; + int isNum = next ? parseint(next, &num) : 0; + + if (strcmp(opt, "help")==0) { + print_help(data->basename); + data->done = 1; + return 0; + } + + if (strcmp(opt, "version")==0) { + print_version(); + data->done = 1; + return 0; + } + + if (strcmp(opt, "time")==0) { + data->show_time = 1; + return 1; + } + + /* FIXME: validation */ + + if (strcmp(opt, "max-nesting")==0 && isNum) { + data->max_nesting = num; + return 2; + } + if (strcmp(opt, "toc-level")==0 && isNum) { + data->toc_level = num; + return 2; + } + if (strcmp(opt, "input-unit")==0 && isNum) { + data->iunit = num; + return 2; + } + if (strcmp(opt, "output-unit")==0 && isNum) { + data->ounit = num; + return 2; + } + + if (strcmp(opt, "html")==0) { + data->renderer = RENDERER_HTML; + return 1; + } + if (strcmp(opt, "html-toc")==0) { + data->renderer = RENDERER_HTML_TOC; + return 1; + } + + if (parse_category_option(opt, data) || parse_flag_option(opt, data) || parse_negative_option(opt, data)) + return 1; + + fprintf(stderr, "Wrong option '--%s' found.\n", opt); + return 0; +} + +int +parse_argument(int argn, char *arg, int is_forced, void *opaque) +{ + struct option_data *data = opaque; + + if (argn == 0) { + /* Input file */ + if (strcmp(arg, "-")!=0 || is_forced) data->filename = arg; + return 1; + } + + fprintf(stderr, "Too many arguments.\n"); + return 0; +} + + /* MAIN LOGIC */ int main(int argc, char **argv) { - int show_time = 0; - //struct timespec start, end; - - /* buffers */ + struct option_data data; + /*struct timespec start, end;*/ + FILE *file = stdin; hoedown_buffer *ib, *ob; - size_t iunit = DEF_IUNIT, ounit = DEF_OUNIT; - - /* files */ - FILE *in = NULL; - - /* renderer */ - int toc_level = 0; - int renderer_type = RENDERER_HTML; - - /* document */ + hoedown_renderer *renderer = NULL; + void (*renderer_free)(hoedown_renderer *) = NULL; hoedown_document *document; - unsigned int extensions = 0; - size_t max_nesting = DEF_MAX_NESTING; - /* HTML renderer-specific */ - unsigned int html_flags = 0; + /* Parse options */ + data.basename = argv[0]; + data.done = 0; + data.show_time = 0; + data.iunit = DEF_IUNIT; + data.ounit = DEF_OUNIT; + data.filename = NULL; + data.renderer = RENDERER_HTML; + data.toc_level = 0; + data.html_flags = 0; + data.extensions = 0; + data.max_nesting = DEF_MAX_NESTING; + argc = parse_options(argc, argv, parse_short_option, parse_long_option, parse_argument, &data); + if (data.done) return 0; + if (!argc) return 1; - /* option parsing */ - int just_args = 0; - int i, j; - for (i = 1; i < argc; i++) { - char *arg = argv[i]; - if (!arg[0]) continue; - - if (just_args || arg[0] != '-') { - /* regular argument */ - in = fopen(arg, "r"); - if (!in) { - fprintf(stderr, "Unable to open input file \"%s\": %s\n", arg, strerror(errno)); - return 5; - } - continue; - } - - if (!arg[1]) { - /* arg is "-" */ - in = stdin; - continue; - } - - if (arg[1] != '-') { - /* parse short options */ - char opt; - const char *val; - for (j = 1; (opt = arg[j]); j++) { - if (opt == 'h') { - print_help(argv[0]); - return 1; - } - - if (opt == 'v') { - print_version(); - return 1; - } - - if (opt == 'T') { - show_time = 1; - continue; - } - - /* options requiring value */ - if (arg[++j]) val = arg+j; - else if (argv[++i]) val = argv[i]; - else { - fprintf(stderr, "Wrong option '-%c' found.\n", opt); - return 1; - } - - long int num; - int isNum = parseint(val, &num); - - if (opt == 'n' && isNum) { - max_nesting = num; - break; - } - - if (opt == 't' && isNum) { - toc_level = num; - break; - } - - if (opt == 'i' && isNum) { - iunit = num; - break; - } - - if (opt == 'o' && isNum) { - ounit = num; - break; - } - - fprintf(stderr, "Wrong option '-%c' found.\n", opt); - return 1; - } - continue; - } - - if (!arg[2]) { - /* arg is "--" */ - just_args = 1; - continue; - } - - /* parse long option */ - char opt [100]; - strncpy(opt, arg+2, 100); - opt[99] = 0; - - char *val = strchr(opt, '='); - - long int num = 0; - int isNum = 0; - - if (val) { - *val = 0; - val++; - - if (*val) - isNum = parseint(val, &num); - } - - int opt_parsed = 0; - - if (strcmp(opt, "help")==0) { - print_help(argv[0]); - return 1; - } - - if (strcmp(opt, "version")==0) { - print_version(); - return 1; - } - - if (strcmp(opt, "max-nesting")==0 && isNum) { - opt_parsed = 1; - max_nesting = num; - } - if (strcmp(opt, "toc-level")==0 && isNum) { - opt_parsed = 1; - toc_level = num; - } - if (strcmp(opt, "input-unit")==0 && isNum) { - opt_parsed = 1; - iunit = num; - } - if (strcmp(opt, "output-unit")==0 && isNum) { - opt_parsed = 1; - ounit = num; - } - - if (strcmp(opt, "html")==0) { - opt_parsed = 1; - renderer_type = RENDERER_HTML; - } - if (strcmp(opt, "html-toc")==0) { - opt_parsed = 1; - renderer_type = RENDERER_HTML_TOC; - } - if (strcmp(opt, "null")==0) { - opt_parsed = 1; - renderer_type = RENDERER_NULL; - } - - const char *name; - size_t i; - - /* extension categories */ - if ((name = strprefix(opt, category_prefix))) { - for (i = 0; i < count_of(categories_info); i++) { - struct extension_category_info *category = categories_info+i; - if (strcmp(name, category->option_name)==0) { - opt_parsed = 1; - extensions |= category->flags; - break; - } - } - } - - /* extensions */ - for (i = 0; i < count_of(extensions_info); i++) { - struct extension_info *extension = extensions_info+i; - if (strcmp(opt, extension->option_name)==0) { - opt_parsed = 1; - extensions |= extension->flag; - break; - } - } - - /* html flags */ - for (i = 0; i < count_of(html_flags_info); i++) { - struct html_flag_info *html_flag = html_flags_info+i; - if (strcmp(opt, html_flag->option_name)==0) { - opt_parsed = 1; - html_flags |= html_flag->flag; - break; - } - } - - /* negations */ - if ((name = strprefix(opt, negative_prefix))) { - for (i = 0; i < count_of(categories_info); i++) { - struct extension_category_info *category = categories_info+i; - if (strcmp(name, category->option_name)==0) { - opt_parsed = 1; - extensions &= ~(category->flags); - break; - } - } - for (i = 0; i < count_of(extensions_info); i++) { - struct extension_info *extension = extensions_info+i; - if (strcmp(name, extension->option_name)==0) { - opt_parsed = 1; - extensions &= ~(extension->flag); - break; - } - } - for (i = 0; i < count_of(html_flags_info); i++) { - struct html_flag_info *html_flag = html_flags_info+i; - if (strcmp(name, html_flag->option_name)==0) { - opt_parsed = 1; - html_flags &= ~(html_flag->flag); - break; - } - } - } - - if (strcmp(opt, "time")==0) { - opt_parsed = 1; - show_time = 1; - } - - if (!opt_parsed) { - fprintf(stderr, "Wrong option '%s' found.\n", arg); - return 1; + /* Open input file, if needed */ + if (data.filename) { + file = fopen(data.filename, "r"); + if (!file) { + fprintf(stderr, "Unable to open input file \"%s\": %s\n", data.filename, strerror(errno)); + return 5; } } - if (!in) - in = stdin; + /* Read everything */ + ib = hoedown_buffer_new(data.iunit); - - /* reading everything */ - ib = hoedown_buffer_new(iunit); - - while (!feof(in)) { - if (ferror(in)) { + while (!feof(file)) { + if (ferror(file)) { fprintf(stderr, "I/O errors found while reading input.\n"); return 5; } - hoedown_buffer_grow(ib, ib->size + iunit); - ib->size += fread(ib->data + ib->size, 1, iunit, in); + hoedown_buffer_grow(ib, ib->size + data.iunit); + ib->size += fread(ib->data + ib->size, 1, data.iunit, file); } - if (in != stdin) - fclose(in); + if (file != stdin) fclose(file); - - /* creating the renderer */ - hoedown_renderer *renderer = NULL; - void (*renderer_free)(hoedown_renderer*) = NULL; - - switch (renderer_type) { + /* Create the renderer */ + switch (data.renderer) { case RENDERER_HTML: - renderer = hoedown_html_renderer_new(html_flags, toc_level); + renderer = hoedown_html_renderer_new(data.html_flags, data.toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_HTML_TOC: - renderer = hoedown_html_toc_renderer_new(toc_level); + renderer = hoedown_html_toc_renderer_new(data.toc_level); renderer_free = hoedown_html_renderer_free; break; - case RENDERER_NULL: - renderer = null_renderer_new(); - renderer_free = null_renderer_free; - break; }; + /* Perform Markdown rendering */ + ob = hoedown_buffer_new(data.ounit); + document = hoedown_document_new(renderer, data.extensions, data.max_nesting); - /* performing markdown rendering */ - ob = hoedown_buffer_new(ounit); - document = hoedown_document_new(renderer, extensions, max_nesting); - - //clock_gettime(CLOCK_MONOTONIC, &start); + /*clock_gettime(CLOCK_MONOTONIC, &start);*/ hoedown_document_render(document, ob, ib->data, ib->size); - //clock_gettime(CLOCK_MONOTONIC, &end); + /*clock_gettime(CLOCK_MONOTONIC, &end);*/ - - /* writing the result to stdout */ + /* Write the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); - - /* showing rendering time */ - if (show_time) { - //TODO: enable this - //long long elapsed = ( end.tv_sec*1000000000 + end.tv_nsec) - // - (start.tv_sec*1000000000 + start.tv_nsec); - //if (elapsed < 1000000000) - // fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1000000); - //else - // fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1000000000); + /* Show rendering time */ + if (data.show_time) { + /*TODO: enable this + long long elapsed = (end.tv_sec - start.tv_sec)*1e9 + (end.tv_nsec - start.tv_nsec); + if (elapsed < 1e9) + fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1e6); + else + fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1e9); + */ } - - /* cleanup */ + /* Cleanup */ hoedown_buffer_free(ib); hoedown_buffer_free(ob); diff --git a/bin/smartypants.c b/bin/smartypants.c index d67165a..de0512e 100644 --- a/bin/smartypants.c +++ b/bin/smartypants.c @@ -1,17 +1,20 @@ #include "html.h" #include "common.h" -//#include +/*#include */ + + +/* FEATURES INFO / DEFAULTS */ #define DEF_IUNIT 1024 #define DEF_OUNIT 64 -#define DEF_MAX_NESTING 16 /* PRINT HELP */ void -print_help(const char *basename) { +print_help(const char *basename) +{ /* usage */ printf("Usage: %s [OPTION]... [FILE]\n\n", basename); @@ -35,193 +38,184 @@ print_help(const char *basename) { } +/* OPTION PARSING */ + +struct option_data { + char *basename; + int done; + + /* time reporting */ + int show_time; + + /* I/O */ + size_t iunit; + size_t ounit; + const char *filename; +}; + +int +parse_short_option(char opt, char *next, void *opaque) +{ + struct option_data *data = opaque; + long int num; + int isNum = next ? parseint(next, &num) : 0; + + if (opt == 'h') { + print_help(data->basename); + data->done = 1; + return 0; + } + + if (opt == 'v') { + print_version(); + data->done = 1; + return 0; + } + + if (opt == 'T') { + data->show_time = 1; + return 1; + } + + /* options requiring value */ + /* FIXME: add validation */ + + if (opt == 'i' && isNum) { + data->iunit = num; + return 2; + } + + if (opt == 'o' && isNum) { + data->ounit = num; + return 2; + } + + fprintf(stderr, "Wrong option '-%c' found.\n", opt); + return 0; +} + +int +parse_long_option(char *opt, char *next, void *opaque) +{ + struct option_data *data = opaque; + long int num; + int isNum = next ? parseint(next, &num) : 0; + + if (strcmp(opt, "help")==0) { + print_help(data->basename); + data->done = 1; + return 0; + } + + if (strcmp(opt, "version")==0) { + print_version(); + data->done = 1; + return 0; + } + + if (strcmp(opt, "time")==0) { + data->show_time = 1; + return 1; + } + + /* FIXME: validation */ + + if (strcmp(opt, "input-unit")==0 && isNum) { + data->iunit = num; + return 2; + } + if (strcmp(opt, "output-unit")==0 && isNum) { + data->ounit = num; + return 2; + } + + fprintf(stderr, "Wrong option '--%s' found.\n", opt); + return 0; +} + +int +parse_argument(int argn, char *arg, int is_forced, void *opaque) +{ + struct option_data *data = opaque; + + if (argn == 0) { + /* Input file */ + if (strcmp(arg, "-")!=0 || is_forced) data->filename = arg; + return 1; + } + + fprintf(stderr, "Too many arguments.\n"); + return 0; +} + + /* MAIN LOGIC */ int main(int argc, char **argv) { - int show_time = 0; - //struct timespec start, end; - - /* buffers */ + struct option_data data; + /*struct timespec start, end;*/ + FILE *file = stdin; hoedown_buffer *ib, *ob; - size_t iunit = DEF_IUNIT, ounit = DEF_OUNIT; - /* files */ - FILE *in = NULL; + /* Parse options */ + data.basename = argv[0]; + data.done = 0; + data.show_time = 0; + data.iunit = DEF_IUNIT; + data.ounit = DEF_OUNIT; + data.filename = NULL; + argc = parse_options(argc, argv, parse_short_option, parse_long_option, parse_argument, &data); + if (data.done) return 0; + if (!argc) return 1; - /* option parsing */ - int just_args = 0; - int i, j; - for (i = 1; i < argc; i++) { - char *arg = argv[i]; - if (!arg[0]) continue; - - if (just_args || arg[0] != '-') { - /* regular argument */ - in = fopen(arg, "r"); - if (!in) { - fprintf(stderr, "Unable to open input file \"%s\": %s\n", arg, strerror(errno)); - return 5; - } - continue; - } - - if (!arg[1]) { - /* arg is "-" */ - in = stdin; - continue; - } - - if (arg[1] != '-') { - /* parse short options */ - char opt; - const char *val; - for (j = 1; (opt = arg[j]); j++) { - if (opt == 'h') { - print_help(argv[0]); - return 1; - } - - if (opt == 'v') { - print_version(); - return 1; - } - - if (opt == 'T') { - show_time = 1; - continue; - } - - /* options requiring value */ - if (arg[++j]) val = arg+j; - else if (argv[++i]) val = argv[i]; - else { - fprintf(stderr, "Wrong option '-%c' found.\n", opt); - return 1; - } - - long int num; - int isNum = parseint(val, &num); - - if (opt == 'i' && isNum) { - iunit = num; - break; - } - - if (opt == 'o' && isNum) { - ounit = num; - break; - } - - fprintf(stderr, "Wrong option '-%c' found.\n", opt); - return 1; - } - continue; - } - - if (!arg[2]) { - /* arg is "--" */ - just_args = 1; - continue; - } - - /* parse long option */ - char opt [100]; - strncpy(opt, arg+2, 100); - opt[99] = 0; - - char *val = strchr(opt, '='); - - long int num = 0; - int isNum = 0; - - if (val) { - *val = 0; - val++; - - if (*val) - isNum = parseint(val, &num); - } - - int opt_parsed = 0; - - if (strcmp(opt, "help")==0) { - print_help(argv[0]); - return 1; - } - - if (strcmp(opt, "version")==0) { - print_version(); - return 1; - } - - if (strcmp(opt, "input-unit")==0 && isNum) { - opt_parsed = 1; - iunit = num; - } - if (strcmp(opt, "output-unit")==0 && isNum) { - opt_parsed = 1; - ounit = num; - } - - if (strcmp(opt, "time")==0) { - opt_parsed = 1; - show_time = 1; - } - - if (!opt_parsed) { - fprintf(stderr, "Wrong option '%s' found.\n", arg); - return 1; + /* Open input file, if needed */ + if (data.filename) { + file = fopen(data.filename, "r"); + if (!file) { + fprintf(stderr, "Unable to open input file \"%s\": %s\n", data.filename, strerror(errno)); + return 5; } } - if (!in) - in = stdin; + /* Read everything */ + ib = hoedown_buffer_new(data.iunit); - - /* reading everything */ - ib = hoedown_buffer_new(iunit); - - while (!feof(in)) { - if (ferror(in)) { + while (!feof(file)) { + if (ferror(file)) { fprintf(stderr, "I/O errors found while reading input.\n"); return 5; } - hoedown_buffer_grow(ib, ib->size + iunit); - ib->size += fread(ib->data + ib->size, 1, iunit, in); + hoedown_buffer_grow(ib, ib->size + data.iunit); + ib->size += fread(ib->data + ib->size, 1, data.iunit, file); } - if (in != stdin) - fclose(in); + if (file != stdin) fclose(file); + /* Perform SmartyPants processing */ + ob = hoedown_buffer_new(data.ounit); - /* performing SmartyPants processing */ - ob = hoedown_buffer_new(ounit); - - //clock_gettime(CLOCK_MONOTONIC, &start); + /*clock_gettime(CLOCK_MONOTONIC, &start);*/ hoedown_html_smartypants(ob, ib->data, ib->size); - //clock_gettime(CLOCK_MONOTONIC, &end); + /*clock_gettime(CLOCK_MONOTONIC, &end);*/ - - /* writing the result to stdout */ + /* Write the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); - - /* showing rendering time */ - if (show_time) { - //TODO: enable this - //long long elapsed = ( end.tv_sec*1000000000 + end.tv_nsec) - // - (start.tv_sec*1000000000 + start.tv_nsec); - //if (elapsed < 1000000000) - // fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1000000); - //else - // fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1000000000); + /* Show rendering time */ + if (data.show_time) { + /*TODO: enable this + long long elapsed = (end.tv_sec - start.tv_sec)*1e9 + (end.tv_nsec - start.tv_nsec); + if (elapsed < 1e9) + fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1e6); + else + fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1e9); + */ } - - /* cleanup */ + /* Cleanup */ hoedown_buffer_free(ib); hoedown_buffer_free(ob); diff --git a/src/buffer.c b/src/buffer.c index daba5fd..2ca0fd1 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -5,6 +5,45 @@ #include #include +void * +hoedown_malloc(size_t size) +{ + void *ret = malloc(size); + + if (!ret) { + fprintf(stderr, "Allocation failed.\n"); + abort(); + } + + return ret; +} + +void * +hoedown_calloc(size_t nmemb, size_t size) +{ + void *ret = calloc(nmemb, size); + + if (!ret) { + fprintf(stderr, "Allocation failed.\n"); + abort(); + } + + return ret; +} + +void * +hoedown_realloc(void *ptr, size_t size) +{ + void *ret = realloc(ptr, size); + + if (!ret) { + fprintf(stderr, "Allocation failed.\n"); + abort(); + } + + return ret; +} + void hoedown_buffer_init( hoedown_buffer *buf, @@ -133,9 +172,10 @@ hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str) int hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix) { - assert(buf && buf->unit); size_t i; + assert(buf && buf->unit); + for (i = 0; i < buf->size; ++i) { if (prefix[i] == 0) return 0; diff --git a/src/buffer.h b/src/buffer.h index 6d42385..fcda83c 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -37,19 +37,8 @@ struct hoedown_buffer { hoedown_free_callback data_free; hoedown_free_callback buffer_free; }; -typedef struct hoedown_buffer hoedown_buffer; -/* malloc / realloc / calloc wrappers */ -#define HOEDOWN_ALLOC_WRAPPER(sig, call) \ - static inline void *hoedown_##sig __attribute__ ((malloc)); \ - static inline void *hoedown_##sig { \ - void *ret = call; \ - if (!ret) { \ - fprintf(stderr, "Allocation failed.\n"); \ - abort(); \ - } \ - return ret; \ - } +typedef struct hoedown_buffer hoedown_buffer; /************* @@ -57,9 +46,9 @@ typedef struct hoedown_buffer hoedown_buffer; *************/ /* allocation wrappers */ -HOEDOWN_ALLOC_WRAPPER(malloc(size_t size), malloc(size)); -HOEDOWN_ALLOC_WRAPPER(calloc(size_t nmemb, size_t size), calloc(nmemb, size)); -HOEDOWN_ALLOC_WRAPPER(realloc(void *ptr, size_t size), realloc(ptr, size)); +void *hoedown_malloc(size_t size) __attribute__ ((malloc)); +void *hoedown_calloc(size_t nmemb, size_t size) __attribute__ ((malloc)); +void *hoedown_realloc(void *ptr, size_t size) __attribute__ ((malloc)); /* hoedown_buffer_init: initialize a buffer with custom allocators */ void hoedown_buffer_init( diff --git a/src/document.c b/src/document.c index f2ce139..3ce4416 100644 --- a/src/document.c +++ b/src/document.c @@ -132,7 +132,7 @@ struct hoedown_document { * HELPER FUNCTIONS * ***************************/ -static inline hoedown_buffer * +static hoedown_buffer * newbuf(hoedown_document *doc, int type) { static const size_t buf_size[2] = {256, 64}; @@ -151,7 +151,7 @@ newbuf(hoedown_document *doc, int type) return work; } -static inline void +static void popbuf(hoedown_document *doc, int type) { doc->work_bufs[type].size--; @@ -320,14 +320,14 @@ free_footnote_list(struct footnote_list *list, int free_refs) * should instead extract an Unicode codepoint from * this character and check for space properties. */ -static inline int +static int _isspace(int c) { return c == ' ' || c == '\n'; } /* is_empty_all: verify that all the data is spacing */ -static inline int +static int is_empty_all(const uint8_t *data, size_t size) { size_t i = 0; @@ -339,7 +339,7 @@ is_empty_all(const uint8_t *data, size_t size) * Replace all spacing characters in data with spaces. As a special * case, this collapses a newline with the previous space, if possible. */ -static inline void +static void replace_spacing(hoedown_buffer *ob, const uint8_t *data, size_t size) { size_t i = 0, mark; @@ -717,22 +717,30 @@ parse_emph3(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz static size_t parse_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size, const char *end, size_t delimsz, int displaymode) { + hoedown_buffer text = { NULL, 0, 0, 0, NULL, NULL, NULL }; size_t i = delimsz; - if (!doc->md.math) return 0; + + if (!doc->md.math) + return 0; /* find ending delimiter */ while (1) { - while (i < size && data[i] != (uint8_t)end[0]) i++; - if (i >= size) return 0; + while (i < size && data[i] != (uint8_t)end[0]) + i++; + + if (i >= size) + return 0; if (!is_escaped(data, i) && !(i + delimsz > size) && memcmp(data + i, end, delimsz) == 0) break; + i++; } /* prepare buffers */ - hoedown_buffer text = { data + delimsz, i - delimsz, 0, 0, NULL, NULL, NULL }; + text.data = data + delimsz; + text.size = i - delimsz; /* if this is a $$ and MATH_EXPLICIT is not active, * guess whether displaymode should be enabled from the context */ @@ -743,6 +751,7 @@ parse_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offs /* call callback */ if (doc->md.math(ob, &text, displaymode, &doc->data)) return i; + return 0; } @@ -804,6 +813,7 @@ char_linebreak(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t static size_t char_codespan(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; size_t end, nb = 0, i, f_begin, f_end; /* counting the number of backticks in the delimiter */ @@ -831,7 +841,9 @@ char_codespan(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t o /* real code span */ if (f_begin < f_end) { - hoedown_buffer work = { data + f_begin, f_end - f_begin, 0, 0, NULL, NULL, NULL }; + work.data = data + f_begin; + work.size = f_end - f_begin; + if (!doc->md.codespan(ob, &work, &doc->data)) end = 0; } else { @@ -954,11 +966,14 @@ char_entity(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t off static size_t char_langle_tag(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; hoedown_autolink_type altype = HOEDOWN_AUTOLINK_NONE; size_t end = tag_length(data, size, &altype); - hoedown_buffer work = { data, end, 0, 0, NULL, NULL, NULL }; int ret = 0; + work.data = data; + work.size = end; + if (end > 2) { if (doc->md.autolink && altype != HOEDOWN_AUTOLINK_NONE) { hoedown_buffer *u_link = newbuf(doc, BUFFER_SPAN); @@ -1618,9 +1633,11 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t static size_t parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; size_t i = 0, end = 0; int level = 0; - hoedown_buffer work = { data, 0, 0, 0, NULL, NULL, NULL }; + + work.data = data; while (i < size) { for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; @@ -1696,23 +1713,27 @@ parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t static size_t parse_fencedcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { + hoedown_buffer text = { 0, 0, 0, 0, NULL, NULL, NULL }; + hoedown_buffer lang = { 0, 0, 0, 0, NULL, NULL, NULL }; size_t i = 0, text_start, line_start; size_t w, w2; size_t width, width2; uint8_t chr, chr2; - hoedown_buffer text = { 0, 0, 0, 0, NULL, NULL, NULL }; - hoedown_buffer lang = { 0, 0, 0, 0, NULL, NULL, NULL }; - // parse codefence line - while (i < size && data[i] != '\n') i++; + /* parse codefence line */ + while (i < size && data[i] != '\n') + i++; + w = parse_codefence(data, i, &lang, &width, &chr); - if (!w) return 0; + if (!w) + return 0; - // search for end + /* search for end */ i++; text_start = i; while ((line_start = i) < size) { - while (i < size && data[i] != '\n') i++; + while (i < size && data[i] != '\n') + i++; w2 = is_codefence(data + line_start, i - line_start, &width2, &chr2); if (w == w2 && width == width2 && chr == chr2 && @@ -1721,6 +1742,7 @@ parse_fencedcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_ i++; } + text.data = data + text_start; text.size = line_start - text_start; @@ -2009,7 +2031,7 @@ parse_footnote_list(hoedown_buffer *ob, hoedown_document *doc, struct footnote_l /* htmlblock_is_end • check for end of HTML block : ( *)\n */ /* returns tag length on match, 0 otherwise */ /* assumes data starts with "<" */ -static inline size_t +static size_t htmlblock_is_end( const char *tag, size_t tag_len, @@ -2087,9 +2109,11 @@ htmlblock_find_end_strict( static size_t parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, int do_render) { - size_t i, j = 0, tag_end; + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; + size_t i, j = 0, tag_len, tag_end; const char *curtag = NULL; - hoedown_buffer work = { data, 0, 0, 0, NULL, NULL, NULL }; + + work.data = data; /* identification of the opening tag */ if (size < 2 || data[0] != '<') @@ -2148,7 +2172,7 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t } /* looking for a matching closing tag in strict mode */ - size_t tag_len = strlen(curtag); + tag_len = strlen(curtag); tag_end = htmlblock_find_end_strict(curtag, tag_len, doc, data, size); /* if not found, trying a second pass looking for indented match */ @@ -2177,7 +2201,7 @@ parse_table_row( hoedown_table_flags *col_data, hoedown_table_flags header_flag) { - size_t i = 0, col; + size_t i = 0, col, len; hoedown_buffer *row_work = 0; if (!doc->md.table_cell || !doc->md.table_row) @@ -2199,7 +2223,7 @@ parse_table_row( cell_start = i; - size_t len = find_emph_char(data + i, size - i, '|'); + len = find_emph_char(data + i, size - i, '|'); i += len ? len : size - i; cell_end = i - 1; diff --git a/src/html.c b/src/html.c index d24bf8e..ddebff7 100644 --- a/src/html.c +++ b/src/html.c @@ -42,12 +42,12 @@ hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname) return HOEDOWN_HTML_TAG_NONE; } -static inline void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length) +static void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length) { hoedown_escape_html(ob, source, length, 0); } -static inline void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length) +static void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length) { hoedown_escape_href(ob, source, length); } @@ -326,15 +326,25 @@ static void rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) { size_t org, sz; - if (!text) return; - //FIXME: do we *really* need to trim the HTML? - //how does that make a difference? + + if (!text) + return; + + /* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */ sz = text->size; - while (sz > 0 && text->data[sz - 1] == '\n') sz--; + 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) hoedown_buffer_putc(ob, '\n'); + while (org < sz && text->data[org] == '\n') + org++; + + if (org >= sz) + return; + + if (ob->size) + hoedown_buffer_putc(ob, '\n'); + hoedown_buffer_put(ob, text->data + org, sz - org); hoedown_buffer_putc(ob, '\n'); } @@ -591,8 +601,12 @@ toc_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer static void toc_finalize(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data) { - if (inline_render) return; - hoedown_html_renderer_state *state = data->opaque; + hoedown_html_renderer_state *state; + + if (inline_render) + return; + + state = data->opaque; while (state->toc_data.current_level > 0) { HOEDOWN_BUFPUTSL(ob, "\n\n"); diff --git a/src/html_smartypants.c b/src/html_smartypants.c index 9f9dcf0..bbe4fc5 100644 --- a/src/html_smartypants.c +++ b/src/html_smartypants.c @@ -60,7 +60,7 @@ static const uint8_t smartypants_cb_chars[UINT8_MAX+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static inline int +static int word_boundary(uint8_t c) { return c == 0 || isspace(c) || ispunct(c);