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) */ 164