From 9397c0a5c73c037160cf1c8ffdfd8fbe6b724c55 Mon Sep 17 00:00:00 2001 From: David Parsons Date: Fri, 27 Feb 2009 16:47:02 -0800 Subject: [PATCH] Redo toc.c to add the new function `mkd_toc()`, which writes the generate toc to a string. Documented in `markdown.3` and `mkd-functions.3`, requires a new file (`Csio.c`) that has functions for writing to a Cstring, requires that some of the internal functions in `generate.c` be exposed (and renaed to `__mkd_`*function* to reduce namespace collisions. The new functions in Csio (particularly `Csprintf()` should make it easier to convert many of the other "we print to a `FILE*` and you need to lump it" functions into a pair of "print to a string" and "print to a file" functions. --- Csio.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ Makefile.in | 2 +- cstring.h | 4 ++++ generate.c | 36 +++++++++++++++++----------------- main.c | 17 +++++++++++++--- markdown.3 | 4 +++- mkd-functions.3 | 17 ++++++++++++++-- toc.c | 52 ++++++++++++++++++++++++++++++++++++------------- 8 files changed, 143 insertions(+), 38 deletions(-) create mode 100644 Csio.c diff --git a/Csio.c b/Csio.c new file mode 100644 index 0000000..ca6a908 --- /dev/null +++ b/Csio.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include "cstring.h" +#include "markdown.h" +#include "amalloc.h" + + +/* putc() into a cstring + */ +int +Csputc(int c, Cstring *iot) +{ + EXPAND(*iot) = c; + return 1; +} + + +/* printf() into a cstring + */ +int +Csprintf(Cstring *iot, char *fmt, ...) +{ + va_list ptr; + int siz=100; + + do { + RESERVE(*iot, siz); + va_start(ptr, fmt); + siz = vsnprintf(T(*iot)+S(*iot), ALL(*iot)-S(*iot), fmt, ptr); + va_end(ptr); + } while ( siz > (ALL(*iot)-S(*iot)) ); + + S(*iot) += siz; + return siz; +} + + +/* reparse() into a cstring + */ +Csreparse(Cstring *iot, char *buf, int size, int flags) +{ + MMIOT f; + ___mkd_initmmiot(&f, 0); + __mkd_reparse(buf, size, 0, &f); + __mkd_emblock(&f); + SUFFIX(*iot, T(f.out), S(f.out)); + ___mkd_freemmiot(&f, 0); +} diff --git a/Makefile.in b/Makefile.in index 06b4c14..fd35b19 100644 --- a/Makefile.in +++ b/Makefile.in @@ -12,7 +12,7 @@ SAMPLE_PGMS=mkd2html makepage @THEME@SAMPLE_PGMS+= theme MKDLIB=libmarkdown.a OBJS=mkdio.o markdown.o dumptree.o generate.o \ - resource.o docheader.o version.o toc.o xmlpage.o @AMALLOC@ + resource.o docheader.o version.o toc.o Csio.o xmlpage.o @AMALLOC@ all: $(PGMS) $(SAMPLE_PGMS) diff --git a/cstring.h b/cstring.h index a221042..40ae3b0 100644 --- a/cstring.h +++ b/cstring.h @@ -50,6 +50,7 @@ */ #define T(x) (x).text #define S(x) (x).size +#define ALL(x) (x).alloc /* abstract anchor type that defines a list base * with a function that attaches an element to @@ -65,4 +66,7 @@ typedef STRING(char) Cstring; +extern int Csputc(int, Cstring *); +extern int Csprintf(Cstring *, char *, ...); + #endif/*_CSTRING_D*/ diff --git a/generate.c b/generate.c index 6050b8c..a964cda 100644 --- a/generate.c +++ b/generate.c @@ -277,10 +277,10 @@ emmatch(MMIOT *f, int go) } -/* emblock() +/* __mkd_emblock() */ -static void -emblock(MMIOT *f) +void +__mkd_emblock(MMIOT *f) { int i; block *p; @@ -301,8 +301,8 @@ emblock(MMIOT *f) /* generate html from a markup fragment */ -static void -reparse(char *bfr, int size, int flags, MMIOT *f) +void +__mkd_reparse(char *bfr, int size, int flags, MMIOT *f) { MMIOT sub; @@ -316,7 +316,7 @@ reparse(char *bfr, int size, int flags, MMIOT *f) S(sub.in)--; text(&sub); - emblock(&sub); + __mkd_emblock(&sub); Qwrite(T(sub.out), S(sub.out), f); @@ -633,12 +633,12 @@ linkylinky(int image, MMIOT *f) if ( S(link.title) ) { Qstring(" title=\"", f); - reparse(T(link.title), S(link.title), INSIDE_TAG, f); + __mkd_reparse(T(link.title), S(link.title), INSIDE_TAG, f); Qchar('"', f); } Qstring(tag->text_pfx, f); - reparse(T(link.tag), S(link.tag), tag->flags, f); + __mkd_reparse(T(link.tag), S(link.tag), tag->flags, f); Qstring(tag->text_sfx, f); } else @@ -883,7 +883,7 @@ smartypants(int c, int *flags, MMIOT *f) break; else if ( c == '\'' && peek(f, j+1) == '\'' ) { Qstring("“", f); - reparse(cursor(f)+1, j-2, 0, f); + __mkd_reparse(cursor(f)+1, j-2, 0, f); Qstring("”", f); shift(f,j+1); return 1; @@ -949,7 +949,7 @@ text(MMIOT *f) ++len; } shift(f,len); - reparse(sup, len, 0, f); + __mkd_reparse(sup, len, 0, f); Qstring("", f); } break; @@ -1189,19 +1189,19 @@ printhtml(Line *t, MMIOT *f) static void htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f) { - emblock(f); + __mkd_emblock(f); if ( block ) Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments); - emblock(f); + __mkd_emblock(f); while (( p = display(p, f) )) { - emblock(f); + __mkd_emblock(f); Qstring("\n\n", f); } if ( block ) Qprintf(f, "", block); - emblock(f); + __mkd_emblock(f); } @@ -1217,7 +1217,7 @@ definitionlist(Paragraph *p, MMIOT *f) for ( ; p ; p = p->next) { for ( tag = p->text; tag; tag = tag->next ) { Qstring("
", f); - reparse(T(tag->text), S(tag->text), 0, f); + __mkd_reparse(T(tag->text), S(tag->text), 0, f); Qstring("
\n", f); } @@ -1343,7 +1343,7 @@ mkd_document(Document *p, char **res) } -/* public interface for reparse() +/* public interface for __mkd_reparse() */ int mkd_text(char *bfr, int size, FILE *output, int flags) @@ -1353,8 +1353,8 @@ mkd_text(char *bfr, int size, FILE *output, int flags) ___mkd_initmmiot(&f, 0); f.flags = flags & USER_FLAGS; - reparse(bfr, size, 0, &f); - emblock(&f); + __mkd_reparse(bfr, size, 0, &f); + __mkd_emblock(&f); if ( flags & CDATA_OUTPUT ) ___mkd_xml(T(f.out), S(f.out), output); else diff --git a/main.c b/main.c index 12be3e5..b5a3f68 100644 --- a/main.c +++ b/main.c @@ -100,6 +100,7 @@ main(int argc, char **argv) int rc; int flags = 0; int debug = 0; + int toc = 0; int use_mkd_text = 0; char *text = 0; char *ofile = 0; @@ -112,7 +113,7 @@ main(int argc, char **argv) pgm = basename(argv[0]); opterr = 1; - while ( (opt=getopt(argc, argv, "b:df:F:o:s:t:V")) != EOF ) { + while ( (opt=getopt(argc, argv, "b:df:F:o:s:t:TV")) != EOF ) { switch (opt) { case 'b': urlbase = optarg; break; @@ -127,6 +128,8 @@ main(int argc, char **argv) case 't': text = optarg; use_mkd_text = 1; break; + case 'T': toc = 1; + break; case 's': text = optarg; break; case 'o': if ( ofile ) { @@ -171,8 +174,16 @@ main(int argc, char **argv) if ( debug ) rc = mkd_dump(doc, stdout, 0, argc ? basename(argv[0]) : "stdin"); - else - rc = markdown(doc, stdout, flags); + else { + rc = 1; + if ( mkd_compile(doc, flags) ) { + rc = 0; + if ( toc ) + mkd_generatetoc(doc, stdout); + mkd_generatehtml(doc, stdout); + mkd_cleanup(doc); + } + } } adump(); exit( (rc == 0) ? 0 : errno ); diff --git a/markdown.3 b/markdown.3 index 3ce0a32..6def6a1 100644 --- a/markdown.3 +++ b/markdown.3 @@ -88,7 +88,9 @@ was originally configured for. .It Ar MKD_TOC Label all headers for use with the .Fn mkd_generatetoc -function. +and +.Fn mkd_toc +functions. .El .Sh RETURN VALUES The functions diff --git a/mkd-functions.3 b/mkd-functions.3 index 0b62d80..5fa9738 100644 --- a/mkd-functions.3 +++ b/mkd-functions.3 @@ -20,6 +20,8 @@ Markdown .Fn mkd_generatehtml "MMIOT *document" "FILE *output" .Ft int .Fn mkd_xhtmlpage "MMIOT *document" "int flags" "FILE *output" +.Ft int +.Fn mkd_toc "MMIOT *document" "char **doc" .Ft void .Fn mkd_generatetoc "MMIOT *document" "FILE *output" .Ft void @@ -65,6 +67,7 @@ by the .Fn mkd_style , .Fn mkd_document , .Fn mkd_generatehtml , +.Fn mkd_toc , .Fn mkd_generatetoc , .Fn mkd_xhtmlpage , .Fn mkd_doc_title , @@ -93,9 +96,19 @@ if any. writes a xhtml page containing the document. The regular set of flags can be passed. .Pp +.Fn mkd_toc +writes a document outline, in the form of a collection of nested +lists with links to each header in the document, into a string +allocated with +.Fn malloc , +and returns the size. +.Pp .Fn mkd_generatetoc -Writes a document outline, in the form of a collection of nested -lists, with links to each header in the document. +is like +.Fn mkd_toc , +except that it writes the document outline to the given +.Pa FILE* +argument. .Pp .Fn mkd_cleanup deletes a diff --git a/toc.c b/toc.c index 8fe240d..e87c57a 100644 --- a/toc.c +++ b/toc.c @@ -17,12 +17,18 @@ /* write an header index */ int -mkd_generatetoc(Document *p, FILE *output) +mkd_toc(Document *p, char **doc) { Paragraph *pp; - int last_hnumber = 0, first_hnumber = 0; + Cstring res; + char bfr[200]; + + CREATE(res); + RESERVE(res, 100); + + *doc = 0; if ( !(p && p->ctx) ) return -1; if ( ! (p->ctx->flags & TOC) ) return 0; @@ -31,32 +37,52 @@ mkd_generatetoc(Document *p, FILE *output) if ( pp->typ == HDR && pp->text ) { if ( last_hnumber == pp->hnumber ) - fprintf(output, "%*s\n", pp->hnumber, ""); + Csprintf(&res, "%*s\n", pp->hnumber, ""); else while ( last_hnumber > pp->hnumber ) { - fprintf(output, "%*s\n%*s\n", + Csprintf(&res, "%*s\n%*s\n", last_hnumber, "", last_hnumber-1,""); --last_hnumber; } while ( pp->hnumber > last_hnumber ) { - fprintf(output, "\n%*s\n", last_hnumber, "", last_hnumber, ""); --last_hnumber; } - - return 0; + /* HACK ALERT! HACK ALERT! HACK ALERT! */ + *doc = T(res); /* we know that a T(Cstring) is a character pointer */ + /* so we can simply pick it up and carry it away, */ + return S(res); /* leaving the husk of the Ctring on the stack */ + /* END HACK ALERT */ } + +/* write an header index + */ +int +mkd_generatetoc(Document *p, FILE *out) +{ + char *buf = 0; + int sz = mkd_toc(p, &buf); + int ret = EOF; + + if ( sz > 0 ) + ret = fwrite(buf, sz, 1, out); + + if ( buf ) free(buf); + + return ret; +}