1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
/* VTY I/O FIFO -- header
* Copyright (C) 2010 Chris Hall (GMCH), Highwayman
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2, or (at your
* option) any later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _ZEBRA_VIO_FIFO_H
#define _ZEBRA_VIO_FIFO_H
#include "misc.h"
#include "vargs.h"
#include <stdio.h>
#include "qstring.h"
#include "list_util.h"
/*==============================================================================
* VTY I/O FIFO -- buffering of arbitrary amounts of I/O.
*/
/*------------------------------------------------------------------------------
* Sort out VIO_FIFO_DEBUG.
*
* Set to 1 if defined, but blank.
* Set to QDEBUG if not defined.
*
* Force to 0 if VIO_FIFO_NO_DEBUG is defined and not zero.
*
* So: defaults to same as QDEBUG, but no matter what QDEBUG is set to:
*
* * can set VIO_FIFO_DEBUG == 0 to turn off debug
* * or set VIO_FIFO_DEBUG != 0 to turn on debug
* * or set VIO_FIFO_NO_DEBUG != 0 to force debug off
*/
#ifdef VIO_FIFO_DEBUG /* If defined, make it 1 or 0 */
# if IS_BLANK_OPTION(VIO_FIFO_DEBUG)
# undef VIO_FIFO_DEBUG
# define VIO_FIFO_DEBUG 1
# endif
#else /* If not defined, follow QDEBUG */
# define VIO_FIFO_DEBUG QDEBUG
#endif
#ifdef VIO_FIFO_NO_DEBUG /* Override, if defined */
# if IS_NOT_ZERO_OPTION(VIO_FIFO_NO_DEBUG)
# undef VIO_FIFO_DEBUG
# define VIO_FIFO_DEBUG 0
# endif
#endif
enum { vio_fifo_debug = VIO_FIFO_DEBUG } ;
/*==============================================================================
* Data Structures
*
* Note that we do not support an embedded fifo.
*/
typedef struct vio_fifo_lump vio_fifo_lump_t ;
typedef struct vio_fifo_lump* vio_fifo_lump ;
struct vio_fifo_lump
{
struct dl_list_pair(vio_fifo_lump) list ;
char* end ; /* end of this particular lump */
char data[] ;
} ;
struct vio_fifo
{
struct dl_base_pair(vio_fifo_lump) base ;
char** p_start ; /* -> hold_ptr/get_ptr */
char* hold_ptr ; /* p_start == &hold_ptr <=> hold mark set */
/* implicitly in the head lump, if set */
vio_fifo_lump get_lump ; /* head lump unless "hold_ptr" */
char* get_ptr ;
char** p_get_end ; /* -> lump->end/end_ptr/put_ptr */
char** p_end ; /* -> end_ptr/put_ptr */
vio_fifo_lump end_lump ; /* tail lump unless "end_ptr" */
char* end_ptr ; /* p_end == &end_ptr <=> end mark set */
char* put_ptr ; /* implicitly in the tail lump */
char* put_end ;
ulen size ; /* set when initialised */
vio_fifo_lump spare ; /* keep back one spare when clearing */
} ;
typedef struct vio_fifo vio_fifo_t ;
typedef struct vio_fifo* vio_fifo ;
enum
{
VIO_FIFO_DEFAULT_LUMP_SIZE = 4 * 1024
} ;
/*==============================================================================
* Functions
*/
extern vio_fifo vio_fifo_new(ulen size) ;
extern vio_fifo vio_fifo_free(vio_fifo vff) ;
extern void vio_fifo_clear(vio_fifo vff) ;
extern void vio_fifo_reset(vio_fifo vff) ;
Inline bool vio_fifo_is_empty(vio_fifo vff) ;
Inline bool vio_fifo_is_quite_empty(vio_fifo vff) ;
Inline bool vio_fifo_is_tail_empty(vio_fifo vff) ;
Inline bool vio_fifo_have_hold_mark(vio_fifo vff) ;
Inline bool vio_fifo_have_end_mark(vio_fifo vff) ;
extern void vio_fifo_put_string(vio_fifo vff, const char* src) ;
extern void vio_fifo_put_bytes(vio_fifo vff, const char* src, ulen n) ;
Inline void vio_fifo_put_byte(vio_fifo vff, char b) ;
extern int vio_fifo_printf(vio_fifo vff, const char* format, ...)
PRINTF_ATTRIBUTE(2, 3) ;
extern int vio_fifo_vprintf(vio_fifo vff, const char *format, va_list args) ;
extern int vio_fifo_read_nb(vio_fifo vff, int fd, ulen require, ulen request) ;
extern void vio_fifo_trim(vio_fifo vff, bool term) ;
extern ulen vio_fifo_get_bytes(vio_fifo vff, void* dst, ulen n) ;
Inline int vio_fifo_get_byte(vio_fifo vff) ;
Inline ulen vio_fifo_get(vio_fifo vff) ;
Inline void* vio_fifo_get_ptr(vio_fifo vff) ;
Inline void vio_fifo_step(vio_fifo vff, ulen step) ;
Inline ulen vio_fifo_step_get(vio_fifo vff, ulen step) ;
extern vio_fifo vio_fifo_copy(vio_fifo dst, vio_fifo src) ;
extern vio_fifo vio_fifo_copy_tail(vio_fifo dst, vio_fifo src) ;
extern vio_fifo vio_fifo_move(vio_fifo dst, vio_fifo src) ;
extern qstring vio_fifo_to_qstring(qstring dst, vio_fifo src) ;
extern int vio_fifo_write_nb(vio_fifo vff, int fd, bool all) ;
extern int vio_fifo_fwrite(vio_fifo vff, FILE* file) ;
extern void vio_fifo_skip_to_end(vio_fifo vff) ;
extern void vio_fifo_set_end_mark(vio_fifo vff) ;
extern void vio_fifo_step_end_mark(vio_fifo vff) ;
extern void vio_fifo_clear_end_mark(vio_fifo vff) ;
extern void vio_fifo_back_to_end_mark(vio_fifo vff) ;
extern void vio_fifo_set_hold_mark(vio_fifo vff) ;
extern void vio_fifo_clear_hold_mark(vio_fifo vff) ;
extern void vio_fifo_back_to_hold_mark(vio_fifo vff, on_off_b on) ;
/*==============================================================================
* Debug -- verification function
*/
Private void vio_fifo_verify(vio_fifo vff) ;
#define VIO_FIFO_DEBUG_VERIFY(vff) if (vio_fifo_debug) vio_fifo_verify(vff)
/*==============================================================================
* Inline Functions
*/
Private void vio_fifo_add_lump(vio_fifo vff) ;
Private void vio_fifo_sync_get(vio_fifo vff) ;
/*------------------------------------------------------------------------------
* Returns true <=> FIFO is empty -- at least up to the end_ptr (if any)
*
* If there is an end marker, then there may be stuff beyond there.
*
* This test of emptiness is consistent with the various get operations, which
* do not read past the end marker if there is one.
*/
Inline bool
vio_fifo_is_empty(vio_fifo vff)
{
return (vff == NULL) || (vff->get_ptr == *vff->p_end) ;
} ;
/*------------------------------------------------------------------------------
* Returns true <=> FIFO is completely empty.
*
* So, ignoring the end marker, if there is one, see if the FIFO is empty.
*
* This is equivalent to: vio_fifo_is_empty(vff) && vio_fifo_is_tail_empty(vff)
*/
Inline bool
vio_fifo_is_quite_empty(vio_fifo vff)
{
return (vff == NULL) || (vff->get_ptr == vff->put_ptr) ;
} ;
/*------------------------------------------------------------------------------
* Returns true <=> FIFO is empty beyond end_ptr (if any).
*/
Inline bool
vio_fifo_is_tail_empty(vio_fifo vff)
{
/* if vff is NULL, treat as empty !
* if end_ptr is NULL, then tail is empty !
* else tail is empty iff end_ptr == put_ptr.
*/
return (vff == NULL) || (vff->put_ptr == *vff->p_end) ;
} ;
/*------------------------------------------------------------------------------
* Test whether there is a hold mark.
*/
Inline bool
vio_fifo_have_hold_mark(vio_fifo vff)
{
return vff->p_start == &vff->hold_ptr ;
} ;
/*------------------------------------------------------------------------------
* Test whether there is an end mark.
*/
Inline bool
vio_fifo_have_end_mark(vio_fifo vff)
{
return vff->p_end == &vff->end_ptr ;
} ;
/*------------------------------------------------------------------------------
* Put one byte to the FIFO
*/
Inline void
vio_fifo_put_byte(vio_fifo vff, char b)
{
if (vff->put_ptr >= vff->put_end)
vio_fifo_add_lump(vff) ; /* traps put_ptr > put_end */
VIO_FIFO_DEBUG_VERIFY(vff) ;
*vff->put_ptr++ = b ;
} ;
/*------------------------------------------------------------------------------
* Get one byte from the FIFO.
*
* Returns: 0x00..0xFF -- byte value (as an int)
* -1 => FIFO is empty.
*/
Inline int
vio_fifo_get_byte(vio_fifo vff)
{
if (vff->get_ptr < *vff->p_get_end)
{
int ch ;
ch = (uchar)*vff->get_ptr ;
vio_fifo_step(vff, 1) ;
return ch ;
}
return -1 ;
} ;
/*------------------------------------------------------------------------------
* Get count of bytes available in the current lump.
*
* There will always be at least 1 byte available in the current lump, unless
* the FIFO is empty, or at the end mark.
*
* Returns: number of bytes available at vio_fifo_get_ptr().
*/
Inline ulen
vio_fifo_get(vio_fifo vff)
{
return *vff->p_get_end - vff->get_ptr ;
} ;
/*------------------------------------------------------------------------------
* Get pointer to bytes in the current lump.
*
* NB: to be called only after vio_fifo_get(), or vio_fifo_steo_get() have
* returned a non-zero value.
*/
Inline void*
vio_fifo_get_ptr(vio_fifo vff)
{
return vff->get_ptr ;
} ;
/*------------------------------------------------------------------------------
* Step FIFO past bytes used.
*
* Can be called after a vio_fifo_get() or vio_fifo_step_get().
*
* NB: the "step" argument MUST not exceed the "have" previously returned.
*/
Inline void
vio_fifo_step(vio_fifo vff, ulen step)
{
vff->get_ptr += step ;
if (vff->get_ptr >= *vff->p_get_end)
vio_fifo_sync_get(vff) ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
* vio_fifo_step() followed by vio_fifo_get() !
*
* Can start with a step == 0.
*/
Inline ulen
vio_fifo_step_get(vio_fifo vff, ulen step)
{
vio_fifo_step(vff, step) ;
return vio_fifo_get(vff) ;
} ;
#endif /* _ZEBRA_VIO_FIFO_H */
|