Merge pull request #137 from hoedown/ansi

Use a stricter subset of C
This commit is contained in:
Devin Torres 2014-10-21 03:15:03 -05:00
commit a88343c593
9 changed files with 642 additions and 530 deletions

View file

@ -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 $@ $<

View file

@ -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;
}

View file

@ -2,32 +2,16 @@
#include "html.h"
#include "common.h"
//#include <time.h>
/* 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 <time.h>*/
/* 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);

View file

@ -1,17 +1,20 @@
#include "html.h"
#include "common.h"
//#include <time.h>
/*#include <time.h>*/
/* 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);

View file

@ -5,6 +5,45 @@
#include <string.h>
#include <assert.h>
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;

View file

@ -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(

View file

@ -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 : </tag>( *)\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;

View file

@ -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, "</li>\n</ul>\n");

View file

@ -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);