summaryrefslogtreecommitdiffstatshomepage
path: root/libmdocml.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmdocml.c')
-rw-r--r--libmdocml.c174
1 files changed, 173 insertions, 1 deletions
diff --git a/libmdocml.c b/libmdocml.c
index 5f1e1e8d..07513496 100644
--- a/libmdocml.c
+++ b/libmdocml.c
@@ -1,4 +1,4 @@
-/* $Id: libmdocml.c,v 1.1 2008/11/22 14:53:29 kristaps Exp $ */
+/* $Id: libmdocml.c,v 1.2 2008/11/22 18:34:06 kristaps Exp $ */
/*
* Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -16,6 +16,178 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+#include <assert.h>
+#include <fcntl.h>
+#include <err.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "libmdocml.h"
+
+#define BUFFER_LINE BUFSIZ
+
+typedef int (*md_line) (struct md_mbuf *, const struct md_rbuf *,
+ const char *, size_t);
+
+static int md_line_dummy(struct md_mbuf *,
+ const struct md_rbuf *,
+ const char *, size_t);
+static ssize_t md_buf_fill(struct md_rbuf *);
+static int md_buf_flush(struct md_mbuf *);
+static int md_buf_putchar(struct md_mbuf *, char);
+static int md_buf_puts(struct md_mbuf *,
+ const char *, size_t);
+
+
+ssize_t
+md_buf_fill(struct md_rbuf *in)
+{
+ ssize_t ssz;
+
+ assert(in);
+ assert(in->buf);
+ assert(in->bufsz > 0);
+ assert(in->name);
+
+ if (-1 == (ssz = read(in->fd, in->buf, in->bufsz)))
+ warn("%s", in->name);
+
+ return(ssz);
+}
+
+
+int
+md_buf_flush(struct md_mbuf *buf)
+{
+ ssize_t sz;
+
+ assert(buf);
+ assert(buf->buf);
+ assert(buf->name);
+
+ if (0 == buf->pos)
+ return(1);
+
+ sz = write(buf->fd, buf->buf, buf->pos);
+
+ if (-1 == sz) {
+ warn("%s", buf->name);
+ return(0);
+ } else if ((size_t)sz != buf->pos) {
+ warnx("%s: short write", buf->name);
+ return(0);
+ }
+
+ buf->pos = 0;
+ return(1);
+}
+
+
+int
+md_buf_putchar(struct md_mbuf *buf, char c)
+{
+ return(md_buf_puts(buf, &c, 1));
+}
+
+
+int
+md_buf_puts(struct md_mbuf *buf, const char *p, size_t sz)
+{
+ size_t ssz;
+
+ assert(p);
+ assert(buf);
+ assert(buf->buf);
+
+ /* LINTED */
+ while (buf->pos + sz > buf->bufsz) {
+ ssz = buf->bufsz - buf->pos;
+ (void)memcpy(/* LINTED */
+ buf->buf + buf->pos, p, ssz);
+ p += (long)ssz;
+ sz -= ssz;
+ buf->pos += ssz;
+
+ if ( ! md_buf_flush(buf))
+ return(0);
+ }
+
+ (void)memcpy(/* LINTED */
+ buf->buf + buf->pos, p, sz);
+ buf->pos += sz;
+ return(1);
+}
+
+
+int
+md_run(enum md_type type, struct md_mbuf *out, struct md_rbuf *in)
+{
+ ssize_t sz, i;
+ char line[BUFFER_LINE];
+ size_t pos;
+ md_line func;
+
+ assert(in);
+ assert(out);
+
+ out->pos = 0;
+ in->line = 1;
+
+ assert(MD_DUMMY == type);
+ func = md_line_dummy;
+
+ /* LINTED */
+ for (pos = 0; ; ) {
+ if (-1 == (sz = md_buf_fill(in)))
+ return(1);
+ else if (0 == sz)
+ break;
+
+ for (i = 0; i < sz; i++) {
+ if ('\n' == in->buf[i]) {
+ if ((*func)(out, in, line, pos))
+ return(1);
+ in->line++;
+ pos = 0;
+ continue;
+ }
+
+ if (pos < BUFFER_LINE) {
+ /* LINTED */
+ line[pos++] = in->buf[i];
+ continue;
+ }
+
+ warnx("%s: line %zu too long",
+ in->name, in->line);
+ return(1);
+ }
+ }
+
+ if (0 != pos && (*func)(out, in, line, pos))
+ return(1);
+
+ return(md_buf_flush(out) ? 0 : 1);
+}
+
+
+static int
+md_line_dummy(struct md_mbuf *out, const struct md_rbuf *in,
+ const char *buf, size_t sz)
+{
+
+ assert(buf);
+ assert(out);
+ assert(in);
+
+ if ( ! md_buf_puts(out, buf, sz))
+ return(1);
+ if ( ! md_buf_putchar(out, '\n'))
+ return(1);
+
+ return(0);
+}
+
+