summaryrefslogtreecommitdiff
path: root/src/ms-buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ms-buffer.c')
-rw-r--r--src/ms-buffer.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/ms-buffer.c b/src/ms-buffer.c
new file mode 100644
index 0000000..5bf49f5
--- /dev/null
+++ b/src/ms-buffer.c
@@ -0,0 +1,163 @@
+/* CVS client logging buffer.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "cvs.h"
+#include "buffer.h"
+#include "ms-buffer.h"
+
+#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
+#ifdef PROXY_SUPPORT
+
+/* This structure is the closure field of a multi-source buffer. */
+struct ms_buffer
+{
+ /* Our buffer struct. */
+ struct buffer *buf;
+
+ /* The underlying buffers. */
+ struct buffer *cur;
+ List *bufs;
+
+ /* Whether we are in blocking mode or not. */
+ bool block;
+};
+
+
+
+/* The block function for a multi-source buffer. */
+static int
+ms_buffer_block (void *closure, bool block)
+{
+ struct ms_buffer *mb = closure;
+
+ mb->block = block;
+ if (block)
+ return set_block (mb->cur);
+ else
+ return set_nonblock (mb->cur);
+}
+
+
+
+/* The input function for a log buffer. */
+static int
+ms_buffer_input (void *closure, char *data, size_t need, size_t size,
+ size_t *got)
+{
+ struct ms_buffer *mb = closure;
+ int status;
+
+ assert (mb->cur->input);
+ status = (*mb->cur->input) (mb->cur->closure, data, need, size, got);
+ if (status == -1)
+ {
+ Node *p;
+ /* EOF. Set up the next buffer in line but return success and no
+ * data since our caller may have selected on the target to find
+ * ready data before calling us.
+ *
+ * If there are no more buffers, return EOF.
+ */
+ if (list_isempty (mb->bufs)) return -1;
+ buf_shutdown (mb->cur);
+ buf_free (mb->cur);
+ p = mb->bufs->list->next;
+ mb->cur = p->data;
+ p->delproc = NULL;
+ p->data = NULL;
+ delnode (p);
+ if (!buf_empty_p (mb->cur)) buf_append_buffer (mb->buf, mb->cur);
+ ms_buffer_block (closure, mb->block);
+ *got = 0;
+ status = 0;
+ }
+
+ return status;
+}
+
+
+
+/* Return the file descriptor underlying any child buffers. */
+static int
+ms_buffer_get_fd (void *closure)
+{
+ struct ms_buffer *mb = closure;
+ return buf_get_fd (mb->cur);
+}
+
+
+
+/* The shutdown function for a multi-source buffer. */
+static int
+ms_buffer_shutdown (struct buffer *buf)
+{
+ struct ms_buffer *mb = buf->closure;
+ Node *p;
+ int err = 0;
+
+ assert (mb->cur);
+ err += buf_shutdown (mb->cur);
+ buf_free (mb->cur);
+ for (p = mb->bufs->list->next; p != mb->bufs->list; p = p->next)
+ {
+ assert (p);
+ err += buf_shutdown (p->data);
+ }
+
+ dellist (&mb->bufs);
+ return err;
+}
+
+
+
+static void
+delbuflist (Node *p)
+{
+ if (p->data)
+ buf_free (p->data);
+}
+
+
+
+/* Create a multi-source buffer. This could easily be generalized to support
+ * any number of source buffers, but for now only two are necessary.
+ */
+struct buffer *
+ms_buffer_initialize (void (*memory) (struct buffer *),
+ struct buffer *buf, struct buffer *buf2/*, ...*/)
+{
+ struct ms_buffer *mb = xmalloc (sizeof *mb);
+ struct buffer *retbuf;
+ Node *p;
+
+ mb->block = false;
+ mb->cur = buf;
+ set_nonblock (buf);
+ mb->bufs = getlist ();
+ p = getnode ();
+ p->data = buf2;
+ p->delproc = delbuflist;
+ addnode (mb->bufs, p);
+ retbuf = buf_initialize (ms_buffer_input, NULL, NULL,
+ ms_buffer_block, ms_buffer_get_fd,
+ ms_buffer_shutdown, memory, mb);
+ if (!buf_empty_p (buf)) buf_append_buffer (retbuf, buf);
+ mb->buf = retbuf;
+
+ return retbuf;
+}
+#endif /* PROXY_SUPPORT */
+#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */