]> git.proxmox.com Git - mirror_frr.git/blame - lib/buffer.c
Initial revision
[mirror_frr.git] / lib / buffer.c
CommitLineData
718e3744 1/*
2 * Buffering of output and input.
3 * Copyright (C) 1998 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
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.
11 *
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.
16 *
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.
21 */
22
23#include <zebra.h>
24
25#include "memory.h"
26#include "buffer.h"
27
28/* Make buffer data. */
29struct buffer_data *
30buffer_data_new (size_t size)
31{
32 struct buffer_data *d;
33
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);
37
38 return d;
39}
40
41void
42buffer_data_free (struct buffer_data *d)
43{
44 if (d->data)
45 XFREE (MTYPE_BUFFER_DATA, d->data);
46 XFREE (MTYPE_BUFFER_DATA, d);
47}
48
49/* Make new buffer. */
50struct buffer *
51buffer_new (size_t size)
52{
53 struct buffer *b;
54
55 b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
56 memset (b, 0, sizeof (struct buffer));
57
58 b->size = size;
59
60 return b;
61}
62
63/* Free buffer. */
64void
65buffer_free (struct buffer *b)
66{
67 struct buffer_data *d;
68 struct buffer_data *next;
69
70 d = b->head;
71 while (d)
72 {
73 next = d->next;
74 buffer_data_free (d);
75 d = next;
76 }
77
78 d = b->unused_head;
79 while (d)
80 {
81 next = d->next;
82 buffer_data_free (d);
83 d = next;
84 }
85
86 XFREE (MTYPE_BUFFER, b);
87}
88
89/* Make string clone. */
90char *
91buffer_getstr (struct buffer *b)
92{
93 return strdup ((char *)b->head->data);
94}
95
96/* Return 1 if buffer is empty. */
97int
98buffer_empty (struct buffer *b)
99{
100 if (b->tail == NULL || b->tail->cp == b->tail->sp)
101 return 1;
102 else
103 return 0;
104}
105
106/* Clear and free all allocated data. */
107void
108buffer_reset (struct buffer *b)
109{
110 struct buffer_data *data;
111 struct buffer_data *next;
112
113 for (data = b->head; data; data = next)
114 {
115 next = data->next;
116 buffer_data_free (data);
117 }
118 b->head = b->tail = NULL;
119 b->alloc = 0;
120 b->length = 0;
121}
122
123/* Add buffer_data to the end of buffer. */
124void
125buffer_add (struct buffer *b)
126{
127 struct buffer_data *d;
128
129 d = buffer_data_new (b->size);
130
131 if (b->tail == NULL)
132 {
133 d->prev = NULL;
134 d->next = NULL;
135 b->head = d;
136 b->tail = d;
137 }
138 else
139 {
140 d->prev = b->tail;
141 d->next = NULL;
142
143 b->tail->next = d;
144 b->tail = d;
145 }
146
147 b->alloc++;
148}
149
150/* Write data to buffer. */
151int
152buffer_write (struct buffer *b, u_char *ptr, size_t size)
153{
154 struct buffer_data *data;
155
156 data = b->tail;
157 b->length += size;
158
159 /* We use even last one byte of data buffer. */
160 while (size)
161 {
162 /* If there is no data buffer add it. */
163 if (data == NULL || data->cp == b->size)
164 {
165 buffer_add (b);
166 data = b->tail;
167 }
168
169 /* Last data. */
170 if (size <= (b->size - data->cp))
171 {
172 memcpy ((data->data + data->cp), ptr, size);
173
174 data->cp += size;
175 size = 0;
176 }
177 else
178 {
179 memcpy ((data->data + data->cp), ptr, (b->size - data->cp));
180
181 size -= (b->size - data->cp);
182 ptr += (b->size - data->cp);
183
184 data->cp = b->size;
185 }
186 }
187 return 1;
188}
189
190/* Insert character into the buffer. */
191int
192buffer_putc (struct buffer *b, u_char c)
193{
194 buffer_write (b, &c, 1);
195 return 1;
196}
197
198/* Insert word (2 octets) into ther buffer. */
199int
200buffer_putw (struct buffer *b, u_short c)
201{
202 buffer_write (b, (char *)&c, 2);
203 return 1;
204}
205
206/* Put string to the buffer. */
207int
208buffer_putstr (struct buffer *b, u_char *c)
209{
210 size_t size;
211
212 size = strlen ((char *)c);
213 buffer_write (b, c, size);
214 return 1;
215}
216
217/* Flush specified size to the fd. */
218void
219buffer_flush (struct buffer *b, int fd, size_t size)
220{
221 int iov_index;
222 struct iovec *iovec;
223 struct buffer_data *data;
224 struct buffer_data *out;
225 struct buffer_data *next;
226
227 iovec = malloc (sizeof (struct iovec) * b->alloc);
228 iov_index = 0;
229
230 for (data = b->head; data; data = data->next)
231 {
232 iovec[iov_index].iov_base = (char *)(data->data + data->sp);
233
234 if (size <= (data->cp - data->sp))
235 {
236 iovec[iov_index++].iov_len = size;
237 data->sp += size;
238 if (data->sp == data->cp)
239 data = data->next;
240 break;
241 }
242 else
243 {
244 iovec[iov_index++].iov_len = data->cp - data->sp;
245 size -= data->cp - data->sp;
246 data->sp = data->cp;
247 }
248 }
249
250 /* Write buffer to the fd. */
251 writev (fd, iovec, iov_index);
252
253 /* Free printed buffer data. */
254 for (out = b->head; out && out != data; out = next)
255 {
256 next = out->next;
257 if (next)
258 next->prev = NULL;
259 else
260 b->tail = next;
261 b->head = next;
262
263 buffer_data_free (out);
264 b->alloc--;
265 }
266
267 free (iovec);
268}
269
270/* Flush all buffer to the fd. */
271int
272buffer_flush_all (struct buffer *b, int fd)
273{
274 int ret;
275 struct buffer_data *d;
276 int iov_index;
277 struct iovec *iovec;
278
279 if (buffer_empty (b))
280 return 0;
281
282 iovec = malloc (sizeof (struct iovec) * b->alloc);
283 iov_index = 0;
284
285 for (d = b->head; d; d = d->next)
286 {
287 iovec[iov_index].iov_base = (char *)(d->data + d->sp);
288 iovec[iov_index].iov_len = d->cp - d->sp;
289 iov_index++;
290 }
291 ret = writev (fd, iovec, iov_index);
292
293 free (iovec);
294
295 buffer_reset (b);
296
297 return ret;
298}
299
300/* Flush all buffer to the fd. */
301int
302buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
303 int no_more_flag)
304{
305 int nbytes;
306 int iov_index;
307 struct iovec *iov;
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;
316
317 /* For erase and more data add two to b's buffer_data count.*/
318 if (b->alloc == 1)
319 iov = small_iov;
320 else
321 iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
322
323 data = b->head;
324 iov_index = 0;
325
326 /* Previously print out is performed. */
327 if (erase_flag)
328 {
329 iov[iov_index].iov_base = erase;
330 iov[iov_index].iov_len = sizeof erase;
331 iov_index++;
332 }
333
334 /* Output data. */
335 for (data = b->head; data; data = data->next)
336 {
337 iov[iov_index].iov_base = (char *)(data->data + data->sp);
338 iov[iov_index].iov_len = data->cp - data->sp;
339 iov_index++;
340 }
341
342 /* In case of `more' display need. */
343 if (! buffer_empty (b) && !no_more_flag)
344 {
345 iov[iov_index].iov_base = more;
346 iov[iov_index].iov_len = sizeof more;
347 iov_index++;
348 }
349
350 /* We use write or writev*/
351 nbytes = writev (fd, iov, iov_index);
352
353 /* Error treatment. */
354 if (nbytes < 0)
355 {
356 if (errno == EINTR)
357 ;
358 if (errno == EWOULDBLOCK)
359 ;
360 }
361
362 /* Free printed buffer data. */
363 for (out = b->head; out && out != data; out = next)
364 {
365 next = out->next;
366 if (next)
367 next->prev = NULL;
368 else
369 b->tail = next;
370 b->head = next;
371
372 buffer_data_free (out);
373 b->alloc--;
374 }
375
376 if (iov != small_iov)
377 XFREE (MTYPE_TMP, iov);
378
379 return nbytes;
380}
381
382/* Flush buffer to the file descriptor. Mainly used from vty
383 interface. */
384int
385buffer_flush_vty (struct buffer *b, int fd, int size,
386 int erase_flag, int no_more_flag)
387{
388 int nbytes;
389 int iov_index;
390 struct iovec *iov;
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;
399
400#ifdef IOV_MAX
401 int iov_size;
402 int total_size;
403 struct iovec *c_iov;
404 int c_nbytes;
405#endif /* IOV_MAX */
406
407 /* For erase and more data add two to b's buffer_data count.*/
408 if (b->alloc == 1)
409 iov = small_iov;
410 else
411 iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
412
413 data = b->head;
414 iov_index = 0;
415
416 /* Previously print out is performed. */
417 if (erase_flag)
418 {
419 iov[iov_index].iov_base = erase;
420 iov[iov_index].iov_len = sizeof erase;
421 iov_index++;
422 }
423
424 /* Output data. */
425 for (data = b->head; data; data = data->next)
426 {
427 iov[iov_index].iov_base = (char *)(data->data + data->sp);
428
429 if (size <= (data->cp - data->sp))
430 {
431 iov[iov_index++].iov_len = size;
432 data->sp += size;
433 if (data->sp == data->cp)
434 data = data->next;
435 break;
436 }
437 else
438 {
439 iov[iov_index++].iov_len = data->cp - data->sp;
440 size -= (data->cp - data->sp);
441 data->sp = data->cp;
442 }
443 }
444
445 /* In case of `more' display need. */
446 if (!buffer_empty (b) && !no_more_flag)
447 {
448 iov[iov_index].iov_base = more;
449 iov[iov_index].iov_len = sizeof more;
450 iov_index++;
451 }
452
453 /* We use write or writev*/
454
455#ifdef IOV_MAX
456 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
457 example: Solaris2.6 are defined IOV_MAX size at 16. */
458 c_iov = iov;
459 total_size = iov_index;
460 nbytes = 0;
461
462 while( total_size > 0 )
463 {
464 /* initialize write vector size at once */
465 iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
466
467 c_nbytes = writev (fd, c_iov, iov_size );
468
469 if( c_nbytes < 0 )
470 {
471 if(errno == EINTR)
472 ;
473 ;
474 if(errno == EWOULDBLOCK)
475 ;
476 ;
477 nbytes = c_nbytes;
478 break;
479
480 }
481
482 nbytes += c_nbytes;
483
484 /* move pointer io-vector */
485 c_iov += iov_size;
486 total_size -= iov_size;
487 }
488#else /* IOV_MAX */
489 nbytes = writev (fd, iov, iov_index);
490
491 /* Error treatment. */
492 if (nbytes < 0)
493 {
494 if (errno == EINTR)
495 ;
496 if (errno == EWOULDBLOCK)
497 ;
498 }
499#endif /* IOV_MAX */
500
501 /* Free printed buffer data. */
502 for (out = b->head; out && out != data; out = next)
503 {
504 next = out->next;
505 if (next)
506 next->prev = NULL;
507 else
508 b->tail = next;
509 b->head = next;
510
511 buffer_data_free (out);
512 b->alloc--;
513 }
514
515 if (iov != small_iov)
516 XFREE (MTYPE_TMP, iov);
517
518 return nbytes;
519}
520
521/* Calculate size of outputs then flush buffer to the file
522 descriptor. */
523int
524buffer_flush_window (struct buffer *b, int fd, int width, int height,
525 int erase, int no_more)
526{
527 unsigned long cp;
528 unsigned long size;
529 int lp;
530 int lineno;
531 struct buffer_data *data;
532
533 if (height >= 2)
534 height--;
535
536 /* We have to calculate how many bytes should be written. */
537 lp = 0;
538 lineno = 0;
539 size = 0;
540
541 for (data = b->head; data; data = data->next)
542 {
543 cp = data->sp;
544
545 while (cp < data->cp)
546 {
547 if (data->data[cp] == '\n' || lp == width)
548 {
549 lineno++;
550 if (lineno == height)
551 {
552 cp++;
553 size++;
554 goto flush;
555 }
556 lp = 0;
557 }
558 cp++;
559 lp++;
560 size++;
561 }
562 }
563
564 /* Write data to the file descriptor. */
565 flush:
566
567 return buffer_flush_vty (b, fd, size, erase, no_more);
568}