2 * Buffering of output and input.
3 * Copyright (C) 1998 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2, or (at your
10 * option) any later version.
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
28 /* Make buffer data. */
30 buffer_data_new (size_t size
)
32 struct buffer_data
*d
;
34 d
= XMALLOC (MTYPE_BUFFER_DATA
, sizeof (struct buffer_data
));
35 memset (d
, 0, sizeof (struct buffer_data
));
36 d
->data
= XMALLOC (MTYPE_BUFFER_DATA
, size
);
42 buffer_data_free (struct buffer_data
*d
)
45 XFREE (MTYPE_BUFFER_DATA
, d
->data
);
46 XFREE (MTYPE_BUFFER_DATA
, d
);
49 /* Make new buffer. */
51 buffer_new (size_t size
)
55 b
= XMALLOC (MTYPE_BUFFER
, sizeof (struct buffer
));
56 memset (b
, 0, sizeof (struct buffer
));
65 buffer_free (struct buffer
*b
)
67 struct buffer_data
*d
;
68 struct buffer_data
*next
;
86 XFREE (MTYPE_BUFFER
, b
);
89 /* Make string clone. */
91 buffer_getstr (struct buffer
*b
)
93 return strdup ((char *)b
->head
->data
);
96 /* Return 1 if buffer is empty. */
98 buffer_empty (struct buffer
*b
)
100 if (b
->tail
== NULL
|| b
->tail
->cp
== b
->tail
->sp
)
106 /* Clear and free all allocated data. */
108 buffer_reset (struct buffer
*b
)
110 struct buffer_data
*data
;
111 struct buffer_data
*next
;
113 for (data
= b
->head
; data
; data
= next
)
116 buffer_data_free (data
);
118 b
->head
= b
->tail
= NULL
;
123 /* Add buffer_data to the end of buffer. */
125 buffer_add (struct buffer
*b
)
127 struct buffer_data
*d
;
129 d
= buffer_data_new (b
->size
);
150 /* Write data to buffer. */
152 buffer_write (struct buffer
*b
, u_char
*ptr
, size_t size
)
154 struct buffer_data
*data
;
159 /* We use even last one byte of data buffer. */
162 /* If there is no data buffer add it. */
163 if (data
== NULL
|| data
->cp
== b
->size
)
170 if (size
<= (b
->size
- data
->cp
))
172 memcpy ((data
->data
+ data
->cp
), ptr
, size
);
179 memcpy ((data
->data
+ data
->cp
), ptr
, (b
->size
- data
->cp
));
181 size
-= (b
->size
- data
->cp
);
182 ptr
+= (b
->size
- data
->cp
);
190 /* Insert character into the buffer. */
192 buffer_putc (struct buffer
*b
, u_char c
)
194 buffer_write (b
, &c
, 1);
198 /* Insert word (2 octets) into ther buffer. */
200 buffer_putw (struct buffer
*b
, u_short c
)
202 buffer_write (b
, (char *)&c
, 2);
206 /* Put string to the buffer. */
208 buffer_putstr (struct buffer
*b
, u_char
*c
)
212 size
= strlen ((char *)c
);
213 buffer_write (b
, c
, size
);
217 /* Flush specified size to the fd. */
219 buffer_flush (struct buffer
*b
, int fd
, size_t size
)
223 struct buffer_data
*data
;
224 struct buffer_data
*out
;
225 struct buffer_data
*next
;
227 iovec
= malloc (sizeof (struct iovec
) * b
->alloc
);
230 for (data
= b
->head
; data
; data
= data
->next
)
232 iovec
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
234 if (size
<= (data
->cp
- data
->sp
))
236 iovec
[iov_index
++].iov_len
= size
;
238 if (data
->sp
== data
->cp
)
244 iovec
[iov_index
++].iov_len
= data
->cp
- data
->sp
;
245 size
-= data
->cp
- data
->sp
;
250 /* Write buffer to the fd. */
251 writev (fd
, iovec
, iov_index
);
253 /* Free printed buffer data. */
254 for (out
= b
->head
; out
&& out
!= data
; out
= next
)
263 buffer_data_free (out
);
270 /* Flush all buffer to the fd. */
272 buffer_flush_all (struct buffer
*b
, int fd
)
275 struct buffer_data
*d
;
279 if (buffer_empty (b
))
282 iovec
= malloc (sizeof (struct iovec
) * b
->alloc
);
285 for (d
= b
->head
; d
; d
= d
->next
)
287 iovec
[iov_index
].iov_base
= (char *)(d
->data
+ d
->sp
);
288 iovec
[iov_index
].iov_len
= d
->cp
- d
->sp
;
291 ret
= writev (fd
, iovec
, iov_index
);
300 /* Flush all buffer to the fd. */
302 buffer_flush_vty_all (struct buffer
*b
, int fd
, int erase_flag
,
308 struct iovec small_iov
[3];
309 char more
[] = " --More-- ";
310 char erase
[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
311 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
312 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
313 struct buffer_data
*data
;
314 struct buffer_data
*out
;
315 struct buffer_data
*next
;
317 /* For erase and more data add two to b's buffer_data count.*/
321 iov
= XCALLOC (MTYPE_TMP
, sizeof (struct iovec
) * (b
->alloc
+ 2));
326 /* Previously print out is performed. */
329 iov
[iov_index
].iov_base
= erase
;
330 iov
[iov_index
].iov_len
= sizeof erase
;
335 for (data
= b
->head
; data
; data
= data
->next
)
337 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
338 iov
[iov_index
].iov_len
= data
->cp
- data
->sp
;
342 /* In case of `more' display need. */
343 if (! buffer_empty (b
) && !no_more_flag
)
345 iov
[iov_index
].iov_base
= more
;
346 iov
[iov_index
].iov_len
= sizeof more
;
350 /* We use write or writev*/
351 nbytes
= writev (fd
, iov
, iov_index
);
353 /* Error treatment. */
358 if (errno
== EWOULDBLOCK
)
362 /* Free printed buffer data. */
363 for (out
= b
->head
; out
&& out
!= data
; out
= next
)
372 buffer_data_free (out
);
376 if (iov
!= small_iov
)
377 XFREE (MTYPE_TMP
, iov
);
382 /* Flush buffer to the file descriptor. Mainly used from vty
385 buffer_flush_vty (struct buffer
*b
, int fd
, int size
,
386 int erase_flag
, int no_more_flag
)
391 struct iovec small_iov
[3];
392 char more
[] = " --More-- ";
393 char erase
[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
394 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
395 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
396 struct buffer_data
*data
;
397 struct buffer_data
*out
;
398 struct buffer_data
*next
;
407 /* For erase and more data add two to b's buffer_data count.*/
411 iov
= XCALLOC (MTYPE_TMP
, sizeof (struct iovec
) * (b
->alloc
+ 2));
416 /* Previously print out is performed. */
419 iov
[iov_index
].iov_base
= erase
;
420 iov
[iov_index
].iov_len
= sizeof erase
;
425 for (data
= b
->head
; data
; data
= data
->next
)
427 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
429 if (size
<= (data
->cp
- data
->sp
))
431 iov
[iov_index
++].iov_len
= size
;
433 if (data
->sp
== data
->cp
)
439 iov
[iov_index
++].iov_len
= data
->cp
- data
->sp
;
440 size
-= (data
->cp
- data
->sp
);
445 /* In case of `more' display need. */
446 if (!buffer_empty (b
) && !no_more_flag
)
448 iov
[iov_index
].iov_base
= more
;
449 iov
[iov_index
].iov_len
= sizeof more
;
453 /* We use write or writev*/
456 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
457 example: Solaris2.6 are defined IOV_MAX size at 16. */
459 total_size
= iov_index
;
462 while( total_size
> 0 )
464 /* initialize write vector size at once */
465 iov_size
= ( total_size
> IOV_MAX
) ? IOV_MAX
: total_size
;
467 c_nbytes
= writev (fd
, c_iov
, iov_size
);
474 if(errno
== EWOULDBLOCK
)
484 /* move pointer io-vector */
486 total_size
-= iov_size
;
489 nbytes
= writev (fd
, iov
, iov_index
);
491 /* Error treatment. */
496 if (errno
== EWOULDBLOCK
)
501 /* Free printed buffer data. */
502 for (out
= b
->head
; out
&& out
!= data
; out
= next
)
511 buffer_data_free (out
);
515 if (iov
!= small_iov
)
516 XFREE (MTYPE_TMP
, iov
);
521 /* Calculate size of outputs then flush buffer to the file
524 buffer_flush_window (struct buffer
*b
, int fd
, int width
, int height
,
525 int erase
, int no_more
)
531 struct buffer_data
*data
;
536 /* We have to calculate how many bytes should be written. */
541 for (data
= b
->head
; data
; data
= data
->next
)
545 while (cp
< data
->cp
)
547 if (data
->data
[cp
] == '\n' || lp
== width
)
550 if (lineno
== height
)
564 /* Write data to the file descriptor. */
567 return buffer_flush_vty (b
, fd
, size
, erase
, no_more
);