drop __RCSID (these are all -kb anyway) and reduce diff to upstream
[alioth/cvs.git] / src / ms-buffer.c
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
13 #include <config.h>
14
15 #include <stdio.h>
16
17 #include "cvs.h"
18 #include "buffer.h"
19 #include "ms-buffer.h"
20
21 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
22 #ifdef PROXY_SUPPORT
23
24 /* This structure is the closure field of a multi-source buffer.  */
25 struct ms_buffer
26 {
27     /* Our buffer struct.  */
28     struct buffer *buf;
29
30     /* The underlying buffers.  */
31     struct buffer *cur;
32     List *bufs;
33
34     /* Whether we are in blocking mode or not.  */
35     bool block;
36 };
37
38
39
40 /* The block function for a multi-source buffer.  */
41 static int
42 ms_buffer_block (void *closure, bool block)
43 {
44     struct ms_buffer *mb = closure;
45
46     mb->block = block;
47     if (block)
48         return set_block (mb->cur);
49     else
50         return set_nonblock (mb->cur);
51 }
52
53
54
55 /* The input function for a log buffer.  */
56 static int
57 ms_buffer_input (void *closure, char *data, size_t need, size_t size,
58                  size_t *got)
59 {
60     struct ms_buffer *mb = closure;
61     int status;
62
63     assert (mb->cur->input);
64     status = (*mb->cur->input) (mb->cur->closure, data, need, size, got);
65     if (status == -1)
66     {
67         Node *p;
68         /* EOF.  Set up the next buffer in line but return success and no
69          * data since our caller may have selected on the target to find
70          * ready data before calling us.
71          *
72          * If there are no more buffers, return EOF.
73          */
74         if (list_isempty (mb->bufs)) return -1;
75         buf_shutdown (mb->cur);
76         buf_free (mb->cur);
77         p = mb->bufs->list->next;
78         mb->cur = p->data;
79         p->delproc = NULL;
80         p->data = NULL;
81         delnode (p);
82         if (!buf_empty_p (mb->cur)) buf_append_buffer (mb->buf, mb->cur);
83         ms_buffer_block (closure, mb->block);
84         *got = 0;
85         status = 0;
86     }
87
88     return status;
89 }
90
91
92
93 /* Return the file descriptor underlying any child buffers.  */
94 static int
95 ms_buffer_get_fd (void *closure)
96 {
97     struct ms_buffer *mb = closure;
98     return buf_get_fd (mb->cur);
99 }
100
101
102
103 /* The shutdown function for a multi-source buffer.  */
104 static int
105 ms_buffer_shutdown (struct buffer *buf)
106 {
107     struct ms_buffer *mb = buf->closure;
108     Node *p;
109     int err = 0;
110
111     assert (mb->cur);
112     err += buf_shutdown (mb->cur);
113     buf_free (mb->cur);
114     for (p = mb->bufs->list->next; p != mb->bufs->list; p = p->next)
115     {
116         assert (p);
117         err += buf_shutdown (p->data);
118     }
119
120     dellist (&mb->bufs);
121     return err;
122 }
123
124
125
126 static void
127 delbuflist (Node *p)
128 {
129     if (p->data)
130         buf_free (p->data);
131 }
132
133
134
135 /* Create a multi-source buffer.  This could easily be generalized to support
136  * any number of source buffers, but for now only two are necessary.
137  */
138 struct buffer *
139 ms_buffer_initialize (void (*memory) (struct buffer *),
140                       struct buffer *buf, struct buffer *buf2/*, ...*/)
141 {
142     struct ms_buffer *mb = xmalloc (sizeof *mb);
143     struct buffer *retbuf;
144     Node *p;
145
146     mb->block = false;
147     mb->cur = buf;
148     set_nonblock (buf);
149     mb->bufs = getlist ();
150     p = getnode ();
151     p->data = buf2;
152     p->delproc = delbuflist;
153     addnode (mb->bufs, p);
154     retbuf = buf_initialize (ms_buffer_input, NULL, NULL,
155                              ms_buffer_block, ms_buffer_get_fd,
156                              ms_buffer_shutdown, memory, mb);
157     if (!buf_empty_p (buf)) buf_append_buffer (retbuf, buf);
158     mb->buf = retbuf;
159
160     return retbuf;
161 }
162 #endif /* PROXY_SUPPORT */
163 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */