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