#include "dynamic-string.h"
#include "util.h"
-/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
- * memory starting at 'base'.
- *
- * 'base' should ordinarily be the first byte of a region obtained from
- * malloc(), but in circumstances where it can be guaranteed that 'b' will
- * never need to be expanded or freed, it can be a pointer into arbitrary
- * memory. */
-void
-ofpbuf_use(struct ofpbuf *b, void *base, size_t allocated)
+static void
+ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
+ enum ofpbuf_source source)
{
b->base = b->data = base;
b->allocated = allocated;
+ b->source = source;
b->size = 0;
b->l2 = b->l3 = b->l4 = b->l7 = NULL;
list_poison(&b->list_node);
b->private_p = NULL;
}
+/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
+ * memory starting at 'base'. 'base' should be the first byte of a region
+ * obtained from malloc(). It will be freed (with free()) if 'b' is resized or
+ * freed. */
+void
+ofpbuf_use(struct ofpbuf *b, void *base, size_t allocated)
+{
+ ofpbuf_use__(b, base, allocated, OFPBUF_MALLOC);
+}
+
+/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
+ * memory starting at 'base'. 'base' should point to a buffer on the stack.
+ * If 'b' is resized, new memory will be allocated with malloc() and 'base'
+ * will not be freed. This is useful when a small stack-allocated buffer is
+ * normally appropriate but sometimes it must be expanded.
+ *
+ * 'base' should be appropriately aligned. Using an array of uint32_t or
+ * uint64_t for the buffer is a reasonable way to ensure appropriate alignment
+ * for 32- or 64-bit data.
+ *
+ * (Nothing actually relies on 'base' being allocated on the stack. It could
+ * be static or malloc()'d memory. But stack space is the most common use
+ * case.) */
+void
+ofpbuf_use_stack(struct ofpbuf *b, void *base, size_t allocated)
+{
+ ofpbuf_use__(b, base, allocated, OFPBUF_STACK);
+}
+
+/* Initializes 'b' as an ofpbuf whose data starts at 'data' and continues for
+ * 'size' bytes. This is appropriate for an ofpbuf that will be used to
+ * inspect existing data, without moving it around or reallocating it, and
+ * generally without modifying it at all.
+ *
+ * An ofpbuf operation that requires reallocating data will assert-fail if this
+ * function was used to initialize it. */
+void
+ofpbuf_use_const(struct ofpbuf *b, const void *data, size_t size)
+{
+ ofpbuf_use__(b, (void *) data, size, OFPBUF_CONST);
+ b->size = size;
+}
+
/* Initializes 'b' as an empty ofpbuf with an initial capacity of 'size'
* bytes. */
void
void
ofpbuf_uninit(struct ofpbuf *b)
{
- if (b) {
+ if (b && b->source == OFPBUF_MALLOC) {
free(b->base);
}
}
static void
ofpbuf_resize_tailroom__(struct ofpbuf *b, size_t new_tailroom)
{
- b->allocated = ofpbuf_headroom(b) + b->size + new_tailroom;
- ofpbuf_rebase__(b, xrealloc(b->base, b->allocated));
+ size_t new_allocated;
+ void *new_base;
+
+ new_allocated = ofpbuf_headroom(b) + b->size + new_tailroom;
+
+ switch (b->source) {
+ case OFPBUF_MALLOC:
+ new_base = xrealloc(b->base, new_allocated);
+ break;
+
+ case OFPBUF_STACK:
+ new_base = xmalloc(new_allocated);
+ memcpy(new_base, b->base, MIN(new_allocated, b->allocated));
+ b->source = OFPBUF_MALLOC;
+ break;
+
+ case OFPBUF_CONST:
+ NOT_REACHED();
+
+ default:
+ NOT_REACHED();
+ }
+
+ b->allocated = new_allocated;
+ ofpbuf_rebase__(b, new_base);
}
/* Ensures that 'b' has room for at least 'size' bytes at its tail end,
}
/* Trims the size of 'b' to fit its actual content, reducing its tailroom to
- * 0. Its headroom, if any, is preserved. */
+ * 0. Its headroom, if any, is preserved.
+ *
+ * Buffers not obtained from malloc() are not resized, since that wouldn't save
+ * any memory. */
void
ofpbuf_trim(struct ofpbuf *b)
{
- if (ofpbuf_tailroom(b) > 0) {
+ if (b->source == OFPBUF_MALLOC && ofpbuf_tailroom(b) > 0) {
ofpbuf_resize_tailroom__(b, 0);
}
}
return dst;
}
+/* Parses as many pairs of hex digits as possible (possibly separated by
+ * spaces) from the beginning of 's', appending bytes for their values to 'b'.
+ * Returns the first character of 's' that is not the first of a pair of hex
+ * digits. If 'n' is nonnull, stores the number of bytes added to 'b' in
+ * '*n'. */
+char *
+ofpbuf_put_hex(struct ofpbuf *b, const char *s, size_t *n)
+{
+ size_t initial_size = b->size;
+ for (;;) {
+ uint8_t byte;
+ bool ok;
+
+ s += strspn(s, " ");
+ byte = hexits_value(s, 2, &ok);
+ if (!ok) {
+ if (n) {
+ *n = b->size - initial_size;
+ }
+ return (char *) s;
+ }
+
+ ofpbuf_put(b, &byte, 1);
+ s += 2;
+ }
+}
+
/* Reserves 'size' bytes of headroom so that they can be later allocated with
* ofpbuf_push_uninit() without reallocating the ofpbuf. */
void