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