From: Mark Wooding Date: Tue, 9 Jul 2024 17:09:30 +0000 (+0100) Subject: struct/buf.c: Add new functions `buf_alignskip' and `buf_alignfill'. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/commitdiff_plain/7947d831c086f7cf5f60efb2c83a050f271f39d2?ds=sidebyside struct/buf.c: Add new functions `buf_alignskip' and `buf_alignfill'. --- diff --git a/struct/buf.3.in b/struct/buf.3.in index 594cbdd..f3c2e7f 100644 --- a/struct/buf.3.in +++ b/struct/buf.3.in @@ -77,6 +77,11 @@ .\" @dbuf_put .\" @dbuf_fill . +.\" @buf_alignskip +.\" @buf_alignfill +.\" @dbuf_alignskip +.\" @dbuf_alignfill +. .\" @buf_getbyte .\" @buf_putbyte .\" @dbuf_getbyte @@ -540,6 +545,9 @@ and taking a first argument of type .BI "int buf_put(buf *" b ", const void *" p ", size_t " sz ); .BI "int buf_fill(buf *" b ", int " ch ", size_t " sz ); .PP +.BI "int buf_alignskip(buf *" b ", size_t " m ", size_t " a ); +.BI "int buf_alignfill(buf *" b ", int " ch ", size_t " m ", size_t " a ); +.PP .BI "int buf_getbyte(buf *" b ); .BI "int buf_putbyte(buf *" b ", int " ch ); .PP @@ -840,6 +848,30 @@ copies of the byte to the buffer, as if by calling .BR memset (3). If it succeeds, it returns 0; otherwise it returns \-1. +.PP +The +.B buf_alignskip +function advances the buffer's position as little as possible, +so as to cause the position to be +.I a +bytes more than a multiple of +.IR m . +If +.I m +is zero then nothing is done. +The buffer contents are not altered. +The related +.B buf_alignfill +function is similar, except that it advances the buffer position by writing +copies of the byte +.IR ch , +as if by calling +.BR memset (3). +Use +.B buf_alignskip +for input and +.B buf_alignfill +for output. . .SS "Formatted buffer access" The function diff --git a/struct/buf.c b/struct/buf.c index 4b02b28..10e0544 100644 --- a/struct/buf.c +++ b/struct/buf.c @@ -223,6 +223,60 @@ int buf_fill(buf *b, int ch, size_t sz) int (dbuf_fill)(dbuf *db, int ch, size_t sz) { return (dbuf_fill(db, ch, sz)); } +/* --- @align_step@ --- * + * + * Arguments: @buf *b@ = pointer to a buffer block + * @size_t m, a@ = alignment parameters + * + * Returns: The number of bytes to skip or fill. + */ + +static size_t align_step(buf *b, size_t m, size_t a) +{ + if (m < 2) return (0); + else if (!(m&(m - 1))) return ((a - BLEN(b))&(m - 1)); + else return ((a + m - BLEN(b)%m)%m); +} + +/* --- @{,d}buf_alignskip@ --- * + * + * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block + * @size_t m, a@ = alignment multiple and offset + * + * Returns: Zero if it worked, nonzero if there wasn't enough space. + * + * Use: Advance the buffer position as little as possible such that + * it is @a@ greater than a multiple of @m@. This doesn't write + * anything to the buffer, so it's probably not suitable for + * output: use @buf_alignfill@ instead. + */ + +int buf_alignskip(buf *b, size_t m, size_t a) +{ + if (!buf_get(b, align_step(b, m, a))) return (-1); + else return (0); +} +int (dbuf_alignskip)(dbuf *db, size_t m, size_t a) + { return (dbuf_alignskip(db, m, a)); } + +/* --- @{,d}buf_alignfill@ --- * + * + * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block + * @int ch@ = fill character + * @size_t m, a@ = alignment multiple and offset + * + * Returns: Zero if it worked, nonzero if there wasn't enough space. + * + * Use: Fill the buffer with as few copies of @ch@ as possible, as if + * by @memset@, to advance the buffer position to a value @a@ + * greater than a multiple of @m@. + */ + +int buf_alignfill(buf *b, int ch, size_t m, size_t a) + { return (buf_fill(b, ch, align_step(b, m, a))); } +int (dbuf_alignfill)(dbuf *db, int ch, size_t m, size_t a) + { return (dbuf_alignfill(db, ch, m, a)); } + /* --- @{,d}buf_getbyte@ --- * * * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block diff --git a/struct/buf.h b/struct/buf.h index 212bd72..8201c49 100644 --- a/struct/buf.h +++ b/struct/buf.h @@ -289,6 +289,42 @@ extern int buf_fill(buf */*b*/, int /*ch*/, size_t /*sz*/); extern int dbuf_fill(dbuf */*db*/, int /*ch*/, size_t /*sz*/); #define dbuf_fill(db, ch, sz) (buf_fill(DBUF_BUF(db), (ch), (sz))) +/* --- @{,d}buf_alignskip@ --- * + * + * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block + * @size_t m, a@ = alignment multiple and offset + * + * Returns: Zero if it worked, nonzero if there wasn't enough space. + * + * Use: Advance the buffer position as little as possible such that + * it is @a@ greater than a multiple of @m@. This doesn't write + * anything to the buffer, so it's probably not suitable for + * output: use @buf_alignfill@ instead. + */ + +extern int buf_alignskip(buf */*b*/, size_t /*m*/, size_t /*a*/); +extern int dbuf_alignskip(dbuf */*db*/, size_t /*m*/, size_t /*a*/); +#define dbuf_alignskip(db, m, a) (buf_alignskip(DBUF_BUF(db), (m), (a))) + +/* --- @{,d}buf_alignfill@ --- * + * + * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block + * @int ch@ = fill character + * @size_t m, a@ = alignment multiple and offset + * + * Returns: Zero if it worked, nonzero if there wasn't enough space. + * + * Use: Fill the buffer with as few copies of @ch@ as possible, as if + * by @memset@, to advance the buffer position to a value @a@ + * greater than a multiple of @m@. + */ + +extern int buf_alignfill(buf */*b*/, int /*ch*/, size_t /*m*/, size_t /*a*/); +extern int (dbuf_alignfill)(dbuf */*db*/, int /*ch*/, + size_t /*m*/, size_t /*a*/); +#define dbuf_alignfill(db, ch, m, a) \ + (buf_alignfill(DBUF_BUF(db), (ch), (a), (m))) + /* --- @{,d}buf_getbyte@ --- * * * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block