@@@ remote works?
[mLib] / struct / buf.h
1 /* -*-c-*-
2 *
3 * Reading and writing packet buffers
4 *
5 * (c) 2001 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the mLib utilities library.
11 *
12 * mLib is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * mLib is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 #ifndef MLIB_BUF_H
29 #define MLIB_BUF_H
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <stdarg.h>
38 #include <stddef.h>
39
40 #ifndef MLIB_BITS_H
41 # include "bits.h"
42 #endif
43
44 #ifndef MLIB_CONTROL_H
45 # include "control.h"
46 #endif
47
48 #ifndef MLIB_DSTR_H
49 # include "dstr.h"
50 #endif
51
52 #ifndef MLIB_MACROS_H
53 # include "macros.h"
54 #endif
55
56 /*----- Data structures ---------------------------------------------------*/
57
58 /* --- Buffers --- *
59 *
60 * Buffers provide a simple stream-like interface for building and parsing
61 * packets.
62 */
63
64 typedef struct buf {
65 octet *base, *p, *limit; /* Pointers to the buffer */
66 unsigned f; /* Various flags */
67 } buf;
68
69 #define BF_BROKEN 1u /* Buffer is broken */
70 #define BF_ALLOC 2u /* Buffer is dynamic */
71 #define BF_WRITE 4u /* Currently writing to buffer */
72
73 typedef struct dbuf {
74 buf _b;
75 arena *a; /* Allocation arena */
76 size_t sz; /* Allocated size */
77 } dbuf;
78
79 #define DBUF_INIT { { 0, 0, 0, BF_ALLOC | BF_WRITE}, &arena_stdlib, 0 }
80 #define DBUF_BUF(db) (&(db)->_b)
81
82 extern const struct gprintf_ops buf_printops;
83
84 /*----- Useful macros -----------------------------------------------------*/
85
86 #define BBASE(b) ((b)->base)
87 #define BLIM(b) ((b)->limit)
88 #define BCUR(b) ((b)->p)
89 #define BSZ(b) ((b)->limit - (b)->base)
90 #define BLEN(b) ((b)->p - (b)->base)
91 #define BLEFT(b) ((b)->limit - (b)->p)
92 #define BSTEP(b, sz) ((b)->p += (sz))
93 #define BBAD(b) ((b)->f & BF_BROKEN)
94 #define BOK(b) (!BBAD(b))
95
96 #if GCC_VERSION_P(8, 0)
97 # define BENSURE(b, sz) \
98 MUFFLE_WARNINGS_EXPR(GCC_WARNING("-Wint-in-bool-context"), \
99 (BBAD(b) ? -1 : (sz) > BLEFT(b) ? buf_tryextend(b, sz) : 0))
100 #else
101 # define BENSURE(b, sz) \
102 (BBAD(b) ? -1 : (sz) > BLEFT(b) ? buf_tryextend(b, sz) : 0)
103 #endif
104
105 #define DBBASE(db) BBASE(DBUF_BUF(db))
106 #define DBLIM(db) BLIM(DBUF_BUF(db))
107 #define DBCUR(db) BCUR(DBUF_BUF(db))
108 #define DBSZ(db) BSZ(DBUF_BUF(db))
109 #define DBLEN(db) BLEN(DBUF_BUF(db))
110 #define DBLEFT(db) BLEFT(DBUF_BUF(db))
111 #define DBSTEP(db, sz) BSTEP(DBUF_BUF(db), (sz))
112 #define DBBAD(db) BBAD(DBUF_BUF(db))
113 #define DBOK(db) BOK(DBUF_BUF(db))
114 #define DBENSURE(b, sz) BENSURE(DBUF_BUF(db), (sz))
115
116 #ifdef HAVE_UINT64
117 # define BUF_DOKLUDGESUFFIXES(_)
118 #else
119 # define BUF_DOKLUDGESUFFIXES(_) \
120 _(64, 64, 64) _(64, 64_B, 64b) _(64, 64_L, 64l)
121 #endif
122
123 #define BUF_DOSUFFIXES(_) DOUINTCONV(_) BUF_DOKLUDGESUFFIXES(_) _(z, z, z)
124
125 /*----- Functions provided ------------------------------------------------*/
126
127 /* --- @buf_init@ --- *
128 *
129 * Arguments: @buf *b@ = pointer to a buffer block
130 * @void *p@ = pointer to a buffer
131 * @size_t sz@ = size of the buffer
132 *
133 * Returns: ---
134 *
135 * Use: Initializes the buffer block appropriately.
136 */
137
138 extern void buf_init(buf */*b*/, void */*p*/, size_t /*sz*/);
139
140 /* --- @dbuf_create@ --- *
141 *
142 * Arguments: @dbuf *db@ = pointer to a dynamic buffer block
143 *
144 * Returns: ---
145 *
146 * Use: Initializes a dynamic buffer. The buffer is initially empty,
147 * and ready for writing.
148 */
149
150 extern void dbuf_create(dbuf */*db*/);
151
152 /* --- @dbuf_reset@ --- *
153 *
154 * Arguments: @dbuf *db@ = pointer to a buffer block
155 *
156 * Returns: ---
157 *
158 * Use: Resets a buffer so that it can be written again.
159 */
160
161 extern void dbuf_reset(dbuf */*db*/);
162
163 /* --- @dbuf_destroy@ --- *
164 *
165 * Arguments: @dbuf *db@ = pointer to a buffer block
166 *
167 * Returns: ---
168 *
169 * Use: Release all of the resources held by a dynamic buffer.
170 */
171
172 extern void dbuf_destroy(dbuf */*db*/);
173
174 /* --- @buf_break@ --- *
175 *
176 * Arguments: @buf *b@ = pointer to a buffer block
177 *
178 * Returns: Some negative value.
179 *
180 * Use: Marks a buffer as broken.
181 */
182
183 extern int buf_break(buf */*b*/);
184
185 /* --- @buf_flip@ --- *
186 *
187 * Arguments: @buf *b@ = pointer to a buffer block
188 *
189 * Returns: ---
190 *
191 * Use: Flips a buffer so that if you've just been writing to it,
192 * you can now read from the bit you've written.
193 */
194
195 extern void buf_flip(buf */*b*/);
196
197 /* --- @buf_ensure@ --- *
198 *
199 * Arguments: @buf *b@ = pointer to a buffer block
200 * @size_t sz@ = size of data wanted
201 *
202 * Returns: Zero if it worked, nonzero if there wasn't enough space.
203 *
204 * Use: Ensures that there are @sz@ bytes still in the buffer.
205 */
206
207 extern int buf_ensure(buf */*b*/, size_t /*sz*/);
208
209 /* --- @buf_tryextend@ --- *
210 *
211 * Arguments: @buf *b@ = pointer to a buffer block
212 * @size_t sz@ = size of data wanted
213 *
214 * Returns: Zero if it worked, nonzero if the buffer won't grow.
215 *
216 * Use: Extend the buffer so that at least @sz@ bytes are available.
217 * This only works if the buffer is allocated.
218 */
219
220 extern int buf_tryextend(buf */*b*/, size_t /*sz*/);
221
222 /* --- @buf_get@ --- *
223 *
224 * Arguments: @buf *b@ = pointer to a buffer block
225 * @size_t sz@ = size of the buffer
226 *
227 * Returns: Pointer to the place in the buffer.
228 *
229 * Use: Reserves a space in the buffer of the requested size, and
230 * returns its start address.
231 */
232
233 extern void *buf_get(buf */*b*/, size_t /*sz*/);
234
235 /* --- @buf_put@ --- *
236 *
237 * Arguments: @buf *b@ = pointer to a buffer block
238 * @const void *p@ = pointer to a buffer
239 * @size_t sz@ = size of the buffer
240 *
241 * Returns: Zero if it worked, nonzero if there wasn't enough space.
242 *
243 * Use: Fetches data from some place and puts it in the buffer
244 */
245
246 extern int buf_put(buf */*b*/, const void */*p*/, size_t /*sz*/);
247
248 /* --- @buf_getbyte@ --- *
249 *
250 * Arguments: @buf *b@ = pointer to a buffer block
251 *
252 * Returns: A byte, or less than zero if there wasn't a byte there.
253 *
254 * Use: Gets a single byte from a buffer.
255 */
256
257 extern int buf_getbyte(buf */*b*/);
258
259 /* --- @buf_putbyte@ --- *
260 *
261 * Arguments: @buf *b@ = pointer to a buffer block
262 * @int ch@ = byte to write
263 *
264 * Returns: Zero if OK, nonzero if there wasn't enough space.
265 *
266 * Use: Puts a single byte in a buffer.
267 */
268
269 extern int buf_putbyte(buf */*b*/, int /*ch*/);
270
271 /* --- @buf_getu{8,{16,24,32,64}{,l,b}}@ --- *
272 *
273 * Arguments: @buf *b@ = pointer to a buffer block
274 * @uintSZ *w@ = where to put the word
275 *
276 * Returns: Zero if OK, or nonzero if there wasn't a word there.
277 *
278 * Use: Gets a word of appropriate size and order from a buffer.
279 */
280
281 #define BUF_DECL_GETU_(n, W, w) \
282 extern int buf_getu##w(buf */*b*/, uint##n */*w*/);
283 DOUINTCONV(BUF_DECL_GETU_)
284
285 /* --- @buf_getk64{,l,b}@ --- *
286 *
287 * Arguments: @buf *b@ = pointer to a buffer block
288 * @kludge64 *w@ = where to put the word
289 *
290 * Returns: Zero if OK, or nonzero if there wasn't a word there.
291 *
292 * Use: Gets a word of appropriate size and order from a buffer.
293 */
294
295 extern int buf_getk64(buf */*b*/, kludge64 */*w*/);
296 extern int buf_getk64l(buf */*b*/, kludge64 */*w*/);
297 extern int buf_getk64b(buf */*b*/, kludge64 */*w*/);
298
299 /* --- @buf_putu{8,{16,24,32,64}{,l,b}}@ --- *
300 *
301 * Arguments: @buf *b@ = pointer to a buffer block
302 * @uintSZ w@ = word to write
303 *
304 * Returns: Zero if OK, or nonzero if there wasn't enough space
305 *
306 * Use: Puts a word into a buffer with appropriate size and order.
307 */
308
309 #define BUF_DECL_PUTU_(n, W, w) \
310 extern int buf_putu##w(buf */*b*/, uint##n /*w*/);
311 DOUINTCONV(BUF_DECL_PUTU_)
312
313 /* --- @buf_putk64{,l,b}@ --- *
314 *
315 * Arguments: @buf *b@ = pointer to a buffer block
316 * @kludge64 w@ = word to write
317 *
318 * Returns: Zero if OK, or nonzero if there wasn't enough space
319 *
320 * Use: Gets a word of appropriate size and order from a buffer.
321 */
322
323 extern int buf_putk64(buf */*b*/, kludge64 /*w*/);
324 extern int buf_putk64l(buf */*b*/, kludge64 /*w*/);
325 extern int buf_putk64b(buf */*b*/, kludge64 /*w*/);
326
327 /* --- @buf_getmem{8,{16,24,32,64}{,l,b},z} --- *
328 *
329 * Arguments: @buf *b@ = pointer to a buffer block
330 * @size_t *nn@ = where to put the length
331 *
332 * Returns: Pointer to the buffer data, or null.
333 *
334 * Use: Gets a chunk of memory from a buffer. The suffix is the
335 * width and byte order of the length; @z@ means null-
336 * terminated.
337 */
338
339 #define BUF_DECL_GETMEM_(n, W, w) \
340 extern void *buf_getmem##w(buf */*b*/, size_t */*nn*/);
341 BUF_DOSUFFIXES(BUF_DECL_GETMEM_)
342
343 /* --- @buf_putmem{8,{16,24,32,64}{,l,b},z} --- *
344 *
345 * Arguments: @buf *b@ = pointer to a buffer block
346 * @const void *p@ = pointer to data to write
347 * @size_t n@ = length to write
348 *
349 * Returns: Zero if OK, nonzero if there wasn't enough space.
350 *
351 * Use: Writes a chunk of data to a buffer. The suffix is the
352 * width and byte order of the length; @z@ means null-
353 * terminated.
354 */
355
356 #define BUF_DECL_PUTMEM_(n, W, w) \
357 extern int buf_putmem##w(buf */*b*/, const void */*p*/, size_t /*nn*/);
358 BUF_DOSUFFIXES(BUF_DECL_PUTMEM_)
359
360 /* --- @buf_getbuf{8,{16,24,32,64}{,l,b},z} --- *
361 *
362 * Arguments: @buf *b@ = pointer to a buffer block
363 * @buf *bb@ = where to put the result
364 *
365 * Returns: Zero if it worked, nonzero if there wasn't enough space.
366 *
367 * Use: Gets a block of data from a buffer, and writes its bounds to
368 * another buffer.
369 */
370
371 #define BUF_DECL_GETBUF_(n, W, w) \
372 extern int buf_getbuf##w(buf */*b*/, buf */*bb*/);
373 BUF_DOSUFFIXES(BUF_DECL_GETBUF_)
374
375 /* --- @buf_putbuf{8,{16,24,32,64}{,l,b},z} --- *
376 *
377 * Arguments: @buf *b@ = pointer to a buffer block
378 * @buf *bb@ = buffer to write
379 *
380 * Returns: Zero if it worked, nonzero if there wasn't enough space.
381 *
382 * Use: Puts the contents of a buffer to a buffer.
383 */
384
385 #define BUF_DECL_PUTBUF_(n, W, w) \
386 extern int buf_putbuf##w(buf */*b*/, buf */*bb*/);
387 BUF_DOSUFFIXES(BUF_DECL_PUTBUF_)
388
389 /* --- @buf_getdstr{8,{16,24,32,64}{,l,b},z} --- *
390 *
391 * Arguments: @buf *b@ = pointer to a buffer block
392 * @dstr *d@ = where to put the result
393 *
394 * Returns: Zero if it worked, nonzero if there wasn't enough space.
395 *
396 * Use: Gets a block of data from a buffer, and writes its contents
397 * to a string.
398 */
399
400 #define BUF_DECL_GETDSTR_(n, W, w) \
401 extern int buf_getdstr##w(buf */*b*/, dstr */*d*/);
402 BUF_DOSUFFIXES(BUF_DECL_GETDSTR_)
403
404 /* --- @buf_putdstr{8,{16,24,32,64}{,l,b},z} --- *
405 *
406 * Arguments: @buf *b@ = pointer to a buffer block
407 * @dstr *d@ = string to write
408 *
409 * Returns: Zero if it worked, nonzero if there wasn't enough space.
410 *
411 * Use: Puts a dynamic string to a buffer.
412 */
413
414 #define BUF_DECL_PUTDSTR_(n, W, w) \
415 extern int buf_putdstr##w(buf */*b*/, dstr */*d*/);
416 BUF_DOSUFFIXES(BUF_DECL_PUTDSTR_)
417
418 /* --- @buf_putstr{8,{16,24,32,64}{,l,b},z} --- *
419 *
420 * Arguments: @buf *b@ = pointer to a buffer block
421 * @const char *p@ = string to write
422 *
423 * Returns: Zero if it worked, nonzero if there wasn't enough space.
424 *
425 * Use: Puts a null-terminated string to a buffer.
426 */
427
428 #define BUF_DECL_PUTSTR_(n, W, w) \
429 extern int buf_putstr##w(buf */*b*/, const char */*p*/);
430 BUF_DOSUFFIXES(BUF_DECL_PUTSTR_)
431
432 /* --- @buf_putf64{,b,l} --- *
433 *
434 * Arguments: @buf *b@ = a buffer to write to
435 * @double x@ = a number to write
436 *
437 * Returns: Zero on success, @-1@ on failure (and the buffer is broken).
438 *
439 * On C89, this function can't detect negative zero so these
440 * will be silently written as positive zero.
441 *
442 * This function doesn't distinguish NaNs. Any NaN is written
443 * as a quiet NaN with all payload bits zero.
444 *
445 * A finite value with too large a magnitude to be represented
446 * is rounded to the appropriate infinity. Other finite values
447 * are rounded as necessary, in the usual IEEE 754 round-to-
448 * nearest-or-even way.
449 */
450
451 extern int buf_putf64(buf */*b*/, double /*x*/);
452 extern int buf_putf64b(buf */*b*/, double /*x*/);
453 extern int buf_putf64l(buf */*b*/, double /*x*/);
454
455 /* --- @buf_getf64{,b,l} --- *
456 *
457 * Arguments: @buf *b@ = a buffer to read from
458 * @double *x_out@ = where to put the result
459 *
460 * Returns: Zero on success, @-1@ on failure (and the buffer is broken).
461 *
462 * If the system supports NaNs, then any encoded NaN is returned
463 * as the value of @NAN@ in @<math.h>@; otherwise, this function
464 * reports failure.
465 *
466 * In general, values are rounded to the nearest available
467 * value, in the way that the system usually rounds. If the
468 * system doesn't support infinities, then any encoded infinity
469 * is reported as the largest-possible-magnitude finite value
470 * instead.
471 */
472
473 extern int buf_getf64(buf */*b*/, double *x_/*out*/);
474 extern int buf_getf64b(buf */*b*/, double *x_/*out*/);
475 extern int buf_getf64l(buf */*b*/, double *x_/*out*/);
476
477 #define BUF_ENCLOSETAG(tag, buf, mk, check, poke, lensz) \
478 MC_BEFORE(tag##__save, \
479 { (mk) = BLEN(buf); \
480 if (!BENSURE(buf, lensz)) (buf)->p += (lensz); }) \
481 MC_AFTER(tag##__poke, \
482 { size_t _delta = BLEN(buf) - (mk) + (lensz); \
483 assert(check); \
484 if (BOK(buf)) poke((buf)->base + (mk), _delta); })
485
486 #define BUF_ENCLOSEZTAG(tag, buf) \
487 MC_AFTER(tag##__zero, { buf_putbyte(buf, 0); })
488
489 #define BUF_ENCLOSENATIVETAG(tag, buf, mk, W) \
490 BUF_ENCLOSETAG(tag, buf, mk, (_delta <= MASK##W), STORE##W, SZ_##W)
491
492 #define BUF_STORESZK64(p, sz) \
493 do { kludge64 _k; ASSIGN64(_k, (sz)); STORE64_((p), _k); } while (0)
494 #define BUF_STORESZK64_B(p, sz) \
495 do { kludge64 _k; ASSIGN64(_k, (sz)); STORE64_B_((p), _k); } while (0)
496 #define BUF_STORESZK64_L(p, sz) \
497 do { kludge64 _k; ASSIGN64(_k, (sz)); STORE64_L_((p), _k); } while (0)
498 #define BUF_ENCLOSEK64TAG(tag, buf, mk, W) \
499 BUF_ENCLOSE(tag, buf, mk, 1, BUF_STORESZK##W, 8)
500
501 #define BUF_ENCLOSE8(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 8)
502 #define BUF_ENCLOSE16(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 16)
503 #define BUF_ENCLOSE16_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 16_B)
504 #define BUF_ENCLOSE16_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 16_L)
505 #define BUF_ENCLOSE24(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 24)
506 #define BUF_ENCLOSE24_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 24_B)
507 #define BUF_ENCLOSE24_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 24_L)
508 #define BUF_ENCLOSE32(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 32)
509 #define BUF_ENCLOSE32_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 32_B)
510 #define BUF_ENCLOSE32_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 32_L)
511 #ifdef HAVE_UINT64
512 # define BUF_ENCLOSE64(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 64)
513 # define BUF_ENCLOSE64_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 64_B)
514 # define BUF_ENCLOSE64_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 64_L)
515 #else
516 # define BUF_ENCLOSE64(buf, mk) BUF_ENCLOSEK64TAG(encl, buf, mk, 64)
517 # define BUF_ENCLOSE64_B(buf, mk) BUF_ENCLOSEK64TAG(encl, buf, mk, 64_B)
518 # define BUF_ENCLOSE64_L(buf, mk) BUF_ENCLOSEK64TAG(encl, buf, mk, 64_L)
519 #endif
520 #define BUF_ENCLOSEZ(buf) BUF_ENCLOSEZTAG(encl, buf)
521
522 /* --- @buf_vputstrf@ --- *
523 *
524 * Arguments: @buf *b@ = pointer to a buffer
525 * @const char *p@ = pointer to @printf@-style format string
526 * @va_list *ap@ = argument handle
527 *
528 * Returns: The number of characters written to the string, or @-1@ on
529 * failure.
530 *
531 * Use: As for @buf_putstrf@, but may be used as a back-end to user-
532 * supplied functions with @printf@-style interfaces.
533 */
534
535 extern int buf_vputstrf(buf */*b*/, const char */*p*/, va_list */*ap*/);
536
537 /* --- @buf_putstrf@ --- *
538 *
539 * Arguments: @buf *b@ = pointer to a buffer
540 * @const char *p@ = pointer to @printf@-style format string
541 * @...@ = argument handle
542 *
543 * Returns: The number of characters written to the string, or @-1@ on
544 * failure.
545 *
546 * Use: Format a string to a buffer. The resulting output is not
547 * null-terminated.
548 */
549
550 extern PRINTF_LIKE(2, 3) int buf_putstrf(buf */*b*/, const char */*p*/, ...);
551
552 /* --- @buf_{,v}putstrf{8,{16,24,32,64}{,b,l},z}@ --- *
553 *
554 * Arguments: @buf *b@ = pointer to a buffer
555 * @const char *p@ = pointer to @printf@-style format string
556 * @va_list *ap@ = argument handle
557 *
558 * Returns: The number of characters written to the string, or @-1@ on
559 * failure.
560 *
561 * Use: As for @buf_putstr@, but using a format string.
562 */
563
564 #define BUF_DECL_PUTSTRF_(n, W, w) \
565 extern int buf_vputstrf##w(buf */*b*/, \
566 const char */*p*/, va_list */*ap*/); \
567 extern PRINTF_LIKE(2, 3) \
568 int buf_putstrf##w(buf */*b*/, const char */*p*/, ...);
569 BUF_DOSUFFIXES(BUF_DECL_PUTSTRF_)
570 #undef BUF_DECL_PUTSTRF_
571
572 /*----- That's all, folks -------------------------------------------------*/
573
574 #ifdef __cplusplus
575 }
576 #endif
577
578 #endif