Warning, file /education/cantor/thirdparty/discount-2.2.6-patched/theme.c was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * theme: use a template to create a webpage (markdown-style) 0003 * 0004 * usage: theme [-d root] [-p pagename] [-t template] [-o html] [source] 0005 * 0006 */ 0007 /* 0008 * Copyright (C) 2007 David L Parsons. 0009 * The redistribution terms are provided in the COPYRIGHT file that must 0010 * be distributed with this source code. 0011 */ 0012 #include "config.h" 0013 #include "pgm_options.h" 0014 0015 #include <stdio.h> 0016 #include <stdlib.h> 0017 #include <string.h> 0018 #if defined(HAVE_BASENAME) && defined(HAVE_LIBGEN_H) 0019 # include <libgen.h> 0020 #endif 0021 #include <stdarg.h> 0022 #include <sys/types.h> 0023 #include <sys/stat.h> 0024 #include <time.h> 0025 #if HAVE_PWD_H 0026 # include <pwd.h> 0027 #endif 0028 #include <fcntl.h> 0029 #include <errno.h> 0030 #include <ctype.h> 0031 #include <unistd.h> 0032 0033 #include "mkdio.h" 0034 #include "cstring.h" 0035 #include "amalloc.h" 0036 #include "gethopt.h" 0037 0038 char *pgm = "theme"; 0039 char *output_file = 0; 0040 char *pagename = 0; 0041 char *root = 0; 0042 int everywhere = 0; /* expand all <?theme elements everywhere */ 0043 0044 #if HAVE_PWD_H 0045 struct passwd *me = 0; 0046 #endif 0047 struct stat *infop = 0; 0048 0049 #if USE_H1TITLE 0050 extern char* mkd_h1_title(MMIOT*); 0051 #endif 0052 0053 extern int notspecial(char *filename); 0054 0055 #define INTAG 0x01 0056 #define INHEAD 0x02 0057 #define INBODY 0x04 0058 0059 0060 #ifndef HAVE_BASENAME 0061 char * 0062 basename(char *path) 0063 { 0064 char *p; 0065 0066 if ( p = strrchr(path, '/') ) 0067 return 1+p; 0068 return path; 0069 } 0070 #endif 0071 0072 #ifdef HAVE_FCHDIR 0073 typedef int HERE; 0074 #define NOT_HERE (-1) 0075 0076 #define pushd(d) open(d, O_RDONLY) 0077 0078 int 0079 popd(HERE pwd) 0080 { 0081 int rc = fchdir(pwd); 0082 close(pwd); 0083 return rc; 0084 } 0085 0086 #else 0087 0088 typedef char* HERE; 0089 #define NOT_HERE 0 0090 0091 HERE 0092 pushd(char *d) 0093 { 0094 HERE cwd; 0095 int size; 0096 0097 if ( chdir(d) == -1 ) 0098 return NOT_HERE; 0099 0100 for (cwd = malloc(size=40); cwd; cwd = realloc(cwd, size *= 2)) 0101 if ( getcwd(cwd, size) ) 0102 return cwd; 0103 0104 return NOT_HERE; 0105 } 0106 0107 int 0108 popd(HERE pwd) 0109 { 0110 if ( pwd ) { 0111 int rc = chdir(pwd); 0112 free(pwd); 0113 0114 return rc; 0115 } 0116 return -1; 0117 } 0118 #endif 0119 0120 typedef STRING(int) Istring; 0121 0122 void 0123 fail(char *why, ...) 0124 { 0125 va_list ptr; 0126 0127 va_start(ptr,why); 0128 fprintf(stderr, "%s: ", pgm); 0129 vfprintf(stderr, why, ptr); 0130 fputc('\n', stderr); 0131 va_end(ptr); 0132 exit(1); 0133 } 0134 0135 0136 /* open_template() -- start at the current directory and work up, 0137 * looking for the deepest nested template. 0138 * Stop looking when we reach $root or / 0139 */ 0140 FILE * 0141 open_template(char *template) 0142 { 0143 char *cwd; 0144 int szcwd; 0145 HERE here = pushd("."); 0146 FILE *ret; 0147 0148 if ( here == NOT_HERE ) 0149 fail("cannot access the current directory"); 0150 0151 szcwd = root ? 1 + strlen(root) : 2; 0152 0153 if ( (cwd = malloc(szcwd)) == 0 ) 0154 return 0; 0155 0156 while ( !(ret = fopen(template, "r")) ) { 0157 if ( getcwd(cwd, szcwd) == 0 ) { 0158 if ( errno == ERANGE ) 0159 goto up; 0160 break; 0161 } 0162 0163 if ( root && (strcmp(root, cwd) == 0) ) 0164 break; /* ran out of paths to search */ 0165 else if ( (strcmp(cwd, "/") == 0) || (*cwd == 0) ) 0166 break; /* reached / */ 0167 0168 up: if ( chdir("..") == -1 ) 0169 break; 0170 } 0171 free(cwd); 0172 popd(here); 0173 return ret; 0174 } /* open_template */ 0175 0176 0177 static Istring inbuf; 0178 static int psp; 0179 0180 static int 0181 prepare(FILE *input) 0182 { 0183 int c; 0184 0185 CREATE(inbuf); 0186 psp = 0; 0187 while ( (c = getc(input)) != EOF ) 0188 EXPAND(inbuf) = c; 0189 fclose(input); 0190 return 1; 0191 } 0192 0193 static int 0194 pull() 0195 { 0196 return psp < S(inbuf) ? T(inbuf)[psp++] : EOF; 0197 } 0198 0199 static int 0200 peek(int offset) 0201 { 0202 int pos = (psp + offset)-1; 0203 0204 if ( pos >= 0 && pos < S(inbuf) ) 0205 return T(inbuf)[pos]; 0206 0207 return EOF; 0208 } 0209 0210 static int 0211 shift(int shiftwidth) 0212 { 0213 psp += shiftwidth; 0214 return psp; 0215 } 0216 0217 static int* 0218 cursor() 0219 { 0220 return T(inbuf) + psp; 0221 } 0222 0223 0224 static int 0225 thesame(int *p, char *pat) 0226 { 0227 int i; 0228 0229 for ( i=0; pat[i]; i++ ) { 0230 if ( pat[i] == ' ' ) { 0231 if ( !isspace(peek(i+1)) ) { 0232 return 0; 0233 } 0234 } 0235 else if ( tolower(peek(i+1)) != pat[i] ) { 0236 return 0; 0237 } 0238 } 0239 return 1; 0240 } 0241 0242 0243 static int 0244 istag(int *p, char *pat) 0245 { 0246 int c; 0247 0248 if ( thesame(p, pat) ) { 0249 c = peek(strlen(pat)+1); 0250 return (c == '>' || isspace(c)); 0251 } 0252 return 0; 0253 } 0254 0255 0256 /* finclude() includes some (unformatted) source 0257 */ 0258 static void 0259 finclude(MMIOT *doc, FILE *out, int flags, int whence) 0260 { 0261 int c; 0262 Cstring include; 0263 FILE *f; 0264 0265 CREATE(include); 0266 0267 while ( (c = pull()) != '(' ) 0268 ; 0269 0270 while ( (c=pull()) != ')' && c != EOF ) 0271 EXPAND(include) = c; 0272 0273 if ( c != EOF ) { 0274 EXPAND(include) = 0; 0275 S(include)--; 0276 0277 if (( f = fopen(T(include), "r") )) { 0278 while ( (c = getc(f)) != EOF ) 0279 putc(c, out); 0280 fclose(f); 0281 } 0282 } 0283 DELETE(include); 0284 } 0285 0286 0287 /* fdirname() prints out the directory part of a path 0288 */ 0289 static void 0290 fdirname(MMIOT *doc, FILE *output, int flags, int whence) 0291 { 0292 char *p; 0293 0294 if ( pagename && (p = basename(pagename)) ) 0295 fwrite(pagename, strlen(pagename)-strlen(p), 1, output); 0296 } 0297 0298 0299 /* fbasename() prints out the file name part of a path 0300 */ 0301 static void 0302 fbasename(MMIOT *doc, FILE *output, int flags, int whence) 0303 { 0304 char *p; 0305 0306 if ( pagename ) { 0307 p = basename(pagename); 0308 0309 if ( !p ) 0310 p = pagename; 0311 0312 if ( p ) 0313 fwrite(p, strlen(p), 1, output); 0314 } 0315 } 0316 0317 0318 /* ftitle() prints out the document title 0319 */ 0320 static void 0321 ftitle(MMIOT *doc, FILE* output, int flags, int whence) 0322 { 0323 char *h; 0324 h = mkd_doc_title(doc); 0325 0326 #if USE_H1TITLE 0327 if ( !h ) 0328 h = mkd_h1_title(doc); 0329 #endif 0330 0331 if ( !h ) 0332 h = pagename; 0333 0334 if ( h ) 0335 mkd_generateline(h, strlen(h), output, flags); 0336 } 0337 0338 0339 /* fdate() prints out the document date 0340 */ 0341 static void 0342 fdate(MMIOT *doc, FILE *output, int flags, int whence) 0343 { 0344 char *h; 0345 0346 if ( (h = mkd_doc_date(doc)) || ( infop && (h = ctime(&infop->st_mtime)) ) ) 0347 mkd_generateline(h, strlen(h), output, flags|MKD_TAGTEXT); 0348 } 0349 0350 0351 /* fauthor() prints out the document author 0352 */ 0353 static void 0354 fauthor(MMIOT *doc, FILE *output, int flags, int whence) 0355 { 0356 char *h = mkd_doc_author(doc); 0357 0358 #if HAVE_PWD_H 0359 if ( (h == 0) && me ) 0360 h = me->pw_gecos; 0361 #endif 0362 0363 if ( h ) 0364 mkd_generateline(h, strlen(h), output, flags); 0365 } 0366 0367 0368 /* fconfig() prints out a tabular version of 0369 * tabular versions of the flags. 0370 */ 0371 static void 0372 fconfig(MMIOT *doc, FILE *output, int flags, int whence) 0373 { 0374 mkd_mmiot_flags(output, doc, (whence & (INHEAD|INTAG)) ? 0 : 1); 0375 } 0376 0377 0378 /* fversion() prints out the document version 0379 */ 0380 static void 0381 fversion(MMIOT *doc, FILE *output, int flags, int whence) 0382 { 0383 fwrite(markdown_version, strlen(markdown_version), 1, output); 0384 } 0385 0386 0387 /* fbody() prints out the document 0388 */ 0389 static void 0390 fbody(MMIOT *doc, FILE *output, int flags, int whence) 0391 { 0392 mkd_generatehtml(doc, output); 0393 } 0394 0395 /* ftoc() prints out the table of contents 0396 */ 0397 static void 0398 ftoc(MMIOT *doc, FILE *output, int flags, int whence) 0399 { 0400 mkd_generatetoc(doc, output); 0401 } 0402 0403 /* fstyle() prints out the document's style section 0404 */ 0405 static void 0406 fstyle(MMIOT *doc, FILE *output, int flags, int whence) 0407 { 0408 mkd_generatecss(doc, output); 0409 } 0410 0411 0412 /* 0413 * theme expansions we love: 0414 * <?theme date?> -- the document date (file or header date) 0415 * <?theme title?> -- the document title (header title or document name) 0416 * <?theme author?> -- the document author (header author or document owner) 0417 * <?theme version?> -- the version# 0418 * <?theme body?> -- the document body 0419 * <?theme source?> -- the filename part of the document name 0420 * <?theme dir?> -- the directory part of the document name 0421 * <?theme html?> -- the html file name 0422 * <?theme style?> -- document-supplied style blocks 0423 * <?theme include(file)?> -- include a file. 0424 */ 0425 static struct _keyword { 0426 char *kw; 0427 int where; 0428 void (*what)(MMIOT*,FILE*,int,int); 0429 } keyword[] = { 0430 { "author?>", 0xffff, fauthor }, 0431 { "body?>", INBODY, fbody }, 0432 { "toc?>", INBODY, ftoc }, 0433 { "date?>", 0xffff, fdate }, 0434 { "dir?>", 0xffff, fdirname }, 0435 { "include(", 0xffff, finclude }, 0436 { "source?>", 0xffff, fbasename }, 0437 { "style?>", INHEAD, fstyle }, 0438 { "title?>", 0xffff, ftitle }, 0439 { "version?>", 0xffff, fversion }, 0440 { "config?>", 0xffff, fconfig }, 0441 }; 0442 #define NR(x) (sizeof x / sizeof x[0]) 0443 0444 0445 /* spin() - run through the theme template, looking for <?theme expansions 0446 */ 0447 void 0448 spin(FILE *template, MMIOT *doc, FILE *output) 0449 { 0450 int c; 0451 int *p; 0452 int flags; 0453 int where = 0x0; 0454 int i; 0455 0456 prepare(template); 0457 0458 while ( (c = pull()) != EOF ) { 0459 if ( c == '<' ) { 0460 if ( peek(1) == '!' && peek(2) == '-' && peek(3) == '-' ) { 0461 fputs("<!--", output); 0462 shift(3); 0463 do { 0464 putc(c=pull(), output); 0465 } while ( ! (c == '-' && peek(1) == '-' && peek(2) == '>') ); 0466 } 0467 else if ( (peek(1) == '?') && thesame(cursor(), "?theme ") ) { 0468 shift(strlen("?theme ")); 0469 0470 while ( ((c = pull()) != EOF) && isspace(c) ) 0471 ; 0472 0473 shift(-1); 0474 p = cursor(); 0475 0476 if ( where & INTAG ) 0477 flags = MKD_TAGTEXT; 0478 else if ( where & INHEAD ) 0479 flags = MKD_NOIMAGE|MKD_NOLINKS; 0480 else 0481 flags = 0; 0482 0483 for (i=0; i < NR(keyword); i++) 0484 if ( thesame(p, keyword[i].kw) ) { 0485 if ( everywhere || (keyword[i].where & where) ) 0486 (*keyword[i].what)(doc,output,flags,where); 0487 break; 0488 } 0489 0490 while ( (c = pull()) != EOF && (c != '?' && peek(1) != '>') ) 0491 ; 0492 shift(1); 0493 } 0494 else 0495 putc(c, output); 0496 0497 if ( istag(cursor(), "head") ) { 0498 where |= INHEAD; 0499 where &= ~INBODY; 0500 } 0501 else if ( istag(cursor(), "body") ) { 0502 where &= ~INHEAD; 0503 where |= INBODY; 0504 } 0505 where |= INTAG; 0506 continue; 0507 } 0508 else if ( c == '>' ) 0509 where &= ~INTAG; 0510 0511 putc(c, output); 0512 } 0513 } /* spin */ 0514 0515 0516 struct h_opt opts[] = { 0517 { 0, 0, 'c', "flags", "set/show rendering options" }, 0518 { 0, 0, 'C', "bitmap", "set/show rendering options numerically" }, 0519 { 0, 0, 'd', "dir", "set the document root" }, 0520 { 0, 0, 'E', 0, "do all theme expansions everywhere" }, 0521 { 0, 0, 'f', 0, "forcibly overwrite existing html files" }, 0522 { 0, 0, 'o', "file", "write output to `file`" }, 0523 { 0, 0, 'p', "title", "set the page title" }, 0524 { 0, 0, 't', "template", "use `template` as template file" }, 0525 { 0, 0, 'V', 0, "show version info" }, 0526 } ; 0527 #define NROPTS (sizeof opts / sizeof opts[0]) 0528 0529 int 0530 main(argc, argv) 0531 char **argv; 0532 { 0533 char *template = "page.theme"; 0534 char *source = "stdin"; 0535 FILE *tmplfile; 0536 mkd_flag_t flags = THEME_CF|MKD_TOC; 0537 int force = 0; 0538 MMIOT *doc; 0539 struct stat sourceinfo; 0540 char *q; 0541 0542 struct h_opt *opt; 0543 struct h_context blob; 0544 0545 hoptset(&blob, argc, argv); 0546 hopterr(&blob, 1); 0547 0548 pgm = basename(argv[0]); 0549 0550 while ( opt = gethopt(&blob, opts, NROPTS) ) { 0551 if ( opt == HOPTERR ) { 0552 hoptusage(pgm, opts, NROPTS, "[file]"); 0553 exit(1); 0554 } 0555 switch ( opt->optchar ) { 0556 case 'd': root = hoptarg(&blob); 0557 break; 0558 case 'E': everywhere = 1; 0559 break; 0560 case 'p': pagename = hoptarg(&blob); 0561 break; 0562 case 'f': force = 1; 0563 break; 0564 case 't': template = hoptarg(&blob); 0565 break; 0566 case 'C': if ( strcmp(hoptarg(&blob), "?") == 0 ) { 0567 show_flags(0,0); 0568 exit(0); 0569 } 0570 else 0571 flags = strtol(hoptarg(&blob), 0, 0); 0572 break; 0573 case 'c': if ( strcmp(hoptarg(&blob), "?") == 0 ) { 0574 show_flags(1,0); 0575 exit(0); 0576 } 0577 else if ( q = set_flag(&flags, hoptarg(&blob)) ) 0578 fprintf(stderr,"%s: unknown option <%s>", pgm, q); 0579 break; 0580 case 'o': output_file = hoptarg(&blob); 0581 break; 0582 case 'V': printf("theme+discount %s\n", markdown_version); 0583 exit(0); 0584 } 0585 } 0586 0587 tmplfile = open_template(template); 0588 0589 argc -= hoptind(&blob); 0590 argv += hoptind(&blob); 0591 0592 0593 if ( argc > 0 ) { 0594 int added_text=0; 0595 0596 if ( (source = malloc(strlen(argv[0]) + strlen("/index.text") + 1)) == 0 ) 0597 fail("out of memory allocating name buffer"); 0598 0599 strcpy(source,argv[0]); 0600 if ( (stat(source, &sourceinfo) == 0) && S_ISDIR(sourceinfo.st_mode) ) 0601 strcat(source, "/index"); 0602 0603 if ( !freopen(source, "r", stdin) ) { 0604 strcat(source, ".text"); 0605 added_text = 1; 0606 if ( !freopen(source, "r", stdin) ) 0607 fail("can't open either %s or %s", argv[0], source); 0608 } 0609 0610 if ( !output_file ) { 0611 char *p, *q; 0612 0613 0614 if ( (output_file = malloc(strlen(source) + strlen(".html") + 1)) == 0 ) 0615 fail("out of memory allocating output file name buffer"); 0616 0617 strcpy(output_file, source); 0618 0619 if (( p = strchr(output_file, '/') )) 0620 q = strrchr(p+1, '.'); 0621 else 0622 q = strrchr(output_file, '.'); 0623 0624 if ( q ) 0625 *q = 0; 0626 else 0627 q = output_file + strlen(output_file); 0628 0629 strcat(q, ".html"); 0630 } 0631 } 0632 if ( output_file && strcmp(output_file, "-") ) { 0633 if ( force && notspecial(output_file) ) 0634 unlink(output_file); 0635 if ( !freopen(output_file, "w", stdout) ) { 0636 fail("can't write to %s", output_file); 0637 } 0638 } 0639 0640 if ( !pagename ) 0641 pagename = source; 0642 0643 if ( (doc = mkd_in(stdin, 0)) == 0 ) 0644 fail("can't read %s", source ? source : "stdin"); 0645 0646 if ( fstat(fileno(stdin), &sourceinfo) == 0 ) 0647 infop = &sourceinfo; 0648 0649 #if HAVE_GETPWUID 0650 me = getpwuid(infop ? infop->st_uid : getuid()); 0651 0652 if ( (root = strdup(me->pw_dir)) == 0 ) 0653 fail("out of memory"); 0654 #endif 0655 0656 if ( !mkd_compile(doc, flags) ) 0657 fail("couldn't compile input"); 0658 0659 if ( tmplfile ) 0660 spin(tmplfile,doc,stdout); 0661 else 0662 mkd_generatehtml(doc, stdout); 0663 0664 mkd_cleanup(doc); 0665 exit(0); 0666 }