/* * theme: use a template to create a webpage (markdown-style) * * usage: theme [-d root] [-p pagename] [-t template] [-o html] [source] * */ /* * Copyright (C) 2007 David L Parsons. * The redistribution terms are provided in the COPYRIGHT file that must * be distributed with this source code. */ #include "config.h" #include "pgm_options.h" #include #include #include #if defined(HAVE_BASENAME) && defined(HAVE_LIBGEN_H) # include #endif #include #include #include #include #include #if HAVE_PWD_H # include #endif #include #include #include #include "mkdio.h" #include "cstring.h" #include "amalloc.h" char *pgm = "theme"; char *output = 0; char *pagename = 0; char *root = 0; int everywhere = 0; /* expand all = 0 && pos < S(inbuf) ) return T(inbuf)[pos]; return EOF; } static int shift(int shiftwidth) { psp += shiftwidth; return psp; } static int* cursor() { return T(inbuf) + psp; } static int thesame(int *p, char *pat) { int i; for ( i=0; pat[i]; i++ ) { if ( pat[i] == ' ' ) { if ( !isspace(peek(i+1)) ) { return 0; } } else if ( tolower(peek(i+1)) != pat[i] ) { return 0; } } return 1; } static int istag(int *p, char *pat) { int c; if ( thesame(p, pat) ) { c = peek(strlen(pat)+1); return (c == '>' || isspace(c)); } return 0; } /* finclude() includes some (unformatted) source */ static void finclude(MMIOT *doc, FILE *out, int flags, int whence) { int c; Cstring include; FILE *f; CREATE(include); while ( (c = pull()) != '(' ) ; while ( (c=pull()) != ')' && c != EOF ) EXPAND(include) = c; if ( c != EOF ) { EXPAND(include) = 0; S(include)--; if (( f = fopen(T(include), "r") )) { while ( (c = getc(f)) != EOF ) putc(c, out); fclose(f); } } DELETE(include); } /* fdirname() prints out the directory part of a path */ static void fdirname(MMIOT *doc, FILE *output, int flags, int whence) { char *p; if ( pagename && (p = basename(pagename)) ) fwrite(pagename, strlen(pagename)-strlen(p), 1, output); } /* fbasename() prints out the file name part of a path */ static void fbasename(MMIOT *doc, FILE *output, int flags, int whence) { char *p; if ( pagename ) { p = basename(pagename); if ( !p ) p = pagename; if ( p ) fwrite(p, strlen(p), 1, output); } } /* ftitle() prints out the document title */ static void ftitle(MMIOT *doc, FILE* output, int flags, int whence) { char *h; if ( (h = mkd_doc_title(doc)) == 0 && pagename ) h = pagename; if ( h ) mkd_generateline(h, strlen(h), output, flags); } /* fdate() prints out the document date */ static void fdate(MMIOT *doc, FILE *output, int flags, int whence) { char *h; if ( (h = mkd_doc_date(doc)) || ( infop && (h = ctime(&infop->st_mtime)) ) ) mkd_generateline(h, strlen(h), output, flags|MKD_TAGTEXT); } /* fauthor() prints out the document author */ static void fauthor(MMIOT *doc, FILE *output, int flags, int whence) { char *h = mkd_doc_author(doc); #if HAVE_PWD_H if ( (h == 0) && me ) h = me->pw_gecos; #endif if ( h ) mkd_generateline(h, strlen(h), output, flags); } /* fconfig() prints out a tabular version of * tabular versions of the flags. */ static void fconfig(MMIOT *doc, FILE *output, int flags, int whence) { mkd_mmiot_flags(output, doc, (whence & (INHEAD|INTAG)) ? 0 : 1); } /* fversion() prints out the document version */ static void fversion(MMIOT *doc, FILE *output, int flags, int whence) { fwrite(markdown_version, strlen(markdown_version), 1, output); } /* fbody() prints out the document */ static void fbody(MMIOT *doc, FILE *output, int flags, int whence) { mkd_generatehtml(doc, output); } /* ftoc() prints out the table of contents */ static void ftoc(MMIOT *doc, FILE *output, int flags, int whence) { mkd_generatetoc(doc, output); } /* fstyle() prints out the document's style section */ static void fstyle(MMIOT *doc, FILE *output, int flags, int whence) { mkd_generatecss(doc, output); } /* * theme expansions we love: * -- the document date (file or header date) * -- the document title (header title or document name) * -- the document author (header author or document owner) * -- the version# * -- the document body * -- the filename part of the document name * -- the directory part of the document name * -- the html file name * -- document-supplied style blocks * -- include a file. */ static struct _keyword { char *kw; int where; void (*what)(MMIOT*,FILE*,int,int); } keyword[] = { { "author?>", 0xffff, fauthor }, { "body?>", INBODY, fbody }, { "toc?>", INBODY, ftoc }, { "date?>", 0xffff, fdate }, { "dir?>", 0xffff, fdirname }, { "include(", 0xffff, finclude }, { "source?>", 0xffff, fbasename }, { "style?>", INHEAD, fstyle }, { "title?>", 0xffff, ftitle }, { "version?>", 0xffff, fversion }, { "config?>", 0xffff, fconfig }, }; #define NR(x) (sizeof x / sizeof x[0]) /* spin() - run through the theme template, looking for ') ); } else if ( (peek(1) == '?') && thesame(cursor(), "?theme ") ) { shift(strlen("?theme ")); while ( ((c = pull()) != EOF) && isspace(c) ) ; shift(-1); p = cursor(); if ( where & INTAG ) flags = MKD_TAGTEXT; else if ( where & INHEAD ) flags = MKD_NOIMAGE|MKD_NOLINKS; else flags = 0; for (i=0; i < NR(keyword); i++) if ( thesame(p, keyword[i].kw) ) { if ( everywhere || (keyword[i].where & where) ) (*keyword[i].what)(doc,output,flags,where); break; } while ( (c = pull()) != EOF && (c != '?' && peek(1) != '>') ) ; shift(1); } else putc(c, output); if ( istag(cursor(), "head") ) { where |= INHEAD; where &= ~INBODY; } else if ( istag(cursor(), "body") ) { where &= ~INHEAD; where |= INBODY; } where |= INTAG; continue; } else if ( c == '>' ) where &= ~INTAG; putc(c, output); } } /* spin */ main(argc, argv) char **argv; { char *template = "page.theme"; char *source = "stdin"; FILE *tmplfile; int opt; mkd_flag_t flags = MKD_TOC; int force = 0; MMIOT *doc; struct stat sourceinfo; opterr=1; pgm = basename(argv[0]); while ( (opt=getopt(argc, argv, "EfC:c:d:t:p:o:V")) != EOF ) { switch (opt) { case 'd': root = optarg; break; case 'E': everywhere = 1; break; case 'p': pagename = optarg; break; case 'f': force = 1; break; case 't': template = optarg; break; case 'C': if ( strcmp(optarg, "?") == 0 ) { show_flags(0); exit(0); } else flags = strtol(optarg, 0, 0); break; case 'c': if ( strcmp(optarg, "?") == 0 ) { show_flags(1); exit(0); } else if ( !set_flag(&flags, optarg) ) fprintf(stderr,"%s: unknown option <%s>", pgm, optarg); break; case 'o': output = optarg; break; case 'V': printf("theme+discount %s\n", markdown_version); exit(0); default: fprintf(stderr, "usage: %s [-V] [-d dir] [-p pagename] [-t template] [-o html] [file]\n", pgm); exit(1); } } tmplfile = open_template(template); argc -= optind; argv += optind; if ( argc > 0 ) { int added_text=0; if ( (source = malloc(strlen(argv[0]) + strlen("/index.text") + 1)) == 0 ) fail("out of memory allocating name buffer"); strcpy(source,argv[0]); if ( (stat(source, &sourceinfo) == 0) && S_ISDIR(sourceinfo.st_mode) ) strcat(source, "/index"); if ( !freopen(source, "r", stdin) ) { strcat(source, ".text"); added_text = 1; if ( !freopen(source, "r", stdin) ) fail("can't open either %s or %s", argv[0], source); } if ( !output ) { char *p, *q; output = alloca(strlen(source) + strlen(".html") + 1); strcpy(output, source); if (( p = strchr(output, '/') )) q = strrchr(p+1, '.'); else q = strrchr(output, '.'); if ( q ) *q = 0; else q = output + strlen(output); strcat(q, ".html"); } } if ( output ) { if ( force ) unlink(output); if ( !freopen(output, "w", stdout) ) fail("can't write to %s", output); } if ( !pagename ) pagename = source; if ( (doc = mkd_in(stdin, 0)) == 0 ) fail("can't read %s", source ? source : "stdin"); if ( fstat(fileno(stdin), &sourceinfo) == 0 ) infop = &sourceinfo; #if HAVE_GETPWUID me = getpwuid(infop ? infop->st_uid : getuid()); if ( (root = strdup(me->pw_dir)) == 0 ) fail("out of memory"); #endif if ( !mkd_compile(doc, flags) ) fail("couldn't compile input"); if ( tmplfile ) spin(tmplfile,doc,stdout); else mkd_generatehtml(doc, stdout); mkd_cleanup(doc); exit(0); }