home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
cvs-1.8.7-src.tgz
/
tar.out
/
fsf
/
cvs
/
src
/
buffer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
26KB
|
1,295 lines
/* Code for the buffer data structure. */
#include <assert.h>
#include "cvs.h"
#include "buffer.h"
#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
/* OS/2 doesn't have EIO. FIXME: this whole notion of turning
a different error into EIO strikes me as pretty dubious. */
#if !defined (EIO)
#define EIO EBADPOS
#endif
/* Linked list of available buffer_data structures. */
static struct buffer_data *free_buffer_data;
/* Local functions. */
static void allocate_buffer_datas PROTO((void));
static struct buffer_data *get_buffer_data PROTO((void));
/* Initialize a buffer structure. */
struct buffer *
buf_initialize (input, output, flush, block, shutdown, memory, closure)
int (*input) PROTO((void *, char *, int, int, int *));
int (*output) PROTO((void *, const char *, int, int *));
int (*flush) PROTO((void *));
int (*block) PROTO((void *, int));
int (*shutdown) PROTO((void *));
void (*memory) PROTO((struct buffer *));
void *closure;
{
struct buffer *buf;
buf = (struct buffer *) xmalloc (sizeof (struct buffer));
buf->data = NULL;
buf->last = NULL;
buf->nonblocking = 0;
buf->input = input;
buf->output = output;
buf->flush = flush;
buf->block = block;
buf->shutdown = shutdown;
buf->memory_error = memory;
buf->closure = closure;
return buf;
}
/* Initialize a buffer structure which is not to be used for I/O. */
struct buffer *
buf_nonio_initialize (memory)
void (*memory) PROTO((struct buffer *));
{
return (buf_initialize
((int (*) PROTO((void *, char *, int, int, int *))) NULL,
(int (*) PROTO((void *, const char *, int, int *))) NULL,
(int (*) PROTO((void *))) NULL,
(int (*) PROTO((void *, int))) NULL,
(int (*) PROTO((void *))) NULL,
memory,
(void *) NULL));
}
/* Allocate more buffer_data structures. */
static void
allocate_buffer_datas ()
{
struct buffer_data *alc;
char *space;
int i;
/* Allocate buffer_data structures in blocks of 16. */
#define ALLOC_COUNT (16)
alc = ((struct buffer_data *)
malloc (ALLOC_COUNT * sizeof (struct buffer_data)));
space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE);
if (alc == NULL || space == NULL)
return;
for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE)
{
alc->next = free_buffer_data;
free_buffer_data = alc;
alc->text = space;
}
}
/* Get a new buffer_data structure. */
static struct buffer_data *
get_buffer_data ()
{
struct buffer_data *ret;
if (free_buffer_data == NULL)
{
allocate_buffer_datas ();
if (free_buffer_data == NULL)
return NULL;
}
ret = free_buffer_data;
free_buffer_data = ret->next;
return ret;
}
/* See whether a buffer is empty. */
int
buf_empty_p (buf)
struct buffer *buf;
{
struct buffer_data *data;
for (data = buf->data; data != NULL; data = data->next)
if (data->size > 0)
return 0;
return 1;
}
#ifdef SERVER_FLOWCONTROL
/*
* Count how much data is stored in the buffer..
* Note that each buffer is a malloc'ed chunk BUFFER_DATA_SIZE.
*/
int
buf_count_mem (buf)
struct buffer *buf;
{
struct buffer_data *data;
int mem = 0;
for (data = buf->data; data != NULL; data = data->next)
mem += BUFFER_DATA_SIZE;
return mem;
}
#endif /* SERVER_FLOWCONTROL */
/* Add data DATA of length LEN to BUF. */
void
buf_output (buf, data, len)
struct buffer *buf;
const char *data;
int len;
{
if (buf->data != NULL
&& (((buf->last->text + BUFFER_DATA_SIZE)
- (buf->last->bufp + buf->last->size))
>= len))
{
memcpy (buf->last->bufp + buf->last->size, data, len);
buf->last->size += len;
return;
}
while (1)
{
struct buffer_data *newdata;
newdata = get_buffer_data ();
if (newdata == NULL)
{
(*buf->memory_error) (buf);
return;
}
if (buf->data == NULL)
buf->data = newdata;
else
buf->last->next = newdata;
newdata->next = NULL;
buf->last = newdata;
newdata->bufp = newdata->text;
if (len <= BUFFER_DATA_SIZE)
{
newdata->size = len;
memcpy (newdata->text, data, len);
return;
}
newdata->size = BUFFER_DATA_SIZE;
memcpy (newdata->text, data, BUFFER_DATA_SIZE);
data += BUFFER_DATA_SIZE;
len -= BUFFER_DATA_SIZE;
}
/*NOTREACHED*/
}
/* Add a '\0' terminated string to BUF. */
void
buf_output0 (buf, string)
struct buffer *buf;
const char *string;
{
buf_output (buf, string, strlen (string));
}
/* Add a single character to BUF. */
void
buf_append_char (buf, ch)
struct buffer *buf;
int ch;
{
if (buf->data != NULL
&& (buf->last->text + BUFFER_DATA_SIZE
!= buf->last->bufp + buf->last->size))
{
*(buf->last->bufp + buf->last->size) = ch;
++buf->last->size;
}
else
{
char b;
b = ch;
buf_output (buf, &b, 1);
}
}
/*
* Send all the output we've been saving up. Returns 0 for success or
* errno code. If the buffer has been set to be nonblocking, this
* will just write until the write would block.
*/
int
buf_send_output (buf)
struct buffer *buf;
{
if (buf->output == NULL)
abort ();
while (buf->data != NULL)
{
struct buffer_data *data;
data = buf->data;
if (data->size > 0)
{
int status, nbytes;
status = (*buf->output) (buf->closure, data->bufp, data->size,
&nbytes);
if (status != 0)
{
/* Some sort of error. Discard the data, and return. */
buf->last->next = free_buffer_data;
free_buffer_data = buf->data;
buf->data = NULL;
buf->last = NULL;
return status;
}
if (nbytes != data->size)
{
/* Not all the data was written out. This is only
permitted in nonblocking mode. Adjust the buffer,
and return. */
assert (buf->nonblocking);
data->size -= nbytes;
data->bufp += nbytes;
return 0;
}
}
buf->data = data->next;
data->next = free_buffer_data;
free_buffer_data = data;
}
buf->last = NULL;
return 0;
}
/*
* Flush any data queued up in the buffer. If BLOCK is nonzero, then
* if the buffer is in nonblocking mode, put it into blocking mode for
* the duration of the flush. This returns 0 on success, or an error
* code.
*/
int
buf_flush (buf, block)
struct buffer *buf;
int block;
{
int nonblocking;
int status;
if (buf->flush == NULL)
abort ();
nonblocking = buf->nonblocking;
if (nonblocking && block)
{
status = set_block (buf);
if (status != 0)
return status;
}
status = buf_send_output (buf);
if (status == 0)
status = (*buf->flush) (buf->closure);
if (nonblocking && block)
{
int blockstat;
blockstat = set_nonblock (buf);
if (status == 0)
status = blockstat;
}
return status;
}
/*
* Set buffer BUF to nonblocking I/O. Returns 0 for success or errno
* code.
*/
int
set_nonblock (buf)
struct buffer *buf;
{
int status;
if (buf->nonblocking)
return 0;
if (buf->block == NULL)
abort ();
status = (*buf->block) (buf->closure, 0);
if (status != 0)
return status;
buf->nonblocking = 1;
return 0;
}
/*
* Set buffer BUF to blocking I/O. Returns 0 for success or errno
* code.
*/
int
set_block (buf)
struct buffer *buf;
{
int status;
if (! buf->nonblocking)
return 0;
if (buf->block == NULL)
abort ();
status = (*buf->block) (buf->closure, 1);
if (status != 0)
return status;
buf->nonblocking = 0;
return 0;
}
/*
* Send a character count and some output. Returns errno code or 0 for
* success.
*
* Sending the count in binary is OK since this is only used on a pipe
* within the same system.
*/
int
buf_send_counted (buf)
struct buffer *buf;
{
int size;
struct buffer_data *data;
size = 0;
for (data = buf->data; data != NULL; data = data->next)
size += data->size;
data = get_buffer_data ();
if (data == NULL)
{
(*buf->memory_error) (buf);
return ENOMEM;
}
data->next = buf->data;
buf->data = data;
if (buf->last == NULL)
buf->last = data;
data->bufp = data->text;
data->size = sizeof (int);
*((int *) data->text) = size;
return buf_send_output (buf);
}
/*
* Send a special count. COUNT should be negative. It will be
* handled speciallyi by buf_copy_counted. This function returns 0 or
* an errno code.
*
* Sending the count in binary is OK since this is only used on a pipe
* within the same system.
*/
int
buf_send_special_count (buf, count)
struct buffer *buf;
int count;
{
struct buffer_data *data;
data = get_buffer_data ();
if (data == NULL)
{
(*buf->memory_error) (buf);
return ENOMEM;
}
data->next = buf->data;
buf->data = data;
if (buf->last == NULL)
buf->last = data;
data->bufp = data->text;
data->size = sizeof (int);
*((int *) data->text) = count;
return buf_send_output (buf);
}
/* Append a list of buffer_data structures to an buffer. */
void
buf_append_data (buf, data, last)
struct buffer *buf;
struct buffer_data *data;
struct buffer_data *last;
{
if (data != NULL)
{
if (buf->data == NULL)
buf->data = data;
else
buf->last->next = data;
buf->last = last;
}
}
/*
* Copy the contents of file F into buffer_data structures. We can't
* copy directly into an buffer, because we want to handle failure and
* succeess differently. Returns 0 on success, or -2 if out of
* memory, or a status code on error. Since the caller happens to
* know the size of the file, it is passed in as SIZE. On success,
* this function sets *RETP and *LASTP, which may be passed to
* buf_append_data.
*/
int
buf_read_file (f, size, retp, lastp)
FILE *f;
long size;
struct buffer_data **retp;
struct buffer_data **lastp;
{
int status;
*retp = NULL;
*lastp = NULL;
while (size > 0)
{
struct buffer_data *data;
int get;
data = get_buffer_data ();
if (data == NULL)
{
status = -2;
goto error_return;
}
if (*retp == NULL)
*retp = data;
else
(*lastp)->next = data;
data->next = NULL;
*lastp = data;
data->bufp = data->text;
data->size = 0;
if (size > BUFFER_DATA_SIZE)
get = BUFFER_DATA_SIZE;
else
get = size;
errno = EIO;
if (fread (data->text, get, 1, f) != 1)
{
status = errno;
goto error_return;
}
data->size += get;
size -= get;
}
return 0;
error_return:
if (*retp != NULL)
{
(*lastp)->next = free_buffer_data;
free_buffer_data = *retp;
}
return status;
}
/*
* Copy the contents of file F into buffer_data structures. We can't
* copy directly into an buffer, because we want to handle failure and
* succeess differently. Returns 0 on success, or -2 if out of
* memory, or a status code on error. On success, this function sets
* *RETP and *LASTP, which may be passed to buf_append_data.
*/
int
buf_read_file_to_eof (f, retp, lastp)
FILE *f;
struct buffer_data **retp;
struct buffer_data **lastp;
{
int status;
*retp = NULL;
*lastp = NULL;
while (!feof (f))
{
struct buffer_data *data;
int get, nread;
data = get_buffer_data ();
if (data == NULL)
{
status = -2;
goto error_return;
}
if (*retp == NULL)
*retp = data;
else
(*lastp)->next = data;
data->next = NULL;
*lastp = data;
data->bufp = data->text;
data->size = 0;
get = BUFFER_DATA_SIZE;
errno = EIO;
nread = fread (data->text, 1, get, f);
if (nread == 0 && !feof (f))
{
status = errno;
goto error_return;
}
data->size = nread;
}
return 0;
error_return:
if (*retp != NULL)
{
(*lastp)->next = free_buffer_data;
free_buffer_data = *retp;
}
return status;
}
/* Return the number of bytes in a chain of buffer_data structures. */
int
buf_chain_length (buf)
struct buffer_data *buf;
{
int size = 0;
while (buf)
{
size += buf->size;
buf = buf->next;
}
return size;
}
/*
* Read an arbitrary amount of data into an input buffer. The buffer
* will be in nonblocking mode, and we just grab what we can. Return
* 0 on success, or -1 on end of file, or -2 if out of memory, or an
* error code. If COUNTP is not NULL, *COUNTP is set to the number of
* bytes read.
*/
int
buf_input_data (buf, countp)
struct buffer *buf;
int *countp;
{
if (buf->input == NULL)
abort ();
if (countp != NULL)
*countp = 0;
while (1)
{
int get;
int status, nbytes;
if (buf->data == NULL
|| (buf->last->bufp + buf->last->size
== buf->last->text + BUFFER_DATA_SIZE))
{
struct buffer_data *data;
data = get_buffer_data ();
if (data == NULL)
{
(*buf->memory_error) (buf);
return -2;
}
if (buf->data == NULL)
buf->data = data;
else
buf->last->next = data;
data->next = NULL;
buf->last = data;
data->bufp = data->text;
data->size = 0;
}
get = ((buf->last->text + BUFFER_DATA_SIZE)
- (buf->last->bufp + buf->last->size));
status = (*buf->input) (buf->closure,
buf->last->bufp + buf->last->size,
0, get, &nbytes);
if (status != 0)
return status;
buf->last->size += nbytes;
if (countp != NULL)
*countp += nbytes;
if (nbytes < get)
{
/* If we did not fill the buffer, then presumably we read
all the available data. */
return 0;
}
}
/*NOTREACHED*/
}
/*
* Read a line (characters up to a \012) from an input buffer. (We
* use \012 rather than \n for the benefit of non Unix clients for
* which \n means something else). This returns 0 on success, or -1
* on end of file, or -2 if out of memory, or an error code. If it
* succeeds, it sets *LINE to an allocated buffer holding the contents
* of the line. The trailing \012 is not included in the buffer. If
* LENP is not NULL, then *LENP is set to the number of bytes read;
* strlen may not work, because there may be embedded null bytes.
*/
int
buf_read_line (buf, line, lenp)
struct buffer *buf;
char **line;
int *lenp;
{
if (buf->input == NULL)
abort ();
*line = NULL;
while (1)
{
int len, finallen;
struct buffer_data *data;
char *nl;
/* See if there is a newline in BUF. */
len = 0;
for (data = buf->data; data != NULL; data = data->next)
{
nl = memchr (data->bufp, '\012', data->size);
if (nl != NULL)
{
finallen = nl - data->bufp;
len += finallen;
break;
}
len += data->size;
}
/* If we found a newline, copy the line into a memory buffer,
and remove it from BUF. */
if (data != NULL)
{
char *p;
struct buffer_data *nldata;
p = malloc (len + 1);
if (p == NULL)
return -2;
*line = p;
nldata = data;
data = buf->data;
while (data != nldata)
{
struct buffer_data *next;
memcpy (p, data->bufp, data->size);
p += data->size;
next = data->next;
data->next = free_buffer_data;
free_buffer_data = data;
data = next;
}
memcpy (p, data->bufp, finallen);
p[finallen] = '\0';
data->size -= finallen + 1;
data->bufp = nl + 1;
buf->data = data;
if (lenp != NULL)
*lenp = len;
return 0;
}
/* Read more data until we get a newline. */
while (1)
{
int size, status, nbytes;
char *mem;
if (buf->data == NULL
|| (buf->last->bufp + buf->last->size
== buf->last->text + BUFFER_DATA_SIZE))
{
data = get_buffer_data ();
if (data == NULL)
{
(*buf->memory_error) (buf);
return -2;
}
if (buf->data == NULL)
buf->data = data;
else
buf->last->next = data;
data->next = NULL;
buf->last = data;
data->bufp = data->text;
data->size = 0;
}
mem = buf->last->bufp + buf->last->size;
size = (buf->last->text + BUFFER_DATA_SIZE) - mem;
/* We need to read at least 1 byte. We can handle up to
SIZE bytes. This will only be efficient if the
underlying communication stream does its own buffering,
or is clever about getting more than 1 byte at a time. */
status = (*buf->input) (buf->closure, mem, 1, size, &nbytes);
if (status != 0)
return status;
buf->last->size += nbytes;
/* Optimize slightly to avoid an unnecessary call to
memchr. */
if (nbytes == 1)
{
if (*mem == '\012')
break;
}
else
{
if (memchr (mem, '\012', nbytes) != NULL)
break;
}
}
}
}
/*
* Extract data from the input buffer BUF. This will read up to WANT
* bytes from the buffer. It will set *RETDATA to point at the bytes,
* and set *GOT to the number of bytes to be found there. Any buffer
* call which uses BUF may change the contents of the buffer at *DATA,
* so the data should be fully processed before any further calls are
* made. This returns 0 on success, or -1 on end of file, or -2 if
* out of memory, or an error code.
*/
int
buf_read_data (buf, want, retdata, got)
struct buffer *buf;
int want;
char **retdata;
int *got;
{
if (buf->input == NULL)
abort ();
while (buf->data != NULL && buf->data->size == 0)
{
struct buffer_data *next;
next = buf->data->next;
buf->data->next = free_buffer_data;
free_buffer_data = buf->data;
buf->data = next;
if (next == NULL)
buf->last = NULL;
}
if (buf->data == NULL)
{
struct buffer_data *data;
int get, status, nbytes;
data = get_buffer_data ();
if (data == NULL)
{
(*buf->memory_error) (buf);
return -2;
}
buf->data = data;
buf->last = data;
data->next = NULL;
data->bufp = data->text;
data->size = 0;
if (want < BUFFER_DATA_SIZE)
get = want;
else
get = BUFFER_DATA_SIZE;
status = (*buf->input) (buf->closure, data->bufp, get,
BUFFER_DATA_SIZE, &nbytes);
if (status != 0)
return status;
data->size = nbytes;
}
*retdata = buf->data->bufp;
if (want < buf->data->size)
{
*got = want;
buf->data->size -= want;
buf->data->bufp += want;
}
else
{
*got = buf->data->size;
buf->data->size = 0;
}
return 0;
}
/*
* Copy lines from an input buffer to an output buffer. This copies
* all complete lines (characters up to a newline) from INBUF to
* OUTBUF. Each line in OUTBUF is preceded by the character COMMAND
* and a space.
*/
void
buf_copy_lines (outbuf, inbuf, command)
struct buffer *outbuf;
struct buffer *inbuf;
int command;
{
while (1)
{
struct buffer_data *data;
struct buffer_data *nldata;
char *nl;
int len;
/* See if there is a newline in INBUF. */
nldata = NULL;
nl = NULL;
for (data = inbuf->data; data != NULL; data = data->next)
{
nl = memchr (data->bufp, '\n', data->size);
if (nl != NULL)
{
nldata = data;
break;
}
}
if (nldata == NULL)
{
/* There are no more lines in INBUF. */
return;
}
/* Put in the command. */
buf_append_char (outbuf, command);
buf_append_char (outbuf, ' ');
if (inbuf->data != nldata)
{
/*
* Simply move over all the buffers up to the one containing
* the newline.
*/
for (data = inbuf->data; data->next != nldata; data = data->next)
;
data->next = NULL;
buf_append_data (outbuf, inbuf->data, data);
inbuf->data = nldata;
}
/*
* If the newline is at the very end of the buffer, just move
* the buffer onto OUTBUF. Otherwise we must copy the data.
*/
len = nl + 1 - nldata->bufp;
if (len == nldata->size)
{
inbuf->data = nldata->next;
if (inbuf->data == NULL)
inbuf->last = NULL;
nldata->next = NULL;
buf_append_data (outbuf, nldata, nldata);
}
else
{
buf_output (outbuf, nldata->bufp, len);
nldata->bufp += len;
nldata->size -= len;
}
}
}
/*
* Copy counted data from one buffer to another. The count is an
* integer, host size, host byte order (it is only used across a
* pipe). If there is enough data, it should be moved over. If there
* is not enough data, it should remain on the original buffer. A
* negative count is a special case. if one is seen, *SPECIAL is set
* to the (negative) count value and no additional data is gathered
* from the buffer; normally *SPECIAL is set to 0. This function
* returns the number of bytes it needs to see in order to actually
* copy something over.
*/
int
buf_copy_counted (outbuf, inbuf, special)
struct buffer *outbuf;
struct buffer *inbuf;
int *special;
{
*special = 0;
while (1)
{
struct buffer_data *data;
int need;
union
{
char intbuf[sizeof (int)];
int i;
} u;
char *intp;
int count;
struct buffer_data *start;
int startoff;
struct buffer_data *stop;
int stopwant;
/* See if we have enough bytes to figure out the count. */
need = sizeof (int);
intp = u.intbuf;
for (data = inbuf->data; data != NULL; data = data->next)
{
if (data->size >= need)
{
memcpy (intp, data->bufp, need);
break;
}
memcpy (intp, data->bufp, data->size);
intp += data->size;
need -= data->size;
}
if (data == NULL)
{
/* We don't have enough bytes to form an integer. */
return need;
}
count = u.i;
start = data;
startoff = need;
if (count < 0)
{
/* A negative COUNT is a special case meaning that we
don't need any further information. */
stop = start;
stopwant = 0;
}
else
{
/*
* We have an integer in COUNT. We have gotten all the
* data from INBUF in all buffers before START, and we
* have gotten STARTOFF bytes from START. See if we have
* enough bytes remaining in INBUF.
*/
need = count - (start->size - startoff);
if (need <= 0)
{
stop = start;
stopwant = count;
}
else
{
for (data = start->next; data != NULL; data = data->next)
{
if (need <= data->size)
break;
need -= data->size;
}
if (data == NULL)
{
/* We don't have enough bytes. */
return need;
}
stop = data;
stopwant = need;
}
}
/*
* We have enough bytes. Free any buffers in INBUF before
* START, and remove STARTOFF bytes from START, so that we can
* forget about STARTOFF.
*/
start->bufp += startoff;
start->size -= startoff;
if (start->size == 0)
start = start->next;
if (stop->size == stopwant)
{
stop = stop->next;
stopwant = 0;
}
while (inbuf->data != start)
{
data = inbuf->data;
inbuf->data = data->next;
data->next = free_buffer_data;
free_buffer_data = data;
}
/* If COUNT is negative, set *SPECIAL and get out now. */
if (count < 0)
{
*special = count;
return 0;
}
/*
* We want to copy over the bytes from START through STOP. We
* only want STOPWANT bytes from STOP.
*/
if (start != stop)
{
/* Attach the buffers from START through STOP to OUTBUF. */
for (data = start; data->next != stop; data = data->next)
;
inbuf->data = stop;
data->next = NULL;
buf_append_data (outbuf, start, data);
}
if (stopwant > 0)
{
buf_output (outbuf, stop->bufp, stopwant);
stop->bufp += stopwant;
stop->size -= stopwant;
}
}
/*NOTREACHED*/
}
/* Shut down a buffer. This returns 0 on success, or an errno code. */
int
buf_shutdown (buf)
struct buffer *buf;
{
if (buf->shutdown)
return (*buf->shutdown) (buf->closure);
return 0;
}
/* The simplest type of buffer is one built on top of a stdio FILE.
For simplicity, and because it is all that is required, we do not
implement setting this type of buffer into nonblocking mode. The
closure field is just a FILE *. */
static int stdio_buffer_input PROTO((void *, char *, int, int, int *));
static int stdio_buffer_output PROTO((void *, const char *, int, int *));
static int stdio_buffer_flush PROTO((void *));
/* Initialize a buffer built on a stdio FILE. */
struct buffer
*stdio_buffer_initialize (fp, input, memory)
FILE *fp;
int input;
void (*memory) PROTO((struct buffer *));
{
return buf_initialize (input ? stdio_buffer_input : NULL,
input ? NULL : stdio_buffer_output,
input ? NULL : stdio_buffer_flush,
(int (*) PROTO((void *, int))) NULL,
(int (*) PROTO((void *))) NULL,
memory,
(void *) fp);
}
/* The buffer input function for a buffer built on a stdio FILE. */
static int
stdio_buffer_input (closure, data, need, size, got)
void *closure;
char *data;
int need;
int size;
int *got;
{
FILE *fp = (FILE *) closure;
int nbytes;
/* Since stdio does its own buffering, we don't worry about
getting more bytes than we need. */
if (need == 0 || need == 1)
{
int ch;
ch = getc (fp);
if (ch == EOF)
{
if (feof (fp))
return -1;
else if (errno == 0)
return EIO;
else
return errno;
}
*data = ch;
*got = 1;
return 0;
}
nbytes = fread (data, 1, need, fp);
if (nbytes == 0)
{
*got = 0;
if (feof (fp))
return -1;
else if (errno == 0)
return EIO;
else
return errno;
}
*got = nbytes;
return 0;
}
/* The buffer output function for a buffer built on a stdio FILE. */
static int
stdio_buffer_output (closure, data, have, wrote)
void *closure;
const char *data;
int have;
int *wrote;
{
FILE *fp = (FILE *) closure;
*wrote = 0;
while (have > 0)
{
int nbytes;
nbytes = fwrite (data, 1, have, fp);
if (nbytes != have)
{
if (errno == 0)
return EIO;
else
return errno;
}
*wrote += nbytes;
have -= nbytes;
data += nbytes;
}
return 0;
}
/* The buffer flush function for a buffer built on a stdio FILE. */
static int
stdio_buffer_flush (closure)
void *closure;
{
FILE *fp = (FILE *) closure;
if (fflush (fp) != 0)
{
if (errno == 0)
return EIO;
else
return errno;
}
return 0;
}
#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */