xref: /netbsd-src/external/gpl2/xcvs/dist/src/ms-buffer.c (revision 5a6c14c844c4c665da5632061aebde7bb2cb5766)
1 /* CVS client logging buffer.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12 #include <sys/cdefs.h>
13 __RCSID("$NetBSD: ms-buffer.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
14 
15 #include <config.h>
16 
17 #include <stdio.h>
18 
19 #include "cvs.h"
20 #include "buffer.h"
21 #include "ms-buffer.h"
22 
23 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
24 #ifdef PROXY_SUPPORT
25 
26 /* This structure is the closure field of a multi-source buffer.  */
27 struct ms_buffer
28 {
29     /* Our buffer struct.  */
30     struct buffer *buf;
31 
32     /* The underlying buffers.  */
33     struct buffer *cur;
34     List *bufs;
35 
36     /* Whether we are in blocking mode or not.  */
37     bool block;
38 };
39 
40 
41 
42 /* The block function for a multi-source buffer.  */
43 static int
ms_buffer_block(void * closure,bool block)44 ms_buffer_block (void *closure, bool block)
45 {
46     struct ms_buffer *mb = closure;
47 
48     mb->block = block;
49     if (block)
50 	return set_block (mb->cur);
51     else
52 	return set_nonblock (mb->cur);
53 }
54 
55 
56 
57 /* The input function for a log buffer.  */
58 static int
ms_buffer_input(void * closure,char * data,size_t need,size_t size,size_t * got)59 ms_buffer_input (void *closure, char *data, size_t need, size_t size,
60 		 size_t *got)
61 {
62     struct ms_buffer *mb = closure;
63     int status;
64 
65     assert (mb->cur->input);
66     status = (*mb->cur->input) (mb->cur->closure, data, need, size, got);
67     if (status == -1)
68     {
69 	Node *p;
70 	/* EOF.  Set up the next buffer in line but return success and no
71 	 * data since our caller may have selected on the target to find
72 	 * ready data before calling us.
73 	 *
74 	 * If there are no more buffers, return EOF.
75 	 */
76 	if (list_isempty (mb->bufs)) return -1;
77 	buf_shutdown (mb->cur);
78 	buf_free (mb->cur);
79 	p = mb->bufs->list->next;
80 	mb->cur = p->data;
81 	p->delproc = NULL;
82 	p->data = NULL;
83 	delnode (p);
84 	if (!buf_empty_p (mb->cur)) buf_append_buffer (mb->buf, mb->cur);
85 	ms_buffer_block (closure, mb->block);
86 	*got = 0;
87 	status = 0;
88     }
89 
90     return status;
91 }
92 
93 
94 
95 /* Return the file descriptor underlying any child buffers.  */
96 static int
ms_buffer_get_fd(void * closure)97 ms_buffer_get_fd (void *closure)
98 {
99     struct ms_buffer *mb = closure;
100     return buf_get_fd (mb->cur);
101 }
102 
103 
104 
105 /* The shutdown function for a multi-source buffer.  */
106 static int
ms_buffer_shutdown(struct buffer * buf)107 ms_buffer_shutdown (struct buffer *buf)
108 {
109     struct ms_buffer *mb = buf->closure;
110     Node *p;
111     int err = 0;
112 
113     assert (mb->cur);
114     err += buf_shutdown (mb->cur);
115     buf_free (mb->cur);
116     for (p = mb->bufs->list->next; p != mb->bufs->list; p = p->next)
117     {
118 	assert (p);
119 	err += buf_shutdown (p->data);
120     }
121 
122     dellist (&mb->bufs);
123     return err;
124 }
125 
126 
127 
128 static void
delbuflist(Node * p)129 delbuflist (Node *p)
130 {
131     if (p->data)
132 	buf_free (p->data);
133 }
134 
135 
136 
137 /* Create a multi-source buffer.  This could easily be generalized to support
138  * any number of source buffers, but for now only two are necessary.
139  */
140 struct buffer *
ms_buffer_initialize(void (* memory)(struct buffer *),struct buffer * buf,struct buffer * buf2)141 ms_buffer_initialize (void (*memory) (struct buffer *),
142 		      struct buffer *buf, struct buffer *buf2/*, ...*/)
143 {
144     struct ms_buffer *mb = xmalloc (sizeof *mb);
145     struct buffer *retbuf;
146     Node *p;
147 
148     mb->block = false;
149     mb->cur = buf;
150     set_nonblock (buf);
151     mb->bufs = getlist ();
152     p = getnode ();
153     p->data = buf2;
154     p->delproc = delbuflist;
155     addnode (mb->bufs, p);
156     retbuf = buf_initialize (ms_buffer_input, NULL, NULL,
157 			     ms_buffer_block, ms_buffer_get_fd,
158 			     ms_buffer_shutdown, memory, mb);
159     if (!buf_empty_p (buf)) buf_append_buffer (retbuf, buf);
160     mb->buf = retbuf;
161 
162     return retbuf;
163 }
164 #endif /* PROXY_SUPPORT */
165 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
166