From b9e867b574d3ff206e69a1b16d0523aa796ed88b Mon Sep 17 00:00:00 2001 From: david parsons Date: Sat, 7 Dec 2019 22:49:52 -0800 Subject: [PATCH] redo the whole flags dealie as an opaque blob --- Csio.c | 2 +- dumptree.c | 6 +- flags.c | 21 ++++- generate.c | 129 ++++++++++++++++-------------- github_flavoured.c | 10 +-- h1title.c | 6 +- main.c | 62 +++++++++------ makepage.c | 37 ++++++--- markdown.c | 136 ++++++++++++++++++++------------ markdown.h | 123 ++++++++++++++++------------- mkdio.c | 63 +++++++++++---- mkdio.h.in | 100 +++++++++++++----------- pgm_options.c | 191 +++++++++++++++++++++++++++++++++++---------- pgm_options.h | 3 +- tests/latex.t | 4 +- theme.c | 70 ++++++++--------- toc.c | 16 +++- xmlpage.c | 2 +- 18 files changed, 622 insertions(+), 359 deletions(-) diff --git a/Csio.c b/Csio.c index 1b418e0..71dd9bb 100644 --- a/Csio.c +++ b/Csio.c @@ -50,7 +50,7 @@ Cswrite(Cstring *iot, char *bfr, int size) /* reparse() into a cstring */ void -Csreparse(Cstring *iot, char *buf, int size, mkd_flag_t flags) +Csreparse(Cstring *iot, char *buf, int size, mkd_flag_t* flags) { MMIOT f; ___mkd_initmmiot(&f, 0); diff --git a/dumptree.c b/dumptree.c index 2fca134..41e73f5 100644 --- a/dumptree.c +++ b/dumptree.c @@ -115,8 +115,8 @@ dumptree(Paragraph *pp, Stack *sp, FILE *f) if ( pp->ident ) d += fprintf(f, " %s", pp->ident); - if ( pp->flags ) - d += fprintf(f, " %x", pp->flags); + if ( pp->para_flags ) + d += fprintf(f, " %x", pp->para_flags); if ( pp->align > 1 ) d += fprintf(f, ", <%s>", Begin[pp->align]); @@ -141,7 +141,7 @@ dumptree(Paragraph *pp, Stack *sp, FILE *f) int -mkd_dump(Document *doc, FILE *out, mkd_flag_t flags, char *title) +mkd_dump(Document *doc, FILE *out, mkd_flag_t *flags, char *title) { Stack stack; diff --git a/flags.c b/flags.c index 2742d53..2bf10d6 100644 --- a/flags.c +++ b/flags.c @@ -2,7 +2,7 @@ #include "markdown.h" struct flagnames { - mkd_flag_t flag; + int flag; char *name; }; @@ -41,8 +41,15 @@ static struct flagnames flagnames[] = { #define NR(x) (sizeof x/sizeof x[0]) +int +mkd_flag_isset(mkd_flag_t *flags, int i) +{ + return flags ? is_flag_set(flags, i) : 0; +} + + void -mkd_flags_are(FILE *f, mkd_flag_t flags, int htmlplease) +mkd_flags_are(FILE *f, mkd_flag_t* flags, int htmlplease) { int i; int not, set, even=1; @@ -51,7 +58,7 @@ mkd_flags_are(FILE *f, mkd_flag_t flags, int htmlplease) if ( htmlplease ) fprintf(f, "\n"); for (i=0; i < NR(flagnames); i++) { - set = flags & flagnames[i].flag; + set = mkd_flag_isset(flags, flagnames[i].flag); name = flagnames[i].name; if ( not = (*name == '!') ) { ++name; @@ -88,5 +95,11 @@ void mkd_mmiot_flags(FILE *f, MMIOT *m, int htmlplease) { if ( m ) - mkd_flags_are(f, m->flags, htmlplease); + mkd_flags_are(f, &(m->flags), htmlplease); +} + +void +mkd_init_flags(mkd_flag_t *p) +{ + memset(p, 0, sizeof(*p)); } diff --git a/generate.c b/generate.c index 30acb64..83b825e 100644 --- a/generate.c +++ b/generate.c @@ -209,14 +209,16 @@ Qem(MMIOT *f, char c, int count) /* generate html from a markup fragment */ void -___mkd_reparse(char *bfr, int size, mkd_flag_t flags, MMIOT *f, char *esc) +___mkd_reparse(char *bfr, int size, mkd_flag_t* flags, MMIOT *f, char *esc) { MMIOT sub; struct escaped e; ___mkd_initmmiot(&sub, f->footnotes); - sub.flags = f->flags | flags; + COPY_FLAGS(sub.flags,f->flags); + if ( flags ) + OR_FLAGS(&sub.flags, flags); sub.cb = f->cb; sub.ref_prefix = f->ref_prefix; @@ -473,7 +475,7 @@ linkyurl(MMIOT *f, int image, Footnote *p) if ( c == '<' ) { pull(f); - if ( !is_flag_set(f->flags, MKD_1_COMPAT) ) + if ( !is_flag_set(&f->flags, MKD_1_COMPAT) ) return linkybroket(f,image,p); mayneedtotrim=1; } @@ -546,15 +548,15 @@ typedef struct linkytype { int WxH; /* this tag allows width x height arguments */ char *text_pfx; /* text prefix (eg: ">" */ char *text_sfx; /* text suffix (eg: "" */ - int flags; /* reparse flags */ + mkd_flag_t flags; /* reparse flags */ int kind; /* tag is url or something else? */ #define IS_URL 0x01 } linkytype; static linkytype imaget = { 0, 0, "\"",", MKD_NOIMAGE|MKD_TAGTEXT, IS_URL }; + 1, " alt=\"", "\" />", { { [MKD_NOIMAGE] = 1, [MKD_TAGTEXT] = 1} }, IS_URL }; static linkytype linkt = { 0, 0, "", "", MKD_NOLINKS, IS_URL }; + 0, ">", "", { {[MKD_NOLINKS] = 1} }, IS_URL }; /* * pseudo-protocols for [][]; @@ -564,11 +566,11 @@ static linkytype linkt = { 0, 0, "", "", 0, 0 }, - { "raw:", 4, 0, 0, 0, 0, 0, MKD_NOHTML, 0 }, - { "lang:", 5, "", "", 0, 0 }, - { "abbr:", 5, "", "", 0, 0 }, - { "class:", 6, "", "", 0, 0 }, + { "id:", 3, "", "", {}, 0 }, + { "raw:", 4, 0, 0, 0, 0, 0, { { [MKD_NOHTML] = 1 } }, 0 }, + { "lang:", 5, "", "", {}, 0 }, + { "abbr:", 5, "", "", {}, 0 }, + { "class:", 6, "", "", {}, 0 }, } ; #define NR(x) (sizeof x / sizeof x[0]) @@ -596,7 +598,7 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size) { char *edit; - if ( is_flag_set(f->flags, IS_LABEL) ) + if ( is_flag_set(&f->flags, IS_LABEL) ) return; Qstring(tag->link_pfx, f); @@ -609,8 +611,12 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size) else puturl(link + tag->szpat, size - tag->szpat, f, 0); } - else - ___mkd_reparse(link + tag->szpat, size - tag->szpat, MKD_TAGTEXT, f, 0); + else { + mkd_flag_t tagtext; + mkd_init_flags(&tagtext); + set_mkd_flag(&tagtext, MKD_TAGTEXT); + ___mkd_reparse(link + tag->szpat, size - tag->szpat, &tagtext, f, 0); + } Qstring(tag->link_sfx, f); @@ -638,13 +644,13 @@ MMIOT *p; static int extra_linky(MMIOT *f, Cstring text, Footnote *ref) { - if ( ref->flags & REFERENCED ) + if ( ref->fn_flags & REFERENCED ) return 0; - if ( f->flags & IS_LABEL ) - ___mkd_reparse(T(text), S(text), linkt.flags, f, 0); + if ( is_flag_set(&f->flags,IS_LABEL) ) + ___mkd_reparse(T(text), S(text), &(linkt.flags), f, 0); else { - ref->flags |= REFERENCED; + ref->fn_flags |= REFERENCED; ref->refnumber = ++ f->footnotes->reference; Qprintf(f, "%d", p_or_nothing(f), ref->refnumber, @@ -686,15 +692,17 @@ static int linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref) { linkytype *tag; + static mkd_flag_t tagtext = { {[MKD_TAGTEXT] = 1} }; + mkd_flag_t flags; if ( image ) tag = &imaget; else if ( tag = pseudo(ref->link) ) { - if ( is_flag_set(f->flags, MKD_NO_EXT) || is_flag_set(f->flags, MKD_SAFELINK) ) + if ( is_flag_set(&f->flags, MKD_NO_EXT) || is_flag_set(&f->flags, MKD_SAFELINK) ) return 0; } - else if ( is_flag_set(f->flags, MKD_SAFELINK) && !safelink(ref->link) ) + else if ( is_flag_set(&f->flags, MKD_SAFELINK) && !safelink(ref->link) ) /* if MKD_SAFELINK, only accept links that are local or * a well-known protocol */ @@ -702,11 +710,12 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref) else tag = &linkt; - if ( f->flags & tag->flags ) + COPY_FLAGS(flags, f->flags); + if ( AND_FLAGS(&flags, &tag->flags) ) return 0; - if ( is_flag_set(f->flags, IS_LABEL) ) - ___mkd_reparse(T(text), S(text), tag->flags, f, 0); + if ( is_flag_set(&f->flags, IS_LABEL) ) + ___mkd_reparse(T(text), S(text), &(tag->flags), f, 0); else if ( tag->link_pfx ) { printlinkyref(f, tag, T(ref->link), S(ref->link)); @@ -717,12 +726,12 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref) if ( S(ref->title) ) { Qstring(" title=\"", f); - ___mkd_reparse(T(ref->title), S(ref->title), MKD_TAGTEXT, f, 0); + ___mkd_reparse(T(ref->title), S(ref->title), &tagtext, f, 0); Qchar('"', f); } Qstring(tag->text_pfx, f); - ___mkd_reparse(T(text), S(text), tag->flags, f, 0); + ___mkd_reparse(T(text), S(text), &(tag->flags), f, 0); Qstring(tag->text_sfx, f); } else @@ -769,9 +778,9 @@ linkylinky(int image, MMIOT *f) * require a second [] */ mmiotseek(f, implicit_mark); - goodlink = !is_flag_set(f->flags, MKD_1_COMPAT); + goodlink = !is_flag_set(&f->flags, MKD_1_COMPAT); - if ( is_flag_set(f->flags, MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' ) + if ( is_flag_set(&f->flags, MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' ) extra_footnote = 1; } @@ -901,13 +910,14 @@ code(MMIOT *f, char *s, int length) cputc(c, f); } /* code */ + /* delspan() -- write out a chunk of text, blocking with ... */ static void delspan(MMIOT *f, int size) { Qstring("", f); - ___mkd_reparse(cursor(f)-1, size, 0, f, 0); + ___mkd_reparse(cursor(f)-1, size, NULL, f, 0); Qstring("", f); } @@ -937,12 +947,12 @@ forbidden_tag(MMIOT *f) { int c = toupper(peek(f, 1)); - if ( is_flag_set(f->flags, MKD_NOHTML) ) + if ( is_flag_set(&f->flags, MKD_NOHTML) ) return 1; - if ( c == 'A' && is_flag_set(f->flags, MKD_NOLINKS) && !isthisalnum(f,2) ) + if ( c == 'A' && is_flag_set(&f->flags, MKD_NOLINKS) && !isthisalnum(f,2) ) return 1; - if ( c == 'I' && is_flag_set(f->flags, MKD_NOIMAGE) + if ( c == 'I' && is_flag_set(&f->flags, MKD_NOIMAGE) && strncasecmp(cursor(f)+1, "MG", 2) == 0 && !isthisalnum(f,4) ) return 1; @@ -989,7 +999,7 @@ process_possible_link(MMIOT *f, int size) int mailto = 0; char *text = cursor(f); - if ( is_flag_set(f->flags, MKD_NOLINKS) ) return 0; + if ( is_flag_set(&f->flags, MKD_NOLINKS) ) return 0; if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) { /* if it says it's a mailto, it's a mailto -- who am @@ -1036,7 +1046,7 @@ maybe_tag_or_link(MMIOT *f) int c, size; int maybetag = 1; - if ( is_flag_set(f->flags, MKD_TAGTEXT) ) + if ( is_flag_set(&f->flags, MKD_TAGTEXT) ) return 0; for ( size=0; (c = peek(f, size+1)) != '>'; size++) { @@ -1050,7 +1060,7 @@ maybe_tag_or_link(MMIOT *f) else if ( isspace(c) ) break; else if ( ! (c == '/' - || (is_flag_set(f->flags, MKD_GITHUBTAGS) && (c == '-' || c == '_')) + || (is_flag_set(&f->flags, MKD_GITHUBTAGS) && (c == '-' || c == '_')) || isalnum(c) ) ) maybetag=0; } @@ -1204,9 +1214,9 @@ smartypants(int c, int *flags, MMIOT *f) { int i; - if ( is_flag_set(f->flags, MKD_NOPANTS) - || is_flag_set(f->flags, MKD_TAGTEXT) - || is_flag_set(f->flags, IS_LABEL) ) + if ( is_flag_set(&f->flags, MKD_NOPANTS) + || is_flag_set(&f->flags, MKD_TAGTEXT) + || is_flag_set(&f->flags, IS_LABEL) ) return 0; for ( i=0; i < NRSMART; i++) @@ -1235,7 +1245,7 @@ smartypants(int c, int *flags, MMIOT *f) break; else if ( c == '\'' && peek(f, j+1) == '\'' ) { Qstring("“", f); - ___mkd_reparse(cursor(f)+1, j-2, 0, f, 0); + ___mkd_reparse(cursor(f)+1, j-2, NULL, f, 0); Qstring("”", f); shift(f,j+1); return 1; @@ -1298,7 +1308,7 @@ tickhandler(MMIOT *f, int tickchar, int minticks, int allow_space, spanhandler s return 0; } -#define tag_text(f) is_flag_set(f->flags, MKD_TAGTEXT) +#define tag_text(f) is_flag_set(&((f)->flags), MKD_TAGTEXT) static void @@ -1308,8 +1318,9 @@ text(MMIOT *f) int rep; int smartyflags = 0; + while (1) { - if ( is_flag_set(f->flags, MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) ) + if ( is_flag_set(&f->flags, MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) ) maybe_autolink(f); c = pull(f); @@ -1351,8 +1362,8 @@ text(MMIOT *f) Qchar(c, f); break; /* A^B -> AB */ - case '^': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT) - || is_flag_set(f->flags, MKD_TAGTEXT) + case '^': if ( is_flag_set(&f->flags, MKD_NOSUPERSCRIPT) + || is_flag_set(&f->flags, MKD_TAGTEXT) || (f->last == 0) || ((ispunct(f->last) || isspace(f->last)) && f->last != ')') @@ -1383,13 +1394,13 @@ text(MMIOT *f) shift(f,len); } Qstring("",f); - ___mkd_reparse(sup, len, 0, f, "()"); + ___mkd_reparse(sup, len, NULL, f, "()"); Qstring("", f); } break; case '_': /* Underscores don't count if they're in the middle of a word */ - if ( !is_flag_set(f->flags, MKD_NORELAXED) + if ( !is_flag_set(&f->flags, MKD_NORELAXED) && isthisalnum(f,-1) && isthisalnum(f,1) ) { Qchar(c, f); break; @@ -1411,8 +1422,8 @@ text(MMIOT *f) } break; - case '~': if ( is_flag_set(f->flags, MKD_NOSTRIKETHROUGH) - || is_flag_set(f->flags, MKD_TAGTEXT) + case '~': if ( is_flag_set(&f->flags, MKD_NOSTRIKETHROUGH) + || is_flag_set(&f->flags, MKD_TAGTEXT) || ! tickhandler(f,c,2,0, delspan) ) Qchar(c, f); break; @@ -1435,7 +1446,7 @@ text(MMIOT *f) } break; - case '^': if ( is_flag_set(f->flags, MKD_NOSUPERSCRIPT) ) { + case '^': if ( is_flag_set(&f->flags, MKD_NOSUPERSCRIPT) ) { Qchar('\\', f); shift(f,-1); break; @@ -1444,7 +1455,7 @@ text(MMIOT *f) break; case ':': case '|': - if ( is_flag_set(f->flags, MKD_NOTABLES) ) { + if ( is_flag_set(&f->flags, MKD_NOTABLES) ) { Qchar('\\', f); shift(f,-1); break; @@ -1456,7 +1467,7 @@ text(MMIOT *f) break; case '[': - case '(': if ( is_flag_set(f->flags, MKD_LATEX) + case '(': if ( is_flag_set(&f->flags, MKD_LATEX) && mathhandler(f, '\\', (c =='(')?')':']') ) break; /* else fall through to default */ @@ -1486,7 +1497,7 @@ text(MMIOT *f) Qchar(c, f); break; - case '$': if ( is_flag_set(f->flags, MKD_LATEX) && (peek(f, 1) == '$') ) { + case '$': if ( is_flag_set(&f->flags, MKD_LATEX) && (peek(f, 1) == '$') ) { pull(f); if ( mathhandler(f, '$', '$') ) break; @@ -1509,16 +1520,16 @@ text(MMIOT *f) static void printheader(Paragraph *pp, MMIOT *f) { - if ( is_flag_set(f->flags, MKD_IDANCHOR) ) { + if ( is_flag_set(&f->flags, MKD_IDANCHOR) ) { Qprintf(f, "hnumber); - if ( is_flag_set(f->flags, MKD_TOC) ) { + if ( is_flag_set(&f->flags, MKD_TOC) ) { Qstring(" id=\"", f); Qanchor(pp->text, f); Qchar('"', f); } Qchar('>', f); } else { - if ( is_flag_set(f->flags, MKD_TOC) ) { + if ( is_flag_set(&f->flags, MKD_TOC) ) { Qstring("text, f); Qstring("\">\n", f); @@ -1566,7 +1577,7 @@ splat(Line *p, char *block, Istring align, int force, MMIOT *f) Qprintf(f, "<%s%s>", block, alignments[ (colno < S(align)) ? T(align)[colno] : a_NONE ]); - ___mkd_reparse(T(p->text)+first, idx-first, 0, f, "|"); + ___mkd_reparse(T(p->text)+first, idx-first, NULL, f, "|"); Qprintf(f, "\n", block); idx++; colno++; @@ -1777,7 +1788,7 @@ htmlify_paragraphs(Paragraph *p, MMIOT *f) static void -li_htmlify(Paragraph *p, char *arguments, mkd_flag_t flags, MMIOT *f) +li_htmlify(Paragraph *p, char *arguments, int flags, MMIOT *f) { ___mkd_emblock(f); @@ -1832,7 +1843,7 @@ definitionlist(Paragraph *p, MMIOT *f) for ( ; p ; p = p->next) { for ( tag = p->text; tag; tag = tag->next ) { Qstring("
", f); - ___mkd_reparse(T(tag->text), S(tag->text), 0, f, 0); + ___mkd_reparse(T(tag->text), S(tag->text), NULL, f, 0); Qstring("
\n", f); } @@ -1855,7 +1866,7 @@ listdisplay(int typ, Paragraph *p, MMIOT* f) Qprintf(f, ">\n"); for ( ; p ; p = p->next ) { - li_htmlify(p->down, p->ident, p->flags, f); + li_htmlify(p->down, p->ident, p->para_flags, f); Qchar('\n', f); } @@ -1938,7 +1949,7 @@ mkd_extra_footnotes(MMIOT *m) for ( i=1; i <= m->footnotes->reference; i++ ) { for ( j=0; j < S(m->footnotes->note); j++ ) { t = &T(m->footnotes->note)[j]; - if ( (t->refnumber == i) && (t->flags & REFERENCED) ) { + if ( (t->refnumber == i) && (t->fn_flags & REFERENCED) ) { Csprintf(&m->out, "
  • \n", p_or_nothing(m), t->refnumber); htmlify(t->text, 0, 0, m); @@ -1963,7 +1974,7 @@ mkd_document(Document *p, char **res) if ( p && p->compiled ) { if ( ! p->html ) { htmlify(p->code, 0, 0, p->ctx); - if ( is_flag_set(p->ctx->flags, MKD_EXTRA_FOOTNOTE) ) + if ( is_flag_set(&p->ctx->flags, MKD_EXTRA_FOOTNOTE) ) mkd_extra_footnotes(p->ctx); p->html = 1; size = S(p->ctx->out); diff --git a/github_flavoured.c b/github_flavoured.c index f7a40cd..869eaca 100644 --- a/github_flavoured.c +++ b/github_flavoured.c @@ -21,7 +21,7 @@ typedef int (*getc_func)(void*); Document * -gfm_populate(getc_func getc, void* ctx, int flags) +gfm_populate(getc_func getc, void* ctx, mkd_flag_t *flags) { Cstring line; Document *a = __mkd_new_Document(); @@ -80,21 +80,21 @@ gfm_populate(getc_func getc, void* ctx, int flags) /* convert a block of text into a linked list */ Document * -gfm_string(const char *buf, int len, mkd_flag_t flags) +gfm_string(const char *buf, int len, mkd_flag_t* flags) { struct string_stream about; about.data = buf; about.size = len; - return gfm_populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK); + return gfm_populate((getc_func)__mkd_io_strget, &about, flags); } /* convert a file into a linked list */ Document * -gfm_in(FILE *f, mkd_flag_t flags) +gfm_in(FILE *f, mkd_flag_t* flags) { - return gfm_populate((getc_func)fgetc, f, flags & INPUT_MASK); + return gfm_populate((getc_func)fgetc, f, flags); } diff --git a/h1title.c b/h1title.c index 89fd9d2..5bfacb2 100644 --- a/h1title.c +++ b/h1title.c @@ -17,7 +17,7 @@ mkd_h1(Paragraph *p) } char * -mkd_h1_title(Document *doc, int flags) +mkd_h1_title(Document *doc, mkd_flag_t* flags) { Paragraph *title; @@ -28,8 +28,10 @@ mkd_h1_title(Document *doc, int flags) /* assert that a H1 header is one line long, so that's * the only thing needed */ + set_mkd_flag(flags, MKD_TAGTEXT); size = mkd_line(T(title->text->text), - S(title->text->text), &generated, flags|MKD_TAGTEXT); + S(title->text->text), &generated, flags); + clear_mkd_flag(flags, MKD_TAGTEXT); if ( size ) return generated; } return 0; diff --git a/main.c b/main.c index 79f83ce..ecdcba9 100644 --- a/main.c +++ b/main.c @@ -168,7 +168,7 @@ int main(int argc, char **argv) { int rc; - mkd_flag_t flags = 0; + mkd_flag_t flags; int debug = 0; int toc = 0; int content = 1; @@ -192,11 +192,13 @@ main(int argc, char **argv) hoptset(&blob, argc, argv); hopterr(&blob, 1); - if ( q = getenv("MARKDOWN_FLAGS") ) - flags = strtol(q, 0, 0); - pgm = basename(argv[0]); + mkd_init_flags(&flags); + + if ( q = getenv("MARKDOWN_FLAGS") ) + mkd_set_flag_bitmap(&flags, strtol(q,0,0)); + while ( opt=gethopt(&blob, opts, NROPTS) ) { if ( opt == HOPTERR ) { hoptusage(pgm, opts, NROPTS, "[file]"); @@ -213,19 +215,29 @@ main(int argc, char **argv) break; case 'E': urlflags = hoptarg(&blob); break; - case 'F': if ( strcmp(hoptarg(&blob), "?") == 0 ) { - show_flags(0, 0); + case 'f': q = hoptarg(&blob); + if ( strcmp(q, "?") == 0 ) { + show_flags(1, version, 0); + exit(0); + } + else if ( strcmp(q, "??") == 0 ) { + show_flags(1, version, &flags); + exit(0); + } + else if ( q=mkd_set_flag_string(&flags, hoptarg(&blob)) ) + complain("unknown option <%s>", q); + break; + case 'F': q = hoptarg(&blob); + if ( strcmp(q, "?") == 0 ) { + show_flags(0, 0, 0); + exit(0); + } + else if ( strcmp(q, "??") == 0 ) { + show_flags(0, version, &flags); exit(0); } else - flags = strtol(hoptarg(&blob), 0, 0); - break; - case 'f': if ( strcmp(hoptarg(&blob), "?") == 0 ) { - show_flags(1, version); - exit(0); - } - else if ( q=set_flag(&flags, hoptarg(&blob)) ) - complain("unknown option <%s>", q); + mkd_set_flag_bitmap(&flags,strtol(q, 0, 0)); break; case 'G': github_flavoured = 1; break; @@ -238,7 +250,7 @@ main(int argc, char **argv) case 't': text = hoptarg(&blob); use_mkd_line = 1; break; - case 'T': flags |= MKD_TOC; + case 'T': mkd_set_flag_num(&flags, MKD_TOC); toc = 1; break; case 'C': extra_footnote_prefix = hoptarg(&blob); @@ -255,18 +267,17 @@ main(int argc, char **argv) case 'x': squash = 1; break; case 'X': use_e_codefmt = 1; - set_flag(&flags, "fencedcode"); + mkd_set_flag_num(&flags, MKD_FENCEDCODE); break; } } + if ( version ) { printf("%s: discount %s%s", pgm, markdown_version, with_html5 ? " +html5":""); if ( version == 2 ) - mkd_flags_are(stdout, flags, 0); - if ( version >= 3 ) - printf(" MARKDOWN_FLAGS=0x%08x", flags); + mkd_flags_are(stdout, &flags, 0); putchar('\n'); exit(0); } @@ -278,11 +289,11 @@ main(int argc, char **argv) mkd_with_html5_tags(); if ( use_mkd_line ) - rc = mkd_generateline( text, strlen(text), stdout, flags); + rc = mkd_generateline( text, strlen(text), stdout, &flags); else { if ( text ) { - doc = github_flavoured ? gfm_string(text, strlen(text), flags) - : mkd_string(text, strlen(text), flags) ; + doc = github_flavoured ? gfm_string(text, strlen(text), &flags) + : mkd_string(text, strlen(text), &flags) ; if ( !doc ) { perror(text); @@ -295,7 +306,8 @@ main(int argc, char **argv) exit(1); } - doc = github_flavoured ? gfm_in(stdin,flags) : mkd_in(stdin,flags); + doc = github_flavoured ? gfm_in(stdin,&flags) + : mkd_in(stdin,&flags); if ( !doc ) { perror(argc ? argv[0] : "stdin"); exit(1); @@ -319,10 +331,10 @@ main(int argc, char **argv) mkd_ref_prefix(doc, extra_footnote_prefix); if ( debug ) - rc = mkd_dump(doc, stdout, 0, argc ? basename(argv[0]) : "stdin"); + rc = mkd_dump(doc, stdout, &flags, argc ? basename(argv[0]) : "stdin"); else { rc = 1; - if ( mkd_compile(doc, flags) ) { + if ( mkd_compile(doc, &flags) ) { rc = 0; if ( styles ) mkd_generatecss(doc, stdout); diff --git a/makepage.c b/makepage.c index 2887664..cdf0b51 100644 --- a/makepage.c +++ b/makepage.c @@ -37,13 +37,21 @@ char **argv; MMIOT *doc; char *q; int version = 0; - int ret; - mkd_flag_t flags = 0; + int ret, i; + DWORD bits; + mkd_flag_t flags; struct h_opt *opt; struct h_context blob; - if ( (q = getenv("MARKDOWN_FLAGS")) ) - flags = strtol(q, 0, 0); + mkd_init_flags(&flags); + + if ( (q = getenv("MARKDOWN_FLAGS")) ) { + bits = strtol(q, 0, 0); + + for ( i=0; i < 8*sizeof(bits); i++) + if ( bits & (1<\n", q); break; } @@ -79,7 +92,7 @@ char **argv; if ( version ) { printf("%s: discount %s", pgm, markdown_version); if ( version > 1 ) - mkd_flags_are(stdout, flags, 0); + mkd_flags_are(stdout, &flags, 0); putchar('\n'); exit(0); } @@ -89,12 +102,12 @@ char **argv; exit(1); } - if ( (doc = mkd_in(stdin, flags)) == 0 ) { + if ( (doc = mkd_in(stdin, &flags)) == 0 ) { perror( (argc > 1) ? argv[1] : "stdin" ); exit(1); } - ret = mkd_xhtmlpage(doc, flags, stdout); + ret = mkd_xhtmlpage(doc, &flags, stdout); mkd_cleanup(doc); diff --git a/markdown.c b/markdown.c index 2e068e2..834d938 100644 --- a/markdown.c +++ b/markdown.c @@ -178,7 +178,7 @@ splitline(Line *t, int cutpoint) } } -#define UNCHECK(l) ((l)->flags &= ~CHECKED) +#define UNCHECK(l) ((l)->line_flags &= ~CHECKED) #define UNLESS_FENCED(t) if (fenced) { \ other = 1; l->count += (c == ' ' ? 0 : -1); \ @@ -189,7 +189,7 @@ splitline(Line *t, int cutpoint) * types. */ static void -checkline(Line *l, mkd_flag_t flags) +checkline(Line *l, mkd_flag_t *flags) { int eol, i; int dashes = 0, spaces = 0, @@ -197,7 +197,7 @@ checkline(Line *l, mkd_flag_t flags) stars = 0, tildes = 0, other = 0, backticks = 0, fenced = 0; - l->flags |= CHECKED; + l->line_flags |= CHECKED; l->kind = chk_text; l->count = 0; @@ -381,9 +381,9 @@ iscode(Line *t) static inline int -ishr(Line *t, mkd_flag_t flags) +ishr(Line *t, mkd_flag_t *flags) { - if ( ! (t->flags & CHECKED) ) + if ( ! (t->line_flags & CHECKED) ) checkline(t, flags); if ( t->count > 2 ) @@ -393,7 +393,7 @@ ishr(Line *t, mkd_flag_t flags) static int -issetext(Line *t, int *htyp, mkd_flag_t flags) +issetext(Line *t, int *htyp, mkd_flag_t *flags) { Line *n; @@ -402,7 +402,7 @@ issetext(Line *t, int *htyp, mkd_flag_t flags) */ if ( (n = t->next) ) { - if ( !(n->flags & CHECKED) ) + if ( !(n->line_flags & CHECKED) ) checkline(n, flags); if ( n->kind == chk_dash || n->kind == chk_equal ) { @@ -415,7 +415,7 @@ issetext(Line *t, int *htyp, mkd_flag_t flags) static int -ishdr(Line *t, int *htyp, mkd_flag_t flags) +ishdr(Line *t, int *htyp, mkd_flag_t *flags) { /* ANY leading `#`'s make this into an ETX header */ @@ -431,7 +431,7 @@ ishdr(Line *t, int *htyp, mkd_flag_t flags) static inline int -end_of_block(Line *t, mkd_flag_t flags) +end_of_block(Line *t, mkd_flag_t *flags) { int dummy; @@ -443,7 +443,7 @@ end_of_block(Line *t, mkd_flag_t flags) static Line* -is_discount_dt(Line *t, int *clip, mkd_flag_t flags) +is_discount_dt(Line *t, int *clip, mkd_flag_t *flags) { if ( is_flag_set(flags, MKD_DLDISCOUNT) && t @@ -472,7 +472,7 @@ is_extra_dd(Line *t) static Line* -is_extra_dt(Line *t, int *clip, mkd_flag_t flags) +is_extra_dt(Line *t, int *clip, mkd_flag_t* flags) { if ( is_flag_set(flags, MKD_DLEXTRA) && t @@ -496,7 +496,7 @@ is_extra_dt(Line *t, int *clip, mkd_flag_t flags) static Line* -isdefinition(Line *t, int *clip, int *kind, mkd_flag_t flags) +isdefinition(Line *t, int *clip, int *kind, mkd_flag_t *flags) { Line *ret; @@ -510,7 +510,7 @@ isdefinition(Line *t, int *clip, int *kind, mkd_flag_t flags) static int -islist(Line *t, int *clip, mkd_flag_t flags, int *list_type) +islist(Line *t, int *clip, mkd_flag_t *flags, int *list_type) { int i, j; char *q; @@ -518,7 +518,7 @@ islist(Line *t, int *clip, mkd_flag_t flags, int *list_type) if ( end_of_block(t, flags) ) return 0; - if ( is_flag_set(flags, MKD_DLIST) && isdefinition(t,clip,list_type,flags) ) + if ( (is_flag_set(flags, MKD_DLEXTRA)||is_flag_set(flags, MKD_DLDISCOUNT)) && isdefinition(t,clip,list_type,flags) ) return DL; if ( strchr("*-+", T(t->text)[t->dle]) && isspace(T(t->text)[t->dle+1]) ) { @@ -623,12 +623,12 @@ codeblock(Paragraph *p) static int -iscodefence(Line *r, int size, line_type kind, mkd_flag_t flags) +iscodefence(Line *r, int size, line_type kind, mkd_flag_t *flags) { if ( !is_flag_set(flags, MKD_FENCEDCODE) ) return 0; - if ( !(r->flags & CHECKED) ) + if ( !(r->line_flags & CHECKED) ) checkline(r, flags); if ( kind ) @@ -639,7 +639,7 @@ iscodefence(Line *r, int size, line_type kind, mkd_flag_t flags) static Paragraph * -fencedcodeblock(ParagraphRoot *d, Line **ptr, mkd_flag_t flags) +fencedcodeblock(ParagraphRoot *d, Line **ptr, mkd_flag_t *flags) { Line *first, *r; Paragraph *ret; @@ -694,7 +694,7 @@ centered(Line *first, Line *last) static int -endoftextblock(Line *t, int toplevelblock, mkd_flag_t flags) +endoftextblock(Line *t, int toplevelblock, mkd_flag_t *flags) { int z; @@ -714,7 +714,7 @@ endoftextblock(Line *t, int toplevelblock, mkd_flag_t flags) static Line * -textblock(Paragraph *p, int toplevel, mkd_flag_t flags) +textblock(Paragraph *p, int toplevel, mkd_flag_t *flags) { Line *t, *next; @@ -749,7 +749,7 @@ szmarkerclass(char *p) #define iscsschar(c) (isalpha(c) || (c == '-') || (c == '_') ) static int -isdivmarker(Line *p, int start, mkd_flag_t flags) +isdivmarker(Line *p, int start, mkd_flag_t *flags) { char *s; int last, i; @@ -788,7 +788,7 @@ isdivmarker(Line *p, int start, mkd_flag_t flags) * way the markdown sample web form at Daring Fireball works. */ static Line * -quoteblock(Paragraph *p, mkd_flag_t flags) +quoteblock(Paragraph *p, mkd_flag_t *flags) { Line *t, *q; int qp; @@ -848,7 +848,7 @@ typedef int (*linefn)(Line *); * marker, but multiple paragraphs need to start with a 4-space indent. */ static Line * -listitem(Paragraph *p, int indent, mkd_flag_t flags, linefn check) +listitem(Paragraph *p, int indent, mkd_flag_t *flags, linefn check) { Line *t, *q; int clip = indent; @@ -872,9 +872,9 @@ listitem(Paragraph *p, int indent, mkd_flag_t flags, linefn check) if ( ischeck != CHECK_NOT ) { __mkd_trim_line(t, 3); - p->flags |= GITHUB_CHECK; + p->para_flags |= GITHUB_CHECK; if ( ischeck == CHECK_YES ) - p->flags |= IS_CHECKED; + p->para_flags |= IS_CHECKED; } firstpara = 0; } @@ -930,7 +930,7 @@ definition_block(Paragraph *top, int clip, MMIOT *f, int kind) while (( labels = q )) { - if ( (q = isdefinition(labels, &z, &kind, f->flags)) == 0 ) + if ( (q = isdefinition(labels, &z, &kind, &(f->flags))) == 0 ) break; if ( (text = skipempty(q->next)) == 0 ) @@ -950,7 +950,7 @@ definition_block(Paragraph *top, int clip, MMIOT *f, int kind) dd_block: p = Pp(&d, text, LISTITEM); - text = listitem(p, clip, f->flags, (kind==2) ? is_extra_dd : 0); + text = listitem(p, clip, &(f->flags), (kind==2) ? is_extra_dd : 0); p->down = compile(p->text, 0, f); p->text = labels; labels = 0; @@ -988,7 +988,7 @@ enumerated_block(Paragraph *top, int clip, MMIOT *f, int list_class) while (( text = q )) { p = Pp(&d, text, LISTITEM); - text = listitem(p, clip, f->flags, 0); + text = listitem(p, clip, &(f->flags), 0); p->down = compile(p->text, 0, f); p->text = 0; @@ -996,7 +996,7 @@ enumerated_block(Paragraph *top, int clip, MMIOT *f, int list_class) if ( para && p->down ) p->down->align = PARA; if ( (q = skipempty(text)) == 0 - || islist(q, &clip, f->flags, &z) != list_class ) + || islist(q, &clip, &(f->flags), &z) != list_class ) break; if ( para = (q != text) ) { @@ -1064,7 +1064,7 @@ addfootnote(Line *p, MMIOT* f) CREATE(foot->link); CREATE(foot->title); foot->text = 0; - foot->flags = foot->height = foot->width = 0; + foot->fn_flags = foot->height = foot->width = 0; /* keep the footnote label */ for (j=i=p->dle+1; T(p->text)[j] != ']'; j++) @@ -1075,12 +1075,12 @@ addfootnote(Line *p, MMIOT* f) /* consume the closing ]: */ j = nextnonblank(p, j+2); - if ( is_flag_set(f->flags, MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) { + if ( is_flag_set(&(f->flags), MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) { /* markdown extra footnote: All indented lines past this point; * the first line includes the footnote reference, so we need to * snip that out as we go. */ - foot->flags |= EXTRA_FOOTNOTE; + foot->fn_flags |= EXTRA_FOOTNOTE; __mkd_trim_line(p,j); np = extrablock(p); @@ -1197,14 +1197,14 @@ compile_document(Line *ptr, MMIOT *f) int previous_was_break = 1; while ( ptr ) { - if ( !is_flag_set(f->flags, MKD_NOHTML) && (tag = isopentag(ptr)) ) { + if ( !is_flag_set(&(f->flags), MKD_NOHTML) && (tag = isopentag(ptr)) ) { int blocktype; /* If we encounter a html/style block, compile and save all * of the cached source BEFORE processing the html/style. */ uncache(&source, &d, f); - if (is_flag_set(f->flags, MKD_NOSTYLE) ) + if (is_flag_set(&(f->flags), MKD_NOSTYLE) ) blocktype = HTML; else blocktype = strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML; @@ -1225,9 +1225,9 @@ compile_document(Line *ptr, MMIOT *f) ptr = consume(addfootnote(ptr, f), &eaten); previous_was_break = 1; } - else if ( previous_was_break && iscodefence(ptr,3,0,f->flags)) { + else if ( previous_was_break && iscodefence(ptr,3,0,&(f->flags)) ) { uncache(&source, &d, f); - if ( !fencedcodeblock(&d, &ptr, f->flags) ) /* just source */ + if ( !fencedcodeblock(&d, &ptr, &(f->flags)) ) /* just source */ goto attach; } else { @@ -1263,7 +1263,7 @@ actually_a_table(MMIOT *f, Line *pp) int c; /* tables need to be turned on */ - if ( is_flag_set(f->flags, MKD_NOTABLES) ) + if ( is_flag_set(&(f->flags), MKD_NOTABLES) ) return 0; /* tables need three lines */ @@ -1273,7 +1273,7 @@ actually_a_table(MMIOT *f, Line *pp) /* all lines must contain |'s */ for (r = pp; r; r = r->next ) - if ( !(r->flags & PIPECHAR) ) { + if ( !(r->line_flags & PIPECHAR) ) { return 0; } @@ -1322,7 +1322,7 @@ compile(Line *ptr, int toplevel, MMIOT *f) if ( iscode(ptr) ) { p = Pp(&d, ptr, CODE); - if ( is_flag_set(f->flags, MKD_1_COMPAT) ) { + if ( is_flag_set(&(f->flags), MKD_1_COMPAT) ) { /* HORRIBLE STANDARDS KLUDGE: the first line of every block * has trailing whitespace trimmed off. */ @@ -1331,15 +1331,15 @@ compile(Line *ptr, int toplevel, MMIOT *f) ptr = codeblock(p); } - else if ( iscodefence(ptr,3,0,f->flags) && (p=fencedcodeblock(&d, &ptr, f->flags)) ) + else if ( iscodefence(ptr,3,0,&(f->flags)) && (p=fencedcodeblock(&d, &ptr, &(f->flags))) ) /* yay, it's already done */ ; - else if ( ishr(ptr, f->flags) ) { + else if ( ishr(ptr, &(f->flags)) ) { p = Pp(&d, 0, HR); r = ptr; ptr = ptr->next; ___mkd_freeLine(r); } - else if ( list_class = islist(ptr, &indent, f->flags, &list_type) ) { + else if ( list_class = islist(ptr, &indent, &(f->flags), &list_type) ) { if ( list_class == DL ) { p = Pp(&d, ptr, DL); ptr = definition_block(p, indent, f, list_type); @@ -1351,11 +1351,11 @@ compile(Line *ptr, int toplevel, MMIOT *f) } else if ( isquote(ptr) ) { p = Pp(&d, ptr, QUOTE); - ptr = quoteblock(p, f->flags); + ptr = quoteblock(p, &(f->flags) ); p->down = compile(p->text, 1, f); p->text = 0; } - else if ( ishdr(ptr, &hdr_type, f->flags) ) { + else if ( ishdr(ptr, &hdr_type, &(f->flags) ) ) { p = Pp(&d, ptr, HDR); ptr = headerblock(p, hdr_type); } @@ -1377,7 +1377,7 @@ compile(Line *ptr, int toplevel, MMIOT *f) * processing with textblock() */ - if ( !is_flag_set(f->flags, MKD_NOHTML) && (tag = isopentag(ptr)) ) { + if ( !is_flag_set(&(f->flags), MKD_NOHTML) && (tag = isopentag(ptr)) ) { /* possibly an html block */ @@ -1387,7 +1387,7 @@ compile(Line *ptr, int toplevel, MMIOT *f) } } if ( unclosed ) { - ptr = textblock(p, toplevel, f->flags); + ptr = textblock(p, toplevel, &(f->flags) ); /* tables are a special kind of paragraph */ if ( actually_a_table(f, p->text) ) p->typ = TABLE; @@ -1413,19 +1413,52 @@ compile(Line *ptr, int toplevel, MMIOT *f) * debugging. */ + +#if DEBUG +static void +sayflags(char *pfx, mkd_flag_t* flags, FILE *output) +{ + int i; + + fprintf(output, "%.*s/", (int)strlen(pfx), " "); + for (i=0; icompiled ) { - if ( doc->ctx->flags == flags && !doc->dirty) + mkd_flag_t changed; + + if ( flags ) + COPY_FLAGS(changed, *flags); + else + mkd_init_flags(&changed); + + if ( AND_FLAGS(&changed, &(doc->ctx->flags)) && !doc->dirty ) return 1; else { doc->compiled = doc->dirty = 0; @@ -1440,12 +1473,15 @@ mkd_compile(Document *doc, mkd_flag_t flags) memset(doc->ctx, 0, sizeof(MMIOT) ); doc->ctx->ref_prefix= doc->ref_prefix; doc->ctx->cb = &(doc->cb); - doc->ctx->flags = flags; + sayflags("flags", flags, stderr); + COPY_FLAGS(doc->ctx->flags,*flags); + sayflags("used ", &(doc->ctx->flags), stderr); CREATE(doc->ctx->in); doc->ctx->footnotes = malloc(sizeof doc->ctx->footnotes[0]); doc->ctx->footnotes->reference = 0; CREATE(doc->ctx->footnotes->note); + mkd_initialize(); doc->code = compile_document(T(doc->content), doc->ctx); diff --git a/markdown.h b/markdown.h index 438a489..26b24ac 100644 --- a/markdown.h +++ b/markdown.h @@ -12,11 +12,64 @@ /* flags, captured into a named type */ -typedef DWORD mkd_flag_t; +enum { + MKD_NOLINKS, /* don't do link processing, block tags */ + MKD_NOIMAGE, /* don't do image processing, block */ + MKD_NOPANTS, /* don't run smartypants() */ + MKD_NOHTML, /* don't allow raw html through AT ALL */ + MKD_NORMAL_LISTITEM, /* disable github-style checkbox lists */ + MKD_TAGTEXT, /* process text inside an html tag; no , no , + * no html or [] expansion */ + MKD_NO_EXT, /* don't allow pseudo-protocols */ + MKD_NOEXT, /* ^^^ (aliased for user convenience) */ + MKD_CDATA, /* generate code for xml ![CDATA[...]] */ + MKD_NOSUPERSCRIPT, /* no A^B */ + MKD_NORELAXED, /* emphasis happens /everywhere/ */ + MKD_NOTABLES, /* disallow tables */ + MKD_NOSTRIKETHROUGH, /* forbid ~~strikethrough~~ */ + MKD_1_COMPAT, /* compatibility with MarkdownTest_1.0 */ + MKD_TOC, /* do table-of-contents processing */ + MKD_AUTOLINK, /* make http://foo.com link even without <>s */ + MKD_NOHEADER, /* don't process header blocks */ + MKD_TABSTOP, /* expand tabs to 4 spaces */ + MKD_SAFELINK, /* paranoid check for link protocol */ + MKD_NODIVQUOTE, /* forbid >%class% blocks */ + MKD_NOALPHALIST, /* forbid alphabetic lists */ + MKD_EXTRA_FOOTNOTE, /* enable markdown extra-style footnotes */ + MKD_NOSTYLE, /* don't extract