chiark / gitweb /
@@@ 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