library.c (5485B)
/* $Id$ */ /* * Copyright (c) 2017--2021 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #if HAVE_SYS_QUEUE # include <sys/queue.h> #endif #include <assert.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include "lowdown.h" #include "extern.h" /* * Starting size for input and output buffers. */ #define HBUF_START_BIG 4096 /* * Starting size for metadata buffers. */ #define HBUF_START_SMALL 128 /* * Return FALSE on failure, TRUE on success. */ static int lowdown_render(const struct lowdown_opts *opts, struct lowdown_buf *ob, const struct lowdown_node *n) { void *rndr; int c = 0; switch (opts == NULL ? LOWDOWN_HTML : opts->type) { case LOWDOWN_GEMINI: if ((rndr = lowdown_gemini_new(opts)) == NULL) return 0; c = lowdown_gemini_rndr(ob, rndr, n); lowdown_gemini_free(rndr); break; case LOWDOWN_HTML: if ((rndr = lowdown_html_new(opts)) == NULL) return 0; c = lowdown_html_rndr(ob, rndr, n); lowdown_html_free(rndr); break; case LOWDOWN_LATEX: if ((rndr = lowdown_latex_new(opts)) == NULL) return 0; c = lowdown_latex_rndr(ob, rndr, n); lowdown_latex_free(rndr); break; case LOWDOWN_MAN: case LOWDOWN_NROFF: if ((rndr = lowdown_nroff_new(opts)) == NULL) return 0; c = lowdown_nroff_rndr(ob, rndr, n); lowdown_nroff_free(rndr); break; case LOWDOWN_FODT: if ((rndr = lowdown_odt_new(opts)) == NULL) return 0; c = lowdown_odt_rndr(ob, rndr, n); lowdown_odt_free(rndr); break; case LOWDOWN_TERM: if ((rndr = lowdown_term_new(opts)) == NULL) return 0; c = lowdown_term_rndr(ob, rndr, n); lowdown_term_free(rndr); break; case LOWDOWN_TREE: c = lowdown_tree_rndr(ob, n); break; default: c = 1; break; } return c; } int lowdown_buf(const struct lowdown_opts *opts, const char *data, size_t datasz, char **res, size_t *rsz, struct lowdown_metaq *metaq) { struct lowdown_buf *ob = NULL; struct lowdown_doc *doc; size_t maxn; enum lowdown_type t; struct lowdown_node *n = NULL; int rc = 0; t = opts == NULL ? LOWDOWN_HTML : opts->type; if ((doc = lowdown_doc_new(opts)) == NULL) goto err; n = lowdown_doc_parse(doc, &maxn, data, datasz, metaq); if (n == NULL) goto err; assert(n->type == LOWDOWN_ROOT); if (opts != NULL && (opts->oflags & LOWDOWN_SMARTY)) if (!smarty(n, maxn, t)) goto err; if ((ob = lowdown_buf_new(HBUF_START_BIG)) == NULL) goto err; if (!lowdown_render(opts, ob, n)) goto err; *res = ob->data; *rsz = ob->size; ob->data = NULL; rc = 1; err: lowdown_buf_free(ob); lowdown_node_free(n); lowdown_doc_free(doc); return rc; } int lowdown_buf_diff(const struct lowdown_opts *opts, const char *new, size_t newsz, const char *old, size_t oldsz, char **res, size_t *rsz) { struct lowdown_buf *ob = NULL; struct lowdown_doc *doc = NULL; enum lowdown_type t; struct lowdown_node *nnew = NULL, *nold = NULL, *ndiff = NULL; size_t maxn; int rc = 0; t = opts == NULL ? LOWDOWN_HTML : opts->type; if ((doc = lowdown_doc_new(opts)) == NULL) goto err; nnew = lowdown_doc_parse(doc, NULL, new, newsz, NULL); if (nnew == NULL) goto err; nold = lowdown_doc_parse(doc, NULL, old, oldsz, NULL); if (nold == NULL) goto err; ndiff = lowdown_diff(nold, nnew, &maxn); if (opts != NULL && (opts->oflags & LOWDOWN_SMARTY)) if (!smarty(ndiff, maxn, t)) goto err; if ((ob = lowdown_buf_new(HBUF_START_BIG)) == NULL) goto err; if (!lowdown_render(opts, ob, ndiff)) goto err; *res = ob->data; *rsz = ob->size; ob->data = NULL; rc = 1; err: lowdown_buf_free(ob); lowdown_node_free(ndiff); lowdown_node_free(nnew); lowdown_node_free(nold); lowdown_doc_free(doc); return rc; } int lowdown_file(const struct lowdown_opts *opts, FILE *fin, char **res, size_t *rsz, struct lowdown_metaq *metaq) { struct lowdown_buf *bin = NULL; int rc = 0; if ((bin = lowdown_buf_new(HBUF_START_BIG)) == NULL) goto out; if (!hbuf_putf(bin, fin)) goto out; if (!lowdown_buf(opts, bin->data, bin->size, res, rsz, metaq)) goto out; rc = 1; out: lowdown_buf_free(bin); return rc; } int lowdown_file_diff(const struct lowdown_opts *opts, FILE *fnew, FILE *fold, char **res, size_t *rsz) { struct lowdown_buf *bnew = NULL, *bold = NULL; int rc = 0; if ((bnew = lowdown_buf_new(HBUF_START_BIG)) == NULL) goto out; if ((bold = lowdown_buf_new(HBUF_START_BIG)) == NULL) goto out; if (!hbuf_putf(bold, fold)) goto out; if (!hbuf_putf(bnew, fnew)) goto out; if (!lowdown_buf_diff(opts, bnew->data, bnew->size, bold->data, bold->size, res, rsz)) goto out; rc = 1; out: lowdown_buf_free(bnew); lowdown_buf_free(bold); return rc; }