xref: /openbsd-src/gnu/usr.bin/cvs/src/buffer.c (revision 6afe391b58eb47ada25469fc9401f2b3984c6d37)
150bf276cStholo /* Code for the buffer data structure.  */
250bf276cStholo 
350bf276cStholo #include <assert.h>
450bf276cStholo #include "cvs.h"
550bf276cStholo #include "buffer.h"
650bf276cStholo 
750bf276cStholo #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
850bf276cStholo 
950bf276cStholo /* OS/2 doesn't have EIO.  FIXME: this whole notion of turning
1050bf276cStholo    a different error into EIO strikes me as pretty dubious.  */
1150bf276cStholo #if !defined (EIO)
1250bf276cStholo #define EIO EBADPOS
1350bf276cStholo #endif
1450bf276cStholo 
1550bf276cStholo /* Linked list of available buffer_data structures.  */
1650bf276cStholo static struct buffer_data *free_buffer_data;
1750bf276cStholo 
1850bf276cStholo /* Local functions.  */
195e617892Stholo static void buf_default_memory_error PROTO ((struct buffer *));
2050bf276cStholo static void allocate_buffer_datas PROTO((void));
2150bf276cStholo static struct buffer_data *get_buffer_data PROTO((void));
2250bf276cStholo 
2350bf276cStholo /* Initialize a buffer structure.  */
2450bf276cStholo 
2550bf276cStholo struct buffer *
2650bf276cStholo buf_initialize (input, output, flush, block, shutdown, memory, closure)
2750bf276cStholo      int (*input) PROTO((void *, char *, int, int, int *));
2850bf276cStholo      int (*output) PROTO((void *, const char *, int, int *));
2950bf276cStholo      int (*flush) PROTO((void *));
3050bf276cStholo      int (*block) PROTO((void *, int));
3150bf276cStholo      int (*shutdown) PROTO((void *));
3250bf276cStholo      void (*memory) PROTO((struct buffer *));
3350bf276cStholo      void *closure;
3450bf276cStholo {
3550bf276cStholo     struct buffer *buf;
3650bf276cStholo 
3750bf276cStholo     buf = (struct buffer *) xmalloc (sizeof (struct buffer));
3850bf276cStholo     buf->data = NULL;
3950bf276cStholo     buf->last = NULL;
4050bf276cStholo     buf->nonblocking = 0;
4150bf276cStholo     buf->input = input;
4250bf276cStholo     buf->output = output;
4350bf276cStholo     buf->flush = flush;
4450bf276cStholo     buf->block = block;
4550bf276cStholo     buf->shutdown = shutdown;
465e617892Stholo     buf->memory_error = memory ? memory : buf_default_memory_error;
4750bf276cStholo     buf->closure = closure;
4850bf276cStholo     return buf;
4950bf276cStholo }
5050bf276cStholo 
515e617892Stholo /* Free a buffer structure.  */
525e617892Stholo 
535e617892Stholo void
buf_free(buf)545e617892Stholo buf_free (buf)
555e617892Stholo      struct buffer *buf;
565e617892Stholo {
575e617892Stholo     if (buf->data != NULL)
585e617892Stholo     {
595e617892Stholo 	buf->last->next = free_buffer_data;
605e617892Stholo 	free_buffer_data = buf->data;
615e617892Stholo     }
625e617892Stholo     free (buf);
635e617892Stholo }
645e617892Stholo 
6550bf276cStholo /* Initialize a buffer structure which is not to be used for I/O.  */
6650bf276cStholo 
6750bf276cStholo struct buffer *
6850bf276cStholo buf_nonio_initialize (memory)
6950bf276cStholo      void (*memory) PROTO((struct buffer *));
7050bf276cStholo {
7150bf276cStholo     return (buf_initialize
7250bf276cStholo 	    ((int (*) PROTO((void *, char *, int, int, int *))) NULL,
7350bf276cStholo 	     (int (*) PROTO((void *, const char *, int, int *))) NULL,
7450bf276cStholo 	     (int (*) PROTO((void *))) NULL,
7550bf276cStholo 	     (int (*) PROTO((void *, int))) NULL,
7650bf276cStholo 	     (int (*) PROTO((void *))) NULL,
7750bf276cStholo 	     memory,
7850bf276cStholo 	     (void *) NULL));
7950bf276cStholo }
8050bf276cStholo 
815e617892Stholo /* Default memory error handler.  */
825e617892Stholo 
835e617892Stholo static void
buf_default_memory_error(buf)845e617892Stholo buf_default_memory_error (buf)
855e617892Stholo      struct buffer *buf;
865e617892Stholo {
875e617892Stholo     error (1, 0, "out of memory");
885e617892Stholo }
895e617892Stholo 
9050bf276cStholo /* Allocate more buffer_data structures.  */
9150bf276cStholo 
9250bf276cStholo static void
allocate_buffer_datas()9350bf276cStholo allocate_buffer_datas ()
9450bf276cStholo {
9550bf276cStholo     struct buffer_data *alc;
9650bf276cStholo     char *space;
9750bf276cStholo     int i;
9850bf276cStholo 
9950bf276cStholo     /* Allocate buffer_data structures in blocks of 16.  */
10050bf276cStholo #define ALLOC_COUNT (16)
10150bf276cStholo 
10250bf276cStholo     alc = ((struct buffer_data *)
10350bf276cStholo 	   malloc (ALLOC_COUNT * sizeof (struct buffer_data)));
104*6afe391bSjsg     if (alc == NULL)
10550bf276cStholo 	return;
106*6afe391bSjsg     space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE);
107*6afe391bSjsg     if (space == NULL) {
108*6afe391bSjsg 	free(alc);
109*6afe391bSjsg 	return;
110*6afe391bSjsg     }
11150bf276cStholo     for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE)
11250bf276cStholo     {
11350bf276cStholo 	alc->next = free_buffer_data;
11450bf276cStholo 	free_buffer_data = alc;
11550bf276cStholo 	alc->text = space;
11650bf276cStholo     }
11750bf276cStholo }
11850bf276cStholo 
11950bf276cStholo /* Get a new buffer_data structure.  */
12050bf276cStholo 
12150bf276cStholo static struct buffer_data *
get_buffer_data()12250bf276cStholo get_buffer_data ()
12350bf276cStholo {
12450bf276cStholo     struct buffer_data *ret;
12550bf276cStholo 
12650bf276cStholo     if (free_buffer_data == NULL)
12750bf276cStholo     {
12850bf276cStholo 	allocate_buffer_datas ();
12950bf276cStholo 	if (free_buffer_data == NULL)
13050bf276cStholo 	    return NULL;
13150bf276cStholo     }
13250bf276cStholo 
13350bf276cStholo     ret = free_buffer_data;
13450bf276cStholo     free_buffer_data = ret->next;
13550bf276cStholo     return ret;
13650bf276cStholo }
13750bf276cStholo 
13850bf276cStholo /* See whether a buffer is empty.  */
13950bf276cStholo 
14050bf276cStholo int
buf_empty_p(buf)14150bf276cStholo buf_empty_p (buf)
14250bf276cStholo     struct buffer *buf;
14350bf276cStholo {
14450bf276cStholo     struct buffer_data *data;
14550bf276cStholo 
14650bf276cStholo     for (data = buf->data; data != NULL; data = data->next)
14750bf276cStholo 	if (data->size > 0)
14850bf276cStholo 	    return 0;
14950bf276cStholo     return 1;
15050bf276cStholo }
15150bf276cStholo 
15250bf276cStholo #ifdef SERVER_FLOWCONTROL
15350bf276cStholo /*
15450bf276cStholo  * Count how much data is stored in the buffer..
15550bf276cStholo  * Note that each buffer is a malloc'ed chunk BUFFER_DATA_SIZE.
15650bf276cStholo  */
15750bf276cStholo 
15850bf276cStholo int
buf_count_mem(buf)15950bf276cStholo buf_count_mem (buf)
16050bf276cStholo     struct buffer *buf;
16150bf276cStholo {
16250bf276cStholo     struct buffer_data *data;
16350bf276cStholo     int mem = 0;
16450bf276cStholo 
16550bf276cStholo     for (data = buf->data; data != NULL; data = data->next)
16650bf276cStholo 	mem += BUFFER_DATA_SIZE;
16750bf276cStholo 
16850bf276cStholo     return mem;
16950bf276cStholo }
17050bf276cStholo #endif /* SERVER_FLOWCONTROL */
17150bf276cStholo 
17250bf276cStholo /* Add data DATA of length LEN to BUF.  */
17350bf276cStholo 
17450bf276cStholo void
buf_output(buf,data,len)17550bf276cStholo buf_output (buf, data, len)
17650bf276cStholo     struct buffer *buf;
17750bf276cStholo     const char *data;
17850bf276cStholo     int len;
17950bf276cStholo {
18050bf276cStholo     if (buf->data != NULL
18150bf276cStholo 	&& (((buf->last->text + BUFFER_DATA_SIZE)
18250bf276cStholo 	     - (buf->last->bufp + buf->last->size))
18350bf276cStholo 	    >= len))
18450bf276cStholo     {
18550bf276cStholo 	memcpy (buf->last->bufp + buf->last->size, data, len);
18650bf276cStholo 	buf->last->size += len;
18750bf276cStholo 	return;
18850bf276cStholo     }
18950bf276cStholo 
19050bf276cStholo     while (1)
19150bf276cStholo     {
19250bf276cStholo 	struct buffer_data *newdata;
19350bf276cStholo 
19450bf276cStholo 	newdata = get_buffer_data ();
19550bf276cStholo 	if (newdata == NULL)
19650bf276cStholo 	{
19750bf276cStholo 	    (*buf->memory_error) (buf);
19850bf276cStholo 	    return;
19950bf276cStholo 	}
20050bf276cStholo 
20150bf276cStholo 	if (buf->data == NULL)
20250bf276cStholo 	    buf->data = newdata;
20350bf276cStholo 	else
20450bf276cStholo 	    buf->last->next = newdata;
20550bf276cStholo 	newdata->next = NULL;
20650bf276cStholo 	buf->last = newdata;
20750bf276cStholo 
20850bf276cStholo 	newdata->bufp = newdata->text;
20950bf276cStholo 
21050bf276cStholo 	if (len <= BUFFER_DATA_SIZE)
21150bf276cStholo 	{
21250bf276cStholo 	    newdata->size = len;
21350bf276cStholo 	    memcpy (newdata->text, data, len);
21450bf276cStholo 	    return;
21550bf276cStholo 	}
21650bf276cStholo 
21750bf276cStholo 	newdata->size = BUFFER_DATA_SIZE;
21850bf276cStholo 	memcpy (newdata->text, data, BUFFER_DATA_SIZE);
21950bf276cStholo 
22050bf276cStholo 	data += BUFFER_DATA_SIZE;
22150bf276cStholo 	len -= BUFFER_DATA_SIZE;
22250bf276cStholo     }
22350bf276cStholo 
22450bf276cStholo     /*NOTREACHED*/
22550bf276cStholo }
22650bf276cStholo 
22750bf276cStholo /* Add a '\0' terminated string to BUF.  */
22850bf276cStholo 
22950bf276cStholo void
buf_output0(buf,string)23050bf276cStholo buf_output0 (buf, string)
23150bf276cStholo     struct buffer *buf;
23250bf276cStholo     const char *string;
23350bf276cStholo {
23450bf276cStholo     buf_output (buf, string, strlen (string));
23550bf276cStholo }
23650bf276cStholo 
23750bf276cStholo /* Add a single character to BUF.  */
23850bf276cStholo 
23950bf276cStholo void
buf_append_char(buf,ch)24050bf276cStholo buf_append_char (buf, ch)
24150bf276cStholo     struct buffer *buf;
24250bf276cStholo     int ch;
24350bf276cStholo {
24450bf276cStholo     if (buf->data != NULL
24550bf276cStholo 	&& (buf->last->text + BUFFER_DATA_SIZE
24650bf276cStholo 	    != buf->last->bufp + buf->last->size))
24750bf276cStholo     {
24850bf276cStholo 	*(buf->last->bufp + buf->last->size) = ch;
24950bf276cStholo 	++buf->last->size;
25050bf276cStholo     }
25150bf276cStholo     else
25250bf276cStholo     {
25350bf276cStholo 	char b;
25450bf276cStholo 
25550bf276cStholo 	b = ch;
25650bf276cStholo 	buf_output (buf, &b, 1);
25750bf276cStholo     }
25850bf276cStholo }
25950bf276cStholo 
26050bf276cStholo /*
26150bf276cStholo  * Send all the output we've been saving up.  Returns 0 for success or
26250bf276cStholo  * errno code.  If the buffer has been set to be nonblocking, this
26350bf276cStholo  * will just write until the write would block.
26450bf276cStholo  */
26550bf276cStholo 
26650bf276cStholo int
buf_send_output(buf)26750bf276cStholo buf_send_output (buf)
26850bf276cStholo      struct buffer *buf;
26950bf276cStholo {
27050bf276cStholo     if (buf->output == NULL)
27150bf276cStholo 	abort ();
27250bf276cStholo 
27350bf276cStholo     while (buf->data != NULL)
27450bf276cStholo     {
27550bf276cStholo 	struct buffer_data *data;
27650bf276cStholo 
27750bf276cStholo 	data = buf->data;
27850bf276cStholo 
27950bf276cStholo 	if (data->size > 0)
28050bf276cStholo 	{
28150bf276cStholo 	    int status, nbytes;
28250bf276cStholo 
28350bf276cStholo 	    status = (*buf->output) (buf->closure, data->bufp, data->size,
28450bf276cStholo 				     &nbytes);
28550bf276cStholo 	    if (status != 0)
28650bf276cStholo 	    {
28750bf276cStholo 		/* Some sort of error.  Discard the data, and return.  */
28850bf276cStholo 
28950bf276cStholo 		buf->last->next = free_buffer_data;
29050bf276cStholo 		free_buffer_data = buf->data;
29150bf276cStholo 		buf->data = NULL;
29250bf276cStholo 		buf->last = NULL;
29350bf276cStholo 
29450bf276cStholo 	        return status;
29550bf276cStholo 	    }
29650bf276cStholo 
29750bf276cStholo 	    if (nbytes != data->size)
29850bf276cStholo 	    {
29950bf276cStholo 		/* Not all the data was written out.  This is only
30050bf276cStholo                    permitted in nonblocking mode.  Adjust the buffer,
30150bf276cStholo                    and return.  */
30250bf276cStholo 
30350bf276cStholo 		assert (buf->nonblocking);
30450bf276cStholo 
30550bf276cStholo 		data->size -= nbytes;
30650bf276cStholo 		data->bufp += nbytes;
30750bf276cStholo 
30850bf276cStholo 		return 0;
30950bf276cStholo 	    }
31050bf276cStholo 	}
31150bf276cStholo 
31250bf276cStholo 	buf->data = data->next;
31350bf276cStholo 	data->next = free_buffer_data;
31450bf276cStholo 	free_buffer_data = data;
31550bf276cStholo     }
31650bf276cStholo 
31750bf276cStholo     buf->last = NULL;
31850bf276cStholo 
31950bf276cStholo     return 0;
32050bf276cStholo }
32150bf276cStholo 
32250bf276cStholo /*
32350bf276cStholo  * Flush any data queued up in the buffer.  If BLOCK is nonzero, then
32450bf276cStholo  * if the buffer is in nonblocking mode, put it into blocking mode for
32550bf276cStholo  * the duration of the flush.  This returns 0 on success, or an error
32650bf276cStholo  * code.
32750bf276cStholo  */
32850bf276cStholo 
32950bf276cStholo int
buf_flush(buf,block)33050bf276cStholo buf_flush (buf, block)
33150bf276cStholo      struct buffer *buf;
33250bf276cStholo      int block;
33350bf276cStholo {
33450bf276cStholo     int nonblocking;
33550bf276cStholo     int status;
33650bf276cStholo 
33750bf276cStholo     if (buf->flush == NULL)
33850bf276cStholo         abort ();
33950bf276cStholo 
34050bf276cStholo     nonblocking = buf->nonblocking;
34150bf276cStholo     if (nonblocking && block)
34250bf276cStholo     {
34350bf276cStholo         status = set_block (buf);
34450bf276cStholo 	if (status != 0)
34550bf276cStholo 	    return status;
34650bf276cStholo     }
34750bf276cStholo 
34850bf276cStholo     status = buf_send_output (buf);
34950bf276cStholo     if (status == 0)
35050bf276cStholo         status = (*buf->flush) (buf->closure);
35150bf276cStholo 
35250bf276cStholo     if (nonblocking && block)
35350bf276cStholo     {
35450bf276cStholo         int blockstat;
35550bf276cStholo 
35650bf276cStholo         blockstat = set_nonblock (buf);
35750bf276cStholo 	if (status == 0)
35850bf276cStholo 	    status = blockstat;
35950bf276cStholo     }
36050bf276cStholo 
36150bf276cStholo     return status;
36250bf276cStholo }
36350bf276cStholo 
36450bf276cStholo /*
36550bf276cStholo  * Set buffer BUF to nonblocking I/O.  Returns 0 for success or errno
36650bf276cStholo  * code.
36750bf276cStholo  */
36850bf276cStholo 
36950bf276cStholo int
set_nonblock(buf)37050bf276cStholo set_nonblock (buf)
37150bf276cStholo      struct buffer *buf;
37250bf276cStholo {
37350bf276cStholo     int status;
37450bf276cStholo 
37550bf276cStholo     if (buf->nonblocking)
37650bf276cStholo 	return 0;
37750bf276cStholo     if (buf->block == NULL)
37850bf276cStholo         abort ();
37950bf276cStholo     status = (*buf->block) (buf->closure, 0);
38050bf276cStholo     if (status != 0)
38150bf276cStholo 	return status;
38250bf276cStholo     buf->nonblocking = 1;
38350bf276cStholo     return 0;
38450bf276cStholo }
38550bf276cStholo 
38650bf276cStholo /*
38750bf276cStholo  * Set buffer BUF to blocking I/O.  Returns 0 for success or errno
38850bf276cStholo  * code.
38950bf276cStholo  */
39050bf276cStholo 
39150bf276cStholo int
set_block(buf)39250bf276cStholo set_block (buf)
39350bf276cStholo      struct buffer *buf;
39450bf276cStholo {
39550bf276cStholo     int status;
39650bf276cStholo 
39750bf276cStholo     if (! buf->nonblocking)
39850bf276cStholo 	return 0;
39950bf276cStholo     if (buf->block == NULL)
40050bf276cStholo         abort ();
40150bf276cStholo     status = (*buf->block) (buf->closure, 1);
40250bf276cStholo     if (status != 0)
40350bf276cStholo 	return status;
40450bf276cStholo     buf->nonblocking = 0;
40550bf276cStholo     return 0;
40650bf276cStholo }
40750bf276cStholo 
40850bf276cStholo /*
40950bf276cStholo  * Send a character count and some output.  Returns errno code or 0 for
41050bf276cStholo  * success.
41150bf276cStholo  *
41250bf276cStholo  * Sending the count in binary is OK since this is only used on a pipe
41350bf276cStholo  * within the same system.
41450bf276cStholo  */
41550bf276cStholo 
41650bf276cStholo int
buf_send_counted(buf)41750bf276cStholo buf_send_counted (buf)
41850bf276cStholo      struct buffer *buf;
41950bf276cStholo {
42050bf276cStholo     int size;
42150bf276cStholo     struct buffer_data *data;
42250bf276cStholo 
42350bf276cStholo     size = 0;
42450bf276cStholo     for (data = buf->data; data != NULL; data = data->next)
42550bf276cStholo 	size += data->size;
42650bf276cStholo 
42750bf276cStholo     data = get_buffer_data ();
42850bf276cStholo     if (data == NULL)
42950bf276cStholo     {
43050bf276cStholo 	(*buf->memory_error) (buf);
43150bf276cStholo 	return ENOMEM;
43250bf276cStholo     }
43350bf276cStholo 
43450bf276cStholo     data->next = buf->data;
43550bf276cStholo     buf->data = data;
43650bf276cStholo     if (buf->last == NULL)
43750bf276cStholo 	buf->last = data;
43850bf276cStholo 
43950bf276cStholo     data->bufp = data->text;
44050bf276cStholo     data->size = sizeof (int);
44150bf276cStholo 
44250bf276cStholo     *((int *) data->text) = size;
44350bf276cStholo 
44450bf276cStholo     return buf_send_output (buf);
44550bf276cStholo }
44650bf276cStholo 
44750bf276cStholo /*
44850bf276cStholo  * Send a special count.  COUNT should be negative.  It will be
44950bf276cStholo  * handled speciallyi by buf_copy_counted.  This function returns 0 or
45050bf276cStholo  * an errno code.
45150bf276cStholo  *
45250bf276cStholo  * Sending the count in binary is OK since this is only used on a pipe
45350bf276cStholo  * within the same system.
45450bf276cStholo  */
45550bf276cStholo 
45650bf276cStholo int
buf_send_special_count(buf,count)45750bf276cStholo buf_send_special_count (buf, count)
45850bf276cStholo      struct buffer *buf;
45950bf276cStholo      int count;
46050bf276cStholo {
46150bf276cStholo     struct buffer_data *data;
46250bf276cStholo 
46350bf276cStholo     data = get_buffer_data ();
46450bf276cStholo     if (data == NULL)
46550bf276cStholo     {
46650bf276cStholo 	(*buf->memory_error) (buf);
46750bf276cStholo 	return ENOMEM;
46850bf276cStholo     }
46950bf276cStholo 
47050bf276cStholo     data->next = buf->data;
47150bf276cStholo     buf->data = data;
47250bf276cStholo     if (buf->last == NULL)
47350bf276cStholo 	buf->last = data;
47450bf276cStholo 
47550bf276cStholo     data->bufp = data->text;
47650bf276cStholo     data->size = sizeof (int);
47750bf276cStholo 
47850bf276cStholo     *((int *) data->text) = count;
47950bf276cStholo 
48050bf276cStholo     return buf_send_output (buf);
48150bf276cStholo }
48250bf276cStholo 
48350bf276cStholo /* Append a list of buffer_data structures to an buffer.  */
48450bf276cStholo 
48550bf276cStholo void
buf_append_data(buf,data,last)48650bf276cStholo buf_append_data (buf, data, last)
48750bf276cStholo      struct buffer *buf;
48850bf276cStholo      struct buffer_data *data;
48950bf276cStholo      struct buffer_data *last;
49050bf276cStholo {
49150bf276cStholo     if (data != NULL)
49250bf276cStholo     {
49350bf276cStholo 	if (buf->data == NULL)
49450bf276cStholo 	    buf->data = data;
49550bf276cStholo 	else
49650bf276cStholo 	    buf->last->next = data;
49750bf276cStholo 	buf->last = last;
49850bf276cStholo     }
49950bf276cStholo }
50050bf276cStholo 
5015e617892Stholo /* Append the data on one buffer to another.  This removes the data
5025e617892Stholo    from the source buffer.  */
5035e617892Stholo 
5045e617892Stholo void
buf_append_buffer(to,from)5055e617892Stholo buf_append_buffer (to, from)
5065e617892Stholo      struct buffer *to;
5075e617892Stholo      struct buffer *from;
5085e617892Stholo {
5095e617892Stholo     buf_append_data (to, from->data, from->last);
5105e617892Stholo     from->data = NULL;
5115e617892Stholo     from->last = NULL;
5125e617892Stholo }
5135e617892Stholo 
51450bf276cStholo /*
51550bf276cStholo  * Copy the contents of file F into buffer_data structures.  We can't
51650bf276cStholo  * copy directly into an buffer, because we want to handle failure and
51750bf276cStholo  * succeess differently.  Returns 0 on success, or -2 if out of
51850bf276cStholo  * memory, or a status code on error.  Since the caller happens to
51950bf276cStholo  * know the size of the file, it is passed in as SIZE.  On success,
52050bf276cStholo  * this function sets *RETP and *LASTP, which may be passed to
52150bf276cStholo  * buf_append_data.
52250bf276cStholo  */
52350bf276cStholo 
52450bf276cStholo int
buf_read_file(f,size,retp,lastp)52550bf276cStholo buf_read_file (f, size, retp, lastp)
52650bf276cStholo     FILE *f;
52750bf276cStholo     long size;
52850bf276cStholo     struct buffer_data **retp;
52950bf276cStholo     struct buffer_data **lastp;
53050bf276cStholo {
53150bf276cStholo     int status;
53250bf276cStholo 
53350bf276cStholo     *retp = NULL;
53450bf276cStholo     *lastp = NULL;
53550bf276cStholo 
53650bf276cStholo     while (size > 0)
53750bf276cStholo     {
53850bf276cStholo 	struct buffer_data *data;
53950bf276cStholo 	int get;
54050bf276cStholo 
54150bf276cStholo 	data = get_buffer_data ();
54250bf276cStholo 	if (data == NULL)
54350bf276cStholo 	{
54450bf276cStholo 	    status = -2;
54550bf276cStholo 	    goto error_return;
54650bf276cStholo 	}
54750bf276cStholo 
54850bf276cStholo 	if (*retp == NULL)
54950bf276cStholo 	    *retp = data;
55050bf276cStholo 	else
55150bf276cStholo 	    (*lastp)->next = data;
55250bf276cStholo 	data->next = NULL;
55350bf276cStholo 	*lastp = data;
55450bf276cStholo 
55550bf276cStholo 	data->bufp = data->text;
55650bf276cStholo 	data->size = 0;
55750bf276cStholo 
55850bf276cStholo 	if (size > BUFFER_DATA_SIZE)
55950bf276cStholo 	    get = BUFFER_DATA_SIZE;
56050bf276cStholo 	else
56150bf276cStholo 	    get = size;
56250bf276cStholo 
56350bf276cStholo 	errno = EIO;
56450bf276cStholo 	if (fread (data->text, get, 1, f) != 1)
56550bf276cStholo 	{
56650bf276cStholo 	    status = errno;
56750bf276cStholo 	    goto error_return;
56850bf276cStholo 	}
56950bf276cStholo 
57050bf276cStholo 	data->size += get;
57150bf276cStholo 	size -= get;
57250bf276cStholo     }
57350bf276cStholo 
57450bf276cStholo     return 0;
57550bf276cStholo 
57650bf276cStholo   error_return:
57750bf276cStholo     if (*retp != NULL)
57850bf276cStholo     {
57950bf276cStholo 	(*lastp)->next = free_buffer_data;
58050bf276cStholo 	free_buffer_data = *retp;
58150bf276cStholo     }
58250bf276cStholo     return status;
58350bf276cStholo }
58450bf276cStholo 
58550bf276cStholo /*
58650bf276cStholo  * Copy the contents of file F into buffer_data structures.  We can't
58750bf276cStholo  * copy directly into an buffer, because we want to handle failure and
58850bf276cStholo  * succeess differently.  Returns 0 on success, or -2 if out of
58950bf276cStholo  * memory, or a status code on error.  On success, this function sets
59050bf276cStholo  * *RETP and *LASTP, which may be passed to buf_append_data.
59150bf276cStholo  */
59250bf276cStholo 
59350bf276cStholo int
buf_read_file_to_eof(f,retp,lastp)59450bf276cStholo buf_read_file_to_eof (f, retp, lastp)
59550bf276cStholo      FILE *f;
59650bf276cStholo      struct buffer_data **retp;
59750bf276cStholo      struct buffer_data **lastp;
59850bf276cStholo {
59950bf276cStholo     int status;
60050bf276cStholo 
60150bf276cStholo     *retp = NULL;
60250bf276cStholo     *lastp = NULL;
60350bf276cStholo 
60450bf276cStholo     while (!feof (f))
60550bf276cStholo     {
60650bf276cStholo 	struct buffer_data *data;
60750bf276cStholo 	int get, nread;
60850bf276cStholo 
60950bf276cStholo 	data = get_buffer_data ();
61050bf276cStholo 	if (data == NULL)
61150bf276cStholo 	{
61250bf276cStholo 	    status = -2;
61350bf276cStholo 	    goto error_return;
61450bf276cStholo 	}
61550bf276cStholo 
61650bf276cStholo 	if (*retp == NULL)
61750bf276cStholo 	    *retp = data;
61850bf276cStholo 	else
61950bf276cStholo 	    (*lastp)->next = data;
62050bf276cStholo 	data->next = NULL;
62150bf276cStholo 	*lastp = data;
62250bf276cStholo 
62350bf276cStholo 	data->bufp = data->text;
62450bf276cStholo 	data->size = 0;
62550bf276cStholo 
62650bf276cStholo 	get = BUFFER_DATA_SIZE;
62750bf276cStholo 
62850bf276cStholo 	errno = EIO;
62950bf276cStholo 	nread = fread (data->text, 1, get, f);
63050bf276cStholo 	if (nread == 0 && !feof (f))
63150bf276cStholo 	{
63250bf276cStholo 	    status = errno;
63350bf276cStholo 	    goto error_return;
63450bf276cStholo 	}
63550bf276cStholo 
63650bf276cStholo 	data->size = nread;
63750bf276cStholo     }
63850bf276cStholo 
63950bf276cStholo     return 0;
64050bf276cStholo 
64150bf276cStholo   error_return:
64250bf276cStholo     if (*retp != NULL)
64350bf276cStholo     {
64450bf276cStholo 	(*lastp)->next = free_buffer_data;
64550bf276cStholo 	free_buffer_data = *retp;
64650bf276cStholo     }
64750bf276cStholo     return status;
64850bf276cStholo }
64950bf276cStholo 
65050bf276cStholo /* Return the number of bytes in a chain of buffer_data structures.  */
65150bf276cStholo 
65250bf276cStholo int
buf_chain_length(buf)65350bf276cStholo buf_chain_length (buf)
65450bf276cStholo      struct buffer_data *buf;
65550bf276cStholo {
65650bf276cStholo     int size = 0;
65750bf276cStholo     while (buf)
65850bf276cStholo     {
65950bf276cStholo 	size += buf->size;
66050bf276cStholo 	buf = buf->next;
66150bf276cStholo     }
66250bf276cStholo     return size;
66350bf276cStholo }
66450bf276cStholo 
6655e617892Stholo /* Return the number of bytes in a buffer.  */
6665e617892Stholo 
6675e617892Stholo int
buf_length(buf)6685e617892Stholo buf_length (buf)
6695e617892Stholo     struct buffer *buf;
6705e617892Stholo {
6715e617892Stholo     return buf_chain_length (buf->data);
6725e617892Stholo }
6735e617892Stholo 
67450bf276cStholo /*
67550bf276cStholo  * Read an arbitrary amount of data into an input buffer.  The buffer
67650bf276cStholo  * will be in nonblocking mode, and we just grab what we can.  Return
67750bf276cStholo  * 0 on success, or -1 on end of file, or -2 if out of memory, or an
67850bf276cStholo  * error code.  If COUNTP is not NULL, *COUNTP is set to the number of
67950bf276cStholo  * bytes read.
68050bf276cStholo  */
68150bf276cStholo 
68250bf276cStholo int
buf_input_data(buf,countp)68350bf276cStholo buf_input_data (buf, countp)
68450bf276cStholo      struct buffer *buf;
68550bf276cStholo      int *countp;
68650bf276cStholo {
68750bf276cStholo     if (buf->input == NULL)
68850bf276cStholo 	abort ();
68950bf276cStholo 
69050bf276cStholo     if (countp != NULL)
69150bf276cStholo 	*countp = 0;
69250bf276cStholo 
69350bf276cStholo     while (1)
69450bf276cStholo     {
69550bf276cStholo 	int get;
69650bf276cStholo 	int status, nbytes;
69750bf276cStholo 
69850bf276cStholo 	if (buf->data == NULL
69950bf276cStholo 	    || (buf->last->bufp + buf->last->size
70050bf276cStholo 		== buf->last->text + BUFFER_DATA_SIZE))
70150bf276cStholo 	{
70250bf276cStholo 	    struct buffer_data *data;
70350bf276cStholo 
70450bf276cStholo 	    data = get_buffer_data ();
70550bf276cStholo 	    if (data == NULL)
70650bf276cStholo 	    {
70750bf276cStholo 		(*buf->memory_error) (buf);
70850bf276cStholo 		return -2;
70950bf276cStholo 	    }
71050bf276cStholo 
71150bf276cStholo 	    if (buf->data == NULL)
71250bf276cStholo 		buf->data = data;
71350bf276cStholo 	    else
71450bf276cStholo 		buf->last->next = data;
71550bf276cStholo 	    data->next = NULL;
71650bf276cStholo 	    buf->last = data;
71750bf276cStholo 
71850bf276cStholo 	    data->bufp = data->text;
71950bf276cStholo 	    data->size = 0;
72050bf276cStholo 	}
72150bf276cStholo 
72250bf276cStholo 	get = ((buf->last->text + BUFFER_DATA_SIZE)
72350bf276cStholo 	       - (buf->last->bufp + buf->last->size));
72450bf276cStholo 
72550bf276cStholo 	status = (*buf->input) (buf->closure,
72650bf276cStholo 				buf->last->bufp + buf->last->size,
72750bf276cStholo 				0, get, &nbytes);
72850bf276cStholo 	if (status != 0)
72950bf276cStholo 	    return status;
73050bf276cStholo 
73150bf276cStholo 	buf->last->size += nbytes;
73250bf276cStholo 	if (countp != NULL)
73350bf276cStholo 	    *countp += nbytes;
73450bf276cStholo 
73550bf276cStholo 	if (nbytes < get)
73650bf276cStholo 	{
73750bf276cStholo 	    /* If we did not fill the buffer, then presumably we read
73850bf276cStholo                all the available data.  */
73950bf276cStholo 	    return 0;
74050bf276cStholo 	}
74150bf276cStholo     }
74250bf276cStholo 
74350bf276cStholo     /*NOTREACHED*/
74450bf276cStholo }
74550bf276cStholo 
74650bf276cStholo /*
74750bf276cStholo  * Read a line (characters up to a \012) from an input buffer.  (We
74850bf276cStholo  * use \012 rather than \n for the benefit of non Unix clients for
74950bf276cStholo  * which \n means something else).  This returns 0 on success, or -1
75050bf276cStholo  * on end of file, or -2 if out of memory, or an error code.  If it
75150bf276cStholo  * succeeds, it sets *LINE to an allocated buffer holding the contents
75250bf276cStholo  * of the line.  The trailing \012 is not included in the buffer.  If
75350bf276cStholo  * LENP is not NULL, then *LENP is set to the number of bytes read;
75450bf276cStholo  * strlen may not work, because there may be embedded null bytes.
75550bf276cStholo  */
75650bf276cStholo 
75750bf276cStholo int
buf_read_line(buf,line,lenp)75850bf276cStholo buf_read_line (buf, line, lenp)
75950bf276cStholo      struct buffer *buf;
76050bf276cStholo      char **line;
76150bf276cStholo      int *lenp;
76250bf276cStholo {
76350bf276cStholo     if (buf->input == NULL)
76450bf276cStholo         abort ();
76550bf276cStholo 
76650bf276cStholo     *line = NULL;
76750bf276cStholo 
76850bf276cStholo     while (1)
76950bf276cStholo     {
7702770ece5Stholo 	int len, finallen = 0;
77150bf276cStholo 	struct buffer_data *data;
77250bf276cStholo 	char *nl;
77350bf276cStholo 
77450bf276cStholo 	/* See if there is a newline in BUF.  */
77550bf276cStholo 	len = 0;
77650bf276cStholo 	for (data = buf->data; data != NULL; data = data->next)
77750bf276cStholo 	{
77850bf276cStholo 	    nl = memchr (data->bufp, '\012', data->size);
77950bf276cStholo 	    if (nl != NULL)
78050bf276cStholo 	    {
78150bf276cStholo 	        finallen = nl - data->bufp;
78250bf276cStholo 	        len += finallen;
78350bf276cStholo 		break;
78450bf276cStholo 	    }
78550bf276cStholo 	    len += data->size;
78650bf276cStholo 	}
78750bf276cStholo 
78850bf276cStholo 	/* If we found a newline, copy the line into a memory buffer,
78950bf276cStholo            and remove it from BUF.  */
79050bf276cStholo 	if (data != NULL)
79150bf276cStholo 	{
79250bf276cStholo 	    char *p;
79350bf276cStholo 	    struct buffer_data *nldata;
79450bf276cStholo 
79550bf276cStholo 	    p = malloc (len + 1);
79650bf276cStholo 	    if (p == NULL)
79750bf276cStholo 		return -2;
79850bf276cStholo 	    *line = p;
79950bf276cStholo 
80050bf276cStholo 	    nldata = data;
80150bf276cStholo 	    data = buf->data;
80250bf276cStholo 	    while (data != nldata)
80350bf276cStholo 	    {
80450bf276cStholo 		struct buffer_data *next;
80550bf276cStholo 
80650bf276cStholo 		memcpy (p, data->bufp, data->size);
80750bf276cStholo 		p += data->size;
80850bf276cStholo 		next = data->next;
80950bf276cStholo 		data->next = free_buffer_data;
81050bf276cStholo 		free_buffer_data = data;
81150bf276cStholo 		data = next;
81250bf276cStholo 	    }
81350bf276cStholo 
81450bf276cStholo 	    memcpy (p, data->bufp, finallen);
81550bf276cStholo 	    p[finallen] = '\0';
81650bf276cStholo 
81750bf276cStholo 	    data->size -= finallen + 1;
81850bf276cStholo 	    data->bufp = nl + 1;
81950bf276cStholo 	    buf->data = data;
82050bf276cStholo 
82150bf276cStholo 	    if (lenp != NULL)
82250bf276cStholo 	        *lenp = len;
82350bf276cStholo 
82450bf276cStholo 	    return 0;
82550bf276cStholo 	}
82650bf276cStholo 
82750bf276cStholo 	/* Read more data until we get a newline.  */
82850bf276cStholo 	while (1)
82950bf276cStholo 	{
83050bf276cStholo 	    int size, status, nbytes;
83150bf276cStholo 	    char *mem;
83250bf276cStholo 
83350bf276cStholo 	    if (buf->data == NULL
83450bf276cStholo 		|| (buf->last->bufp + buf->last->size
83550bf276cStholo 		    == buf->last->text + BUFFER_DATA_SIZE))
83650bf276cStholo 	    {
83750bf276cStholo 		data = get_buffer_data ();
83850bf276cStholo 		if (data == NULL)
83950bf276cStholo 		{
84050bf276cStholo 		    (*buf->memory_error) (buf);
84150bf276cStholo 		    return -2;
84250bf276cStholo 		}
84350bf276cStholo 
84450bf276cStholo 		if (buf->data == NULL)
84550bf276cStholo 		    buf->data = data;
84650bf276cStholo 		else
84750bf276cStholo 		    buf->last->next = data;
84850bf276cStholo 		data->next = NULL;
84950bf276cStholo 		buf->last = data;
85050bf276cStholo 
85150bf276cStholo 		data->bufp = data->text;
85250bf276cStholo 		data->size = 0;
85350bf276cStholo 	    }
85450bf276cStholo 
85550bf276cStholo 	    mem = buf->last->bufp + buf->last->size;
85650bf276cStholo 	    size = (buf->last->text + BUFFER_DATA_SIZE) - mem;
85750bf276cStholo 
85850bf276cStholo 	    /* We need to read at least 1 byte.  We can handle up to
85950bf276cStholo                SIZE bytes.  This will only be efficient if the
86050bf276cStholo                underlying communication stream does its own buffering,
86150bf276cStholo                or is clever about getting more than 1 byte at a time.  */
86250bf276cStholo 	    status = (*buf->input) (buf->closure, mem, 1, size, &nbytes);
86350bf276cStholo 	    if (status != 0)
86450bf276cStholo 		return status;
86550bf276cStholo 
86650bf276cStholo 	    buf->last->size += nbytes;
86750bf276cStholo 
86850bf276cStholo 	    /* Optimize slightly to avoid an unnecessary call to
86950bf276cStholo                memchr.  */
87050bf276cStholo 	    if (nbytes == 1)
87150bf276cStholo 	    {
87250bf276cStholo 		if (*mem == '\012')
87350bf276cStholo 		    break;
87450bf276cStholo 	    }
87550bf276cStholo 	    else
87650bf276cStholo 	    {
87750bf276cStholo 		if (memchr (mem, '\012', nbytes) != NULL)
87850bf276cStholo 		    break;
87950bf276cStholo 	    }
88050bf276cStholo 	}
88150bf276cStholo     }
88250bf276cStholo }
88350bf276cStholo 
88450bf276cStholo /*
88550bf276cStholo  * Extract data from the input buffer BUF.  This will read up to WANT
88650bf276cStholo  * bytes from the buffer.  It will set *RETDATA to point at the bytes,
88750bf276cStholo  * and set *GOT to the number of bytes to be found there.  Any buffer
88850bf276cStholo  * call which uses BUF may change the contents of the buffer at *DATA,
88950bf276cStholo  * so the data should be fully processed before any further calls are
89050bf276cStholo  * made.  This returns 0 on success, or -1 on end of file, or -2 if
89150bf276cStholo  * out of memory, or an error code.
89250bf276cStholo  */
89350bf276cStholo 
89450bf276cStholo int
buf_read_data(buf,want,retdata,got)89550bf276cStholo buf_read_data (buf, want, retdata, got)
89650bf276cStholo      struct buffer *buf;
89750bf276cStholo      int want;
89850bf276cStholo      char **retdata;
89950bf276cStholo      int *got;
90050bf276cStholo {
90150bf276cStholo     if (buf->input == NULL)
90250bf276cStholo 	abort ();
90350bf276cStholo 
90450bf276cStholo     while (buf->data != NULL && buf->data->size == 0)
90550bf276cStholo     {
90650bf276cStholo 	struct buffer_data *next;
90750bf276cStholo 
90850bf276cStholo 	next = buf->data->next;
90950bf276cStholo 	buf->data->next = free_buffer_data;
91050bf276cStholo 	free_buffer_data = buf->data;
91150bf276cStholo 	buf->data = next;
91250bf276cStholo 	if (next == NULL)
91350bf276cStholo 	    buf->last = NULL;
91450bf276cStholo     }
91550bf276cStholo 
91650bf276cStholo     if (buf->data == NULL)
91750bf276cStholo     {
91850bf276cStholo 	struct buffer_data *data;
91950bf276cStholo 	int get, status, nbytes;
92050bf276cStholo 
92150bf276cStholo 	data = get_buffer_data ();
92250bf276cStholo 	if (data == NULL)
92350bf276cStholo 	{
92450bf276cStholo 	    (*buf->memory_error) (buf);
92550bf276cStholo 	    return -2;
92650bf276cStholo 	}
92750bf276cStholo 
92850bf276cStholo 	buf->data = data;
92950bf276cStholo 	buf->last = data;
93050bf276cStholo 	data->next = NULL;
93150bf276cStholo 	data->bufp = data->text;
93250bf276cStholo 	data->size = 0;
93350bf276cStholo 
93450bf276cStholo 	if (want < BUFFER_DATA_SIZE)
93550bf276cStholo 	    get = want;
93650bf276cStholo 	else
93750bf276cStholo 	    get = BUFFER_DATA_SIZE;
93850bf276cStholo 	status = (*buf->input) (buf->closure, data->bufp, get,
93950bf276cStholo 				BUFFER_DATA_SIZE, &nbytes);
94050bf276cStholo 	if (status != 0)
94150bf276cStholo 	    return status;
94250bf276cStholo 
94350bf276cStholo 	data->size = nbytes;
94450bf276cStholo     }
94550bf276cStholo 
94650bf276cStholo     *retdata = buf->data->bufp;
94750bf276cStholo     if (want < buf->data->size)
94850bf276cStholo     {
94950bf276cStholo         *got = want;
95050bf276cStholo 	buf->data->size -= want;
95150bf276cStholo 	buf->data->bufp += want;
95250bf276cStholo     }
95350bf276cStholo     else
95450bf276cStholo     {
95550bf276cStholo         *got = buf->data->size;
95650bf276cStholo 	buf->data->size = 0;
95750bf276cStholo     }
95850bf276cStholo 
95950bf276cStholo     return 0;
96050bf276cStholo }
96150bf276cStholo 
96250bf276cStholo /*
96350bf276cStholo  * Copy lines from an input buffer to an output buffer.  This copies
96450bf276cStholo  * all complete lines (characters up to a newline) from INBUF to
96550bf276cStholo  * OUTBUF.  Each line in OUTBUF is preceded by the character COMMAND
96650bf276cStholo  * and a space.
96750bf276cStholo  */
96850bf276cStholo 
96950bf276cStholo void
buf_copy_lines(outbuf,inbuf,command)97050bf276cStholo buf_copy_lines (outbuf, inbuf, command)
97150bf276cStholo      struct buffer *outbuf;
97250bf276cStholo      struct buffer *inbuf;
97350bf276cStholo      int command;
97450bf276cStholo {
97550bf276cStholo     while (1)
97650bf276cStholo     {
97750bf276cStholo 	struct buffer_data *data;
97850bf276cStholo 	struct buffer_data *nldata;
97950bf276cStholo 	char *nl;
98050bf276cStholo 	int len;
98150bf276cStholo 
98250bf276cStholo 	/* See if there is a newline in INBUF.  */
98350bf276cStholo 	nldata = NULL;
98450bf276cStholo 	nl = NULL;
98550bf276cStholo 	for (data = inbuf->data; data != NULL; data = data->next)
98650bf276cStholo 	{
98750bf276cStholo 	    nl = memchr (data->bufp, '\n', data->size);
98850bf276cStholo 	    if (nl != NULL)
98950bf276cStholo 	    {
99050bf276cStholo 		nldata = data;
99150bf276cStholo 		break;
99250bf276cStholo 	    }
99350bf276cStholo 	}
99450bf276cStholo 
99550bf276cStholo 	if (nldata == NULL)
99650bf276cStholo 	{
99750bf276cStholo 	    /* There are no more lines in INBUF.  */
99850bf276cStholo 	    return;
99950bf276cStholo 	}
100050bf276cStholo 
100150bf276cStholo 	/* Put in the command.  */
100250bf276cStholo 	buf_append_char (outbuf, command);
100350bf276cStholo 	buf_append_char (outbuf, ' ');
100450bf276cStholo 
100550bf276cStholo 	if (inbuf->data != nldata)
100650bf276cStholo 	{
100750bf276cStholo 	    /*
100850bf276cStholo 	     * Simply move over all the buffers up to the one containing
100950bf276cStholo 	     * the newline.
101050bf276cStholo 	     */
101150bf276cStholo 	    for (data = inbuf->data; data->next != nldata; data = data->next)
101250bf276cStholo 		;
101350bf276cStholo 	    data->next = NULL;
101450bf276cStholo 	    buf_append_data (outbuf, inbuf->data, data);
101550bf276cStholo 	    inbuf->data = nldata;
101650bf276cStholo 	}
101750bf276cStholo 
101850bf276cStholo 	/*
101950bf276cStholo 	 * If the newline is at the very end of the buffer, just move
102050bf276cStholo 	 * the buffer onto OUTBUF.  Otherwise we must copy the data.
102150bf276cStholo 	 */
102250bf276cStholo 	len = nl + 1 - nldata->bufp;
102350bf276cStholo 	if (len == nldata->size)
102450bf276cStholo 	{
102550bf276cStholo 	    inbuf->data = nldata->next;
102650bf276cStholo 	    if (inbuf->data == NULL)
102750bf276cStholo 		inbuf->last = NULL;
102850bf276cStholo 
102950bf276cStholo 	    nldata->next = NULL;
103050bf276cStholo 	    buf_append_data (outbuf, nldata, nldata);
103150bf276cStholo 	}
103250bf276cStholo 	else
103350bf276cStholo 	{
103450bf276cStholo 	    buf_output (outbuf, nldata->bufp, len);
103550bf276cStholo 	    nldata->bufp += len;
103650bf276cStholo 	    nldata->size -= len;
103750bf276cStholo 	}
103850bf276cStholo     }
103950bf276cStholo }
104050bf276cStholo 
104150bf276cStholo /*
104250bf276cStholo  * Copy counted data from one buffer to another.  The count is an
104350bf276cStholo  * integer, host size, host byte order (it is only used across a
104450bf276cStholo  * pipe).  If there is enough data, it should be moved over.  If there
104550bf276cStholo  * is not enough data, it should remain on the original buffer.  A
104650bf276cStholo  * negative count is a special case.  if one is seen, *SPECIAL is set
104750bf276cStholo  * to the (negative) count value and no additional data is gathered
104850bf276cStholo  * from the buffer; normally *SPECIAL is set to 0.  This function
104950bf276cStholo  * returns the number of bytes it needs to see in order to actually
105050bf276cStholo  * copy something over.
105150bf276cStholo  */
105250bf276cStholo 
105350bf276cStholo int
buf_copy_counted(outbuf,inbuf,special)105450bf276cStholo buf_copy_counted (outbuf, inbuf, special)
105550bf276cStholo      struct buffer *outbuf;
105650bf276cStholo      struct buffer *inbuf;
105750bf276cStholo      int *special;
105850bf276cStholo {
105950bf276cStholo     *special = 0;
106050bf276cStholo 
106150bf276cStholo     while (1)
106250bf276cStholo     {
106350bf276cStholo 	struct buffer_data *data;
106450bf276cStholo 	int need;
106550bf276cStholo 	union
106650bf276cStholo 	{
106750bf276cStholo 	    char intbuf[sizeof (int)];
106850bf276cStholo 	    int i;
106950bf276cStholo 	} u;
107050bf276cStholo 	char *intp;
107150bf276cStholo 	int count;
107250bf276cStholo 	struct buffer_data *start;
107350bf276cStholo 	int startoff;
107450bf276cStholo 	struct buffer_data *stop;
107550bf276cStholo 	int stopwant;
107650bf276cStholo 
107750bf276cStholo 	/* See if we have enough bytes to figure out the count.  */
107850bf276cStholo 	need = sizeof (int);
107950bf276cStholo 	intp = u.intbuf;
108050bf276cStholo 	for (data = inbuf->data; data != NULL; data = data->next)
108150bf276cStholo 	{
108250bf276cStholo 	    if (data->size >= need)
108350bf276cStholo 	    {
108450bf276cStholo 		memcpy (intp, data->bufp, need);
108550bf276cStholo 		break;
108650bf276cStholo 	    }
108750bf276cStholo 	    memcpy (intp, data->bufp, data->size);
108850bf276cStholo 	    intp += data->size;
108950bf276cStholo 	    need -= data->size;
109050bf276cStholo 	}
109150bf276cStholo 	if (data == NULL)
109250bf276cStholo 	{
109350bf276cStholo 	    /* We don't have enough bytes to form an integer.  */
109450bf276cStholo 	    return need;
109550bf276cStholo 	}
109650bf276cStholo 
109750bf276cStholo 	count = u.i;
109850bf276cStholo 	start = data;
109950bf276cStholo 	startoff = need;
110050bf276cStholo 
110150bf276cStholo 	if (count < 0)
110250bf276cStholo 	{
110350bf276cStholo 	    /* A negative COUNT is a special case meaning that we
110450bf276cStholo                don't need any further information.  */
110550bf276cStholo 	    stop = start;
110650bf276cStholo 	    stopwant = 0;
110750bf276cStholo 	}
110850bf276cStholo 	else
110950bf276cStholo 	{
111050bf276cStholo 	    /*
111150bf276cStholo 	     * We have an integer in COUNT.  We have gotten all the
111250bf276cStholo 	     * data from INBUF in all buffers before START, and we
111350bf276cStholo 	     * have gotten STARTOFF bytes from START.  See if we have
111450bf276cStholo 	     * enough bytes remaining in INBUF.
111550bf276cStholo 	     */
111650bf276cStholo 	    need = count - (start->size - startoff);
111750bf276cStholo 	    if (need <= 0)
111850bf276cStholo 	    {
111950bf276cStholo 		stop = start;
112050bf276cStholo 		stopwant = count;
112150bf276cStholo 	    }
112250bf276cStholo 	    else
112350bf276cStholo 	    {
112450bf276cStholo 		for (data = start->next; data != NULL; data = data->next)
112550bf276cStholo 		{
112650bf276cStholo 		    if (need <= data->size)
112750bf276cStholo 			break;
112850bf276cStholo 		    need -= data->size;
112950bf276cStholo 		}
113050bf276cStholo 		if (data == NULL)
113150bf276cStholo 		{
113250bf276cStholo 		    /* We don't have enough bytes.  */
113350bf276cStholo 		    return need;
113450bf276cStholo 		}
113550bf276cStholo 		stop = data;
113650bf276cStholo 		stopwant = need;
113750bf276cStholo 	    }
113850bf276cStholo 	}
113950bf276cStholo 
114050bf276cStholo 	/*
114150bf276cStholo 	 * We have enough bytes.  Free any buffers in INBUF before
114250bf276cStholo 	 * START, and remove STARTOFF bytes from START, so that we can
114350bf276cStholo 	 * forget about STARTOFF.
114450bf276cStholo 	 */
114550bf276cStholo 	start->bufp += startoff;
114650bf276cStholo 	start->size -= startoff;
114750bf276cStholo 
114850bf276cStholo 	if (start->size == 0)
114950bf276cStholo 	    start = start->next;
115050bf276cStholo 
115150bf276cStholo 	if (stop->size == stopwant)
115250bf276cStholo 	{
115350bf276cStholo 	    stop = stop->next;
115450bf276cStholo 	    stopwant = 0;
115550bf276cStholo 	}
115650bf276cStholo 
115750bf276cStholo 	while (inbuf->data != start)
115850bf276cStholo 	{
115950bf276cStholo 	    data = inbuf->data;
116050bf276cStholo 	    inbuf->data = data->next;
116150bf276cStholo 	    data->next = free_buffer_data;
116250bf276cStholo 	    free_buffer_data = data;
116350bf276cStholo 	}
116450bf276cStholo 
116550bf276cStholo 	/* If COUNT is negative, set *SPECIAL and get out now.  */
116650bf276cStholo 	if (count < 0)
116750bf276cStholo 	{
116850bf276cStholo 	    *special = count;
116950bf276cStholo 	    return 0;
117050bf276cStholo 	}
117150bf276cStholo 
117250bf276cStholo 	/*
117350bf276cStholo 	 * We want to copy over the bytes from START through STOP.  We
117450bf276cStholo 	 * only want STOPWANT bytes from STOP.
117550bf276cStholo 	 */
117650bf276cStholo 
117750bf276cStholo 	if (start != stop)
117850bf276cStholo 	{
117950bf276cStholo 	    /* Attach the buffers from START through STOP to OUTBUF.  */
118050bf276cStholo 	    for (data = start; data->next != stop; data = data->next)
118150bf276cStholo 		;
118250bf276cStholo 	    inbuf->data = stop;
118350bf276cStholo 	    data->next = NULL;
118450bf276cStholo 	    buf_append_data (outbuf, start, data);
118550bf276cStholo 	}
118650bf276cStholo 
118750bf276cStholo 	if (stopwant > 0)
118850bf276cStholo 	{
118950bf276cStholo 	    buf_output (outbuf, stop->bufp, stopwant);
119050bf276cStholo 	    stop->bufp += stopwant;
119150bf276cStholo 	    stop->size -= stopwant;
119250bf276cStholo 	}
119350bf276cStholo     }
119450bf276cStholo 
119550bf276cStholo     /*NOTREACHED*/
119650bf276cStholo }
119750bf276cStholo 
119850bf276cStholo /* Shut down a buffer.  This returns 0 on success, or an errno code.  */
119950bf276cStholo 
120050bf276cStholo int
buf_shutdown(buf)120150bf276cStholo buf_shutdown (buf)
120250bf276cStholo      struct buffer *buf;
120350bf276cStholo {
120450bf276cStholo     if (buf->shutdown)
120550bf276cStholo 	return (*buf->shutdown) (buf->closure);
120650bf276cStholo     return 0;
120750bf276cStholo }
120850bf276cStholo 
120950bf276cStholo /* The simplest type of buffer is one built on top of a stdio FILE.
121050bf276cStholo    For simplicity, and because it is all that is required, we do not
121150bf276cStholo    implement setting this type of buffer into nonblocking mode.  The
121250bf276cStholo    closure field is just a FILE *.  */
121350bf276cStholo 
121450bf276cStholo static int stdio_buffer_input PROTO((void *, char *, int, int, int *));
121550bf276cStholo static int stdio_buffer_output PROTO((void *, const char *, int, int *));
121650bf276cStholo static int stdio_buffer_flush PROTO((void *));
121750bf276cStholo 
121850bf276cStholo /* Initialize a buffer built on a stdio FILE.  */
121950bf276cStholo 
12202286d8edStholo struct buffer *
stdio_buffer_initialize(fp,input,memory)12212286d8edStholo stdio_buffer_initialize (fp, input, memory)
122250bf276cStholo      FILE *fp;
122350bf276cStholo      int input;
122450bf276cStholo      void (*memory) PROTO((struct buffer *));
122550bf276cStholo {
122650bf276cStholo     return buf_initialize (input ? stdio_buffer_input : NULL,
122750bf276cStholo 			   input ? NULL : stdio_buffer_output,
122850bf276cStholo 			   input ? NULL : stdio_buffer_flush,
122950bf276cStholo 			   (int (*) PROTO((void *, int))) NULL,
123050bf276cStholo 			   (int (*) PROTO((void *))) NULL,
123150bf276cStholo 			   memory,
123250bf276cStholo 			   (void *) fp);
123350bf276cStholo }
123450bf276cStholo 
123550bf276cStholo /* The buffer input function for a buffer built on a stdio FILE.  */
123650bf276cStholo 
123750bf276cStholo static int
stdio_buffer_input(closure,data,need,size,got)123850bf276cStholo stdio_buffer_input (closure, data, need, size, got)
123950bf276cStholo      void *closure;
124050bf276cStholo      char *data;
124150bf276cStholo      int need;
124250bf276cStholo      int size;
124350bf276cStholo      int *got;
124450bf276cStholo {
124550bf276cStholo     FILE *fp = (FILE *) closure;
124650bf276cStholo     int nbytes;
124750bf276cStholo 
124850bf276cStholo     /* Since stdio does its own buffering, we don't worry about
124950bf276cStholo        getting more bytes than we need.  */
125050bf276cStholo 
125150bf276cStholo     if (need == 0 || need == 1)
125250bf276cStholo     {
125350bf276cStholo         int ch;
125450bf276cStholo 
125550bf276cStholo 	ch = getc (fp);
125650bf276cStholo 
125750bf276cStholo 	if (ch == EOF)
125850bf276cStholo 	{
125950bf276cStholo 	    if (feof (fp))
126050bf276cStholo 		return -1;
126150bf276cStholo 	    else if (errno == 0)
126250bf276cStholo 		return EIO;
126350bf276cStholo 	    else
126450bf276cStholo 		return errno;
126550bf276cStholo 	}
126650bf276cStholo 
126750bf276cStholo 	*data = ch;
126850bf276cStholo 	*got = 1;
126950bf276cStholo 	return 0;
127050bf276cStholo     }
127150bf276cStholo 
127250bf276cStholo     nbytes = fread (data, 1, need, fp);
127350bf276cStholo 
127450bf276cStholo     if (nbytes == 0)
127550bf276cStholo     {
127650bf276cStholo 	*got = 0;
127750bf276cStholo 	if (feof (fp))
127850bf276cStholo 	    return -1;
127950bf276cStholo 	else if (errno == 0)
128050bf276cStholo 	    return EIO;
128150bf276cStholo 	else
128250bf276cStholo 	    return errno;
128350bf276cStholo     }
128450bf276cStholo 
128550bf276cStholo     *got = nbytes;
128650bf276cStholo 
128750bf276cStholo     return 0;
128850bf276cStholo }
128950bf276cStholo 
129050bf276cStholo /* The buffer output function for a buffer built on a stdio FILE.  */
129150bf276cStholo 
129250bf276cStholo static int
stdio_buffer_output(closure,data,have,wrote)129350bf276cStholo stdio_buffer_output (closure, data, have, wrote)
129450bf276cStholo      void *closure;
129550bf276cStholo      const char *data;
129650bf276cStholo      int have;
129750bf276cStholo      int *wrote;
129850bf276cStholo {
129950bf276cStholo     FILE *fp = (FILE *) closure;
130050bf276cStholo 
130150bf276cStholo     *wrote = 0;
130250bf276cStholo 
130350bf276cStholo     while (have > 0)
130450bf276cStholo     {
130550bf276cStholo 	int nbytes;
130650bf276cStholo 
130750bf276cStholo 	nbytes = fwrite (data, 1, have, fp);
130850bf276cStholo 
130950bf276cStholo 	if (nbytes != have)
131050bf276cStholo 	{
131150bf276cStholo 	    if (errno == 0)
131250bf276cStholo 		return EIO;
131350bf276cStholo 	    else
131450bf276cStholo 		return errno;
131550bf276cStholo 	}
131650bf276cStholo 
131750bf276cStholo 	*wrote += nbytes;
131850bf276cStholo 	have -= nbytes;
131950bf276cStholo 	data += nbytes;
132050bf276cStholo     }
132150bf276cStholo 
132250bf276cStholo     return 0;
132350bf276cStholo }
132450bf276cStholo 
132550bf276cStholo /* The buffer flush function for a buffer built on a stdio FILE.  */
132650bf276cStholo 
132750bf276cStholo static int
stdio_buffer_flush(closure)132850bf276cStholo stdio_buffer_flush (closure)
132950bf276cStholo      void *closure;
133050bf276cStholo {
133150bf276cStholo     FILE *fp = (FILE *) closure;
133250bf276cStholo 
133350bf276cStholo     if (fflush (fp) != 0)
133450bf276cStholo     {
133550bf276cStholo 	if (errno == 0)
133650bf276cStholo 	    return EIO;
133750bf276cStholo 	else
133850bf276cStholo 	    return errno;
133950bf276cStholo     }
134050bf276cStholo 
134150bf276cStholo     return 0;
134250bf276cStholo }
134350bf276cStholo 
13442286d8edStholo /* Certain types of communication input and output data in packets,
13452286d8edStholo    where each packet is translated in some fashion.  The packetizing
13462286d8edStholo    buffer type supports that, given a buffer which handles lower level
13472286d8edStholo    I/O and a routine to translate the data in a packet.
13482286d8edStholo 
13492286d8edStholo    This code uses two bytes for the size of a packet, so packets are
13502286d8edStholo    restricted to 65536 bytes in total.
13512286d8edStholo 
13522286d8edStholo    The translation functions should just translate; they may not
13532286d8edStholo    significantly increase or decrease the amount of data.  The actual
13542286d8edStholo    size of the initial data is part of the translated data.  The
13552286d8edStholo    output translation routine may add up to PACKET_SLOP additional
13562286d8edStholo    bytes, and the input translation routine should shrink the data
13572286d8edStholo    correspondingly.  */
13582286d8edStholo 
13592286d8edStholo #define PACKET_SLOP (100)
13602286d8edStholo 
13612286d8edStholo /* This structure is the closure field of a packetizing buffer.  */
13622286d8edStholo 
13632286d8edStholo struct packetizing_buffer
13642286d8edStholo {
13652286d8edStholo     /* The underlying buffer.  */
13662286d8edStholo     struct buffer *buf;
13672286d8edStholo     /* The input translation function.  Exactly one of inpfn and outfn
13682286d8edStholo        will be NULL.  The input translation function should
13692286d8edStholo        untranslate the data in INPUT, storing the result in OUTPUT.
13702286d8edStholo        SIZE is the amount of data in INPUT, and is also the size of
13712286d8edStholo        OUTPUT.  This should return 0 on success, or an errno code.  */
13722286d8edStholo     int (*inpfn) PROTO((void *fnclosure, const char *input, char *output,
13732286d8edStholo 			int size));
13742286d8edStholo     /* The output translation function.  This should translate the
13752286d8edStholo        data in INPUT, storing the result in OUTPUT.  The first two
13762286d8edStholo        bytes in INPUT will be the size of the data, and so will SIZE.
13772286d8edStholo        This should set *TRANSLATED to the amount of translated data in
13782286d8edStholo        OUTPUT.  OUTPUT is large enough to hold SIZE + PACKET_SLOP
13792286d8edStholo        bytes.  This should return 0 on success, or an errno code.  */
13802286d8edStholo     int (*outfn) PROTO((void *fnclosure, const char *input, char *output,
13812286d8edStholo 			int size, int *translated));
13822286d8edStholo     /* A closure for the translation function.  */
13832286d8edStholo     void *fnclosure;
13842286d8edStholo     /* For an input buffer, we may have to buffer up data here.  */
13852286d8edStholo     /* This is non-zero if the buffered data has been translated.
13862286d8edStholo        Otherwise, the buffered data has not been translated, and starts
13872286d8edStholo        with the two byte packet size.  */
13882286d8edStholo     int translated;
13892286d8edStholo     /* The amount of buffered data.  */
13902286d8edStholo     int holdsize;
13912286d8edStholo     /* The buffer allocated to hold the data.  */
13922286d8edStholo     char *holdbuf;
13932286d8edStholo     /* The size of holdbuf.  */
13942286d8edStholo     int holdbufsize;
13952286d8edStholo     /* If translated is set, we need another data pointer to track
13962286d8edStholo        where we are in holdbuf.  If translated is clear, then this
13972286d8edStholo        pointer is not used.  */
13982286d8edStholo     char *holddata;
13992286d8edStholo };
14002286d8edStholo 
14012286d8edStholo static int packetizing_buffer_input PROTO((void *, char *, int, int, int *));
14022286d8edStholo static int packetizing_buffer_output PROTO((void *, const char *, int, int *));
14032286d8edStholo static int packetizing_buffer_flush PROTO((void *));
14042286d8edStholo static int packetizing_buffer_block PROTO((void *, int));
14052286d8edStholo static int packetizing_buffer_shutdown PROTO((void *));
14062286d8edStholo 
14072286d8edStholo /* Create a packetizing buffer.  */
14082286d8edStholo 
14092286d8edStholo struct buffer *
packetizing_buffer_initialize(buf,inpfn,outfn,fnclosure,memory)14102286d8edStholo packetizing_buffer_initialize (buf, inpfn, outfn, fnclosure, memory)
14112286d8edStholo      struct buffer *buf;
14122286d8edStholo      int (*inpfn) PROTO ((void *, const char *, char *, int));
14132286d8edStholo      int (*outfn) PROTO ((void *, const char *, char *, int, int *));
14142286d8edStholo      void *fnclosure;
14152286d8edStholo      void (*memory) PROTO((struct buffer *));
14162286d8edStholo {
14172286d8edStholo     struct packetizing_buffer *pb;
14182286d8edStholo 
14192286d8edStholo     pb = (struct packetizing_buffer *) xmalloc (sizeof *pb);
14202286d8edStholo     memset (pb, 0, sizeof *pb);
14212286d8edStholo 
14222286d8edStholo     pb->buf = buf;
14232286d8edStholo     pb->inpfn = inpfn;
14242286d8edStholo     pb->outfn = outfn;
14252286d8edStholo     pb->fnclosure = fnclosure;
14262286d8edStholo 
14272286d8edStholo     if (inpfn != NULL)
14282286d8edStholo     {
14292286d8edStholo 	/* Add PACKET_SLOP to handle larger translated packets, and
14302286d8edStholo            add 2 for the count.  This buffer is increased if
14312286d8edStholo            necessary.  */
14322286d8edStholo 	pb->holdbufsize = BUFFER_DATA_SIZE + PACKET_SLOP + 2;
14332286d8edStholo 	pb->holdbuf = xmalloc (pb->holdbufsize);
14342286d8edStholo     }
14352286d8edStholo 
14362286d8edStholo     return buf_initialize (inpfn != NULL ? packetizing_buffer_input : NULL,
14372286d8edStholo 			   inpfn != NULL ? NULL : packetizing_buffer_output,
14382286d8edStholo 			   inpfn != NULL ? NULL : packetizing_buffer_flush,
14392286d8edStholo 			   packetizing_buffer_block,
14402286d8edStholo 			   packetizing_buffer_shutdown,
14412286d8edStholo 			   memory,
14422286d8edStholo 			   pb);
14432286d8edStholo }
14442286d8edStholo 
14452286d8edStholo /* Input data from a packetizing buffer.  */
14462286d8edStholo 
14472286d8edStholo static int
packetizing_buffer_input(closure,data,need,size,got)14482286d8edStholo packetizing_buffer_input (closure, data, need, size, got)
14492286d8edStholo      void *closure;
14502286d8edStholo      char *data;
14512286d8edStholo      int need;
14522286d8edStholo      int size;
14532286d8edStholo      int *got;
14542286d8edStholo {
14552286d8edStholo     struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
14562286d8edStholo 
14572286d8edStholo     *got = 0;
14582286d8edStholo 
14592286d8edStholo     if (pb->holdsize > 0 && pb->translated)
14602286d8edStholo     {
14612286d8edStholo 	int copy;
14622286d8edStholo 
14632286d8edStholo 	copy = pb->holdsize;
14642286d8edStholo 
14652286d8edStholo 	if (copy > size)
14662286d8edStholo 	{
14672286d8edStholo 	    memcpy (data, pb->holddata, size);
14682286d8edStholo 	    pb->holdsize -= size;
14692286d8edStholo 	    pb->holddata += size;
14702286d8edStholo 	    *got = size;
14712286d8edStholo 	    return 0;
14722286d8edStholo 	}
14732286d8edStholo 
14742286d8edStholo 	memcpy (data, pb->holddata, copy);
14752286d8edStholo 	pb->holdsize = 0;
14762286d8edStholo 	pb->translated = 0;
14772286d8edStholo 
14782286d8edStholo 	data += copy;
14792286d8edStholo 	need -= copy;
14802286d8edStholo 	size -= copy;
14812286d8edStholo 	*got = copy;
14822286d8edStholo     }
14832286d8edStholo 
14842286d8edStholo     while (need > 0 || *got == 0)
14852286d8edStholo     {
14862286d8edStholo 	int get, status, nread, count, tcount;
14872286d8edStholo 	char *bytes;
14882286d8edStholo 	char stackoutbuf[BUFFER_DATA_SIZE + PACKET_SLOP];
14892286d8edStholo 	char *inbuf, *outbuf;
14902286d8edStholo 
14912286d8edStholo 	/* If we don't already have the two byte count, get it.  */
14922286d8edStholo 	if (pb->holdsize < 2)
14932286d8edStholo 	{
14942286d8edStholo 	    get = 2 - pb->holdsize;
14952286d8edStholo 	    status = buf_read_data (pb->buf, get, &bytes, &nread);
14962286d8edStholo 	    if (status != 0)
14972286d8edStholo 	    {
14982286d8edStholo 		/* buf_read_data can return -2, but a buffer input
14992286d8edStholo                    function is only supposed to return -1, 0, or an
15002286d8edStholo                    error code.  */
15012286d8edStholo 		if (status == -2)
15022286d8edStholo 		    status = ENOMEM;
15032286d8edStholo 		return status;
15042286d8edStholo 	    }
15052286d8edStholo 
15062286d8edStholo 	    if (nread == 0)
15072286d8edStholo 	    {
15082286d8edStholo 		/* The buffer is in nonblocking mode, and we didn't
15092286d8edStholo                    manage to read anything.  */
15102286d8edStholo 		return 0;
15112286d8edStholo 	    }
15122286d8edStholo 
15132286d8edStholo 	    if (get == 1)
15142286d8edStholo 		pb->holdbuf[1] = bytes[0];
15152286d8edStholo 	    else
15162286d8edStholo 	    {
15172286d8edStholo 		pb->holdbuf[0] = bytes[0];
15182286d8edStholo 		if (nread < 2)
15192286d8edStholo 		{
15202286d8edStholo 		    /* We only got one byte, but we needed two.  Stash
15212286d8edStholo                        the byte we got, and try again.  */
15222286d8edStholo 		    pb->holdsize = 1;
15232286d8edStholo 		    continue;
15242286d8edStholo 		}
15252286d8edStholo 		pb->holdbuf[1] = bytes[1];
15262286d8edStholo 	    }
15272286d8edStholo 	    pb->holdsize = 2;
15282286d8edStholo 	}
15292286d8edStholo 
15302286d8edStholo 	/* Read the packet.  */
15312286d8edStholo 
15322286d8edStholo 	count = (((pb->holdbuf[0] & 0xff) << 8)
15332286d8edStholo 		 + (pb->holdbuf[1] & 0xff));
15342286d8edStholo 
15352286d8edStholo 	if (count + 2 > pb->holdbufsize)
15362286d8edStholo 	{
15372286d8edStholo 	    char *n;
15382286d8edStholo 
15392286d8edStholo 	    /* We didn't allocate enough space in the initialize
15402286d8edStholo                function.  */
15412286d8edStholo 
15422286d8edStholo 	    n = realloc (pb->holdbuf, count + 2);
15432286d8edStholo 	    if (n == NULL)
15442286d8edStholo 	    {
15452286d8edStholo 		(*pb->buf->memory_error) (pb->buf);
15462286d8edStholo 		return ENOMEM;
15472286d8edStholo 	    }
15482286d8edStholo 	    pb->holdbuf = n;
15492286d8edStholo 	    pb->holdbufsize = count + 2;
15502286d8edStholo 	}
15512286d8edStholo 
15522286d8edStholo 	get = count - (pb->holdsize - 2);
15532286d8edStholo 
15542286d8edStholo 	status = buf_read_data (pb->buf, get, &bytes, &nread);
15552286d8edStholo 	if (status != 0)
15562286d8edStholo 	{
15572286d8edStholo 	    /* buf_read_data can return -2, but a buffer input
15582286d8edStholo                function is only supposed to return -1, 0, or an error
15592286d8edStholo                code.  */
15602286d8edStholo 	    if (status == -2)
15612286d8edStholo 		status = ENOMEM;
15622286d8edStholo 	    return status;
15632286d8edStholo 	}
15642286d8edStholo 
15652286d8edStholo 	if (nread == 0)
15662286d8edStholo 	{
15672286d8edStholo 	    /* We did not get any data.  Presumably the buffer is in
15682286d8edStholo                nonblocking mode.  */
15692286d8edStholo 	    return 0;
15702286d8edStholo 	}
15712286d8edStholo 
15722286d8edStholo 	if (nread < get)
15732286d8edStholo 	{
15742286d8edStholo 	    /* We did not get all the data we need to fill the packet.
15752286d8edStholo                buf_read_data does not promise to return all the bytes
15762286d8edStholo                requested, so we must try again.  */
15772286d8edStholo 	    memcpy (pb->holdbuf + pb->holdsize, bytes, nread);
15782286d8edStholo 	    pb->holdsize += nread;
15792286d8edStholo 	    continue;
15802286d8edStholo 	}
15812286d8edStholo 
15822286d8edStholo 	/* We have a complete untranslated packet of COUNT bytes.  */
15832286d8edStholo 
15842286d8edStholo 	if (pb->holdsize == 2)
15852286d8edStholo 	{
15862286d8edStholo 	    /* We just read the entire packet (the 2 bytes in
15872286d8edStholo                PB->HOLDBUF are the size).  Save a memcpy by
15882286d8edStholo                translating directly from BYTES.  */
15892286d8edStholo 	    inbuf = bytes;
15902286d8edStholo 	}
15912286d8edStholo 	else
15922286d8edStholo 	{
15932286d8edStholo 	    /* We already had a partial packet in PB->HOLDBUF.  We
15942286d8edStholo                need to copy the new data over to make the input
15952286d8edStholo                contiguous.  */
15962286d8edStholo 	    memcpy (pb->holdbuf + pb->holdsize, bytes, nread);
15972286d8edStholo 	    inbuf = pb->holdbuf + 2;
15982286d8edStholo 	}
15992286d8edStholo 
16002286d8edStholo 	if (count <= sizeof stackoutbuf)
16012286d8edStholo 	    outbuf = stackoutbuf;
16022286d8edStholo 	else
16032286d8edStholo 	{
16042286d8edStholo 	    outbuf = malloc (count);
16052286d8edStholo 	    if (outbuf == NULL)
16062286d8edStholo 	    {
16072286d8edStholo 		(*pb->buf->memory_error) (pb->buf);
16082286d8edStholo 		return ENOMEM;
16092286d8edStholo 	    }
16102286d8edStholo 	}
16112286d8edStholo 
16122286d8edStholo 	status = (*pb->inpfn) (pb->fnclosure, inbuf, outbuf, count);
16132286d8edStholo 	if (status != 0)
16142286d8edStholo 	    return status;
16152286d8edStholo 
16162286d8edStholo 	/* The first two bytes in the translated buffer are the real
16172286d8edStholo            length of the translated data.  */
16182286d8edStholo 	tcount = ((outbuf[0] & 0xff) << 8) + (outbuf[1] & 0xff);
16192286d8edStholo 
16202286d8edStholo 	if (tcount > count)
16212286d8edStholo 	    error (1, 0, "Input translation failure");
16222286d8edStholo 
16232286d8edStholo 	if (tcount > size)
16242286d8edStholo 	{
16252286d8edStholo 	    /* We have more data than the caller has provided space
16262286d8edStholo                for.  We need to save some of it for the next call.  */
16272286d8edStholo 
16282286d8edStholo 	    memcpy (data, outbuf + 2, size);
16292286d8edStholo 	    *got += size;
16302286d8edStholo 
16312286d8edStholo 	    pb->holdsize = tcount - size;
16322286d8edStholo 	    memcpy (pb->holdbuf, outbuf + 2 + size, tcount - size);
16332286d8edStholo 	    pb->holddata = pb->holdbuf;
16342286d8edStholo 	    pb->translated = 1;
16352286d8edStholo 
16362286d8edStholo 	    if (outbuf != stackoutbuf)
16372286d8edStholo 		free (outbuf);
16382286d8edStholo 
16392286d8edStholo 	    return 0;
16402286d8edStholo 	}
16412286d8edStholo 
16422286d8edStholo 	memcpy (data, outbuf + 2, tcount);
16432286d8edStholo 
16442286d8edStholo 	if (outbuf != stackoutbuf)
16452286d8edStholo 	    free (outbuf);
16462286d8edStholo 
16472286d8edStholo 	pb->holdsize = 0;
16482286d8edStholo 
16492286d8edStholo 	data += tcount;
16502286d8edStholo 	need -= tcount;
16512286d8edStholo 	size -= tcount;
16522286d8edStholo 	*got += tcount;
16532286d8edStholo     }
16542286d8edStholo 
16552286d8edStholo     return 0;
16562286d8edStholo }
16572286d8edStholo 
16582286d8edStholo /* Output data to a packetizing buffer.  */
16592286d8edStholo 
16602286d8edStholo static int
packetizing_buffer_output(closure,data,have,wrote)16612286d8edStholo packetizing_buffer_output (closure, data, have, wrote)
16622286d8edStholo      void *closure;
16632286d8edStholo      const char *data;
16642286d8edStholo      int have;
16652286d8edStholo      int *wrote;
16662286d8edStholo {
16672286d8edStholo     struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
16682286d8edStholo     char inbuf[BUFFER_DATA_SIZE + 2];
16692286d8edStholo     char stack_outbuf[BUFFER_DATA_SIZE + PACKET_SLOP + 4];
16702286d8edStholo     struct buffer_data *outdata;
16712286d8edStholo     char *outbuf;
16722286d8edStholo     int size, status, translated;
16732286d8edStholo 
16742286d8edStholo     if (have > BUFFER_DATA_SIZE)
16752286d8edStholo     {
16762286d8edStholo 	/* It would be easy to malloc a buffer, but I don't think this
16772286d8edStholo            case can ever arise.  */
16782286d8edStholo 	abort ();
16792286d8edStholo     }
16802286d8edStholo 
16812286d8edStholo     inbuf[0] = (have >> 8) & 0xff;
16822286d8edStholo     inbuf[1] = have & 0xff;
16832286d8edStholo     memcpy (inbuf + 2, data, have);
16842286d8edStholo 
16852286d8edStholo     size = have + 2;
16862286d8edStholo 
16872286d8edStholo     /* The output function is permitted to add up to PACKET_SLOP
16882286d8edStholo        bytes, and we need 2 bytes for the size of the translated data.
16892286d8edStholo        If we can guarantee that the result will fit in a buffer_data,
16902286d8edStholo        we translate directly into one to avoid a memcpy in buf_output.  */
16912286d8edStholo     if (size + PACKET_SLOP + 2 > BUFFER_DATA_SIZE)
16922286d8edStholo 	outbuf = stack_outbuf;
16932286d8edStholo     else
16942286d8edStholo     {
16952286d8edStholo 	outdata = get_buffer_data ();
16962286d8edStholo 	if (outdata == NULL)
16972286d8edStholo 	{
16982286d8edStholo 	    (*pb->buf->memory_error) (pb->buf);
16992286d8edStholo 	    return ENOMEM;
17002286d8edStholo 	}
17012286d8edStholo 
17022286d8edStholo 	outdata->next = NULL;
17032286d8edStholo 	outdata->bufp = outdata->text;
17042286d8edStholo 
17052286d8edStholo 	outbuf = outdata->text;
17062286d8edStholo     }
17072286d8edStholo 
17082286d8edStholo     status = (*pb->outfn) (pb->fnclosure, inbuf, outbuf + 2, size,
17092286d8edStholo 			   &translated);
17102286d8edStholo     if (status != 0)
17112286d8edStholo 	return status;
17122286d8edStholo 
17132286d8edStholo     /* The output function is permitted to add up to PACKET_SLOP
17142286d8edStholo        bytes.  */
17152286d8edStholo     if (translated > size + PACKET_SLOP)
17162286d8edStholo 	abort ();
17172286d8edStholo 
17182286d8edStholo     outbuf[0] = (translated >> 8) & 0xff;
17192286d8edStholo     outbuf[1] = translated & 0xff;
17202286d8edStholo 
17212286d8edStholo     if (outbuf == stack_outbuf)
17222286d8edStholo 	buf_output (pb->buf, outbuf, translated + 2);
17232286d8edStholo     else
17242286d8edStholo     {
17252286d8edStholo 	outdata->size = translated + 2;
17262286d8edStholo 	buf_append_data (pb->buf, outdata, outdata);
17272286d8edStholo     }
17282286d8edStholo 
17292286d8edStholo     *wrote = have;
17302286d8edStholo 
17312286d8edStholo     /* We will only be here because buf_send_output was called on the
17322286d8edStholo        packetizing buffer.  That means that we should now call
17332286d8edStholo        buf_send_output on the underlying buffer.  */
17342286d8edStholo     return buf_send_output (pb->buf);
17352286d8edStholo }
17362286d8edStholo 
17372286d8edStholo /* Flush data to a packetizing buffer.  */
17382286d8edStholo 
17392286d8edStholo static int
packetizing_buffer_flush(closure)17402286d8edStholo packetizing_buffer_flush (closure)
17412286d8edStholo      void *closure;
17422286d8edStholo {
17432286d8edStholo     struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
17442286d8edStholo 
17452286d8edStholo     /* Flush the underlying buffer.  Note that if the original call to
17462286d8edStholo        buf_flush passed 1 for the BLOCK argument, then the buffer will
17472286d8edStholo        already have been set into blocking mode, so we should always
17482286d8edStholo        pass 0 here.  */
17492286d8edStholo     return buf_flush (pb->buf, 0);
17502286d8edStholo }
17512286d8edStholo 
17522286d8edStholo /* The block routine for a packetizing buffer.  */
17532286d8edStholo 
17542286d8edStholo static int
packetizing_buffer_block(closure,block)17552286d8edStholo packetizing_buffer_block (closure, block)
17562286d8edStholo      void *closure;
17572286d8edStholo      int block;
17582286d8edStholo {
17592286d8edStholo     struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
17602286d8edStholo 
17612286d8edStholo     if (block)
17622286d8edStholo 	return set_block (pb->buf);
17632286d8edStholo     else
17642286d8edStholo 	return set_nonblock (pb->buf);
17652286d8edStholo }
17662286d8edStholo 
17672286d8edStholo /* Shut down a packetizing buffer.  */
17682286d8edStholo 
17692286d8edStholo static int
packetizing_buffer_shutdown(closure)17702286d8edStholo packetizing_buffer_shutdown (closure)
17712286d8edStholo      void *closure;
17722286d8edStholo {
17732286d8edStholo     struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
17742286d8edStholo 
17752286d8edStholo     return buf_shutdown (pb->buf);
17762286d8edStholo }
17772286d8edStholo 
177850bf276cStholo #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
1779