chiark / gitweb /
struct/buf.c: Add new functions `buf_alignskip' and `buf_alignfill'.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 9 Jul 2024 17:09:30 +0000 (18:09 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 9 Jul 2024 17:09:30 +0000 (18:09 +0100)
struct/buf.3.in
struct/buf.c
struct/buf.h

index 594cbddfd8f1f8fdfe02dbcac843769b51c9950f..f3c2e7f569b717f8a3d08c17fbfaca3fb4eb0700 100644 (file)
 .\" @dbuf_put
 .\" @dbuf_fill
 .
 .\" @dbuf_put
 .\" @dbuf_fill
 .
+.\" @buf_alignskip
+.\" @buf_alignfill
+.\" @dbuf_alignskip
+.\" @dbuf_alignfill
+.
 .\" @buf_getbyte
 .\" @buf_putbyte
 .\" @dbuf_getbyte
 .\" @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_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
 .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.
 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
 .
 .SS "Formatted buffer access"
 The function
index 4b02b28bc456ba64f6a0c3f7a73be2568bbe7f7a..10e05444b9b84051302b0ff719305063d6d69278 100644 (file)
@@ -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)); }
 
 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
 /* --- @{,d}buf_getbyte@ --- *
  *
  * Arguments:  @buf *b@ or @dbuf *db@ = pointer to a buffer block
index 212bd72ef459e31b2169d57c3d3ce5136aa09bb8..8201c49f1bddc06216a2e8180d5dc8ae4e4e179f 100644 (file)
@@ -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)))
 
 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
 /* --- @{,d}buf_getbyte@ --- *
  *
  * Arguments:  @buf *b@ or @dbuf *db@ = pointer to a buffer block