# Hacky makefile to compile everything and run the tests in some kind of sane order.
# V=--verbose for verbose tests.
-CFLAGS=-O3 -Wall -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I.
+CFLAGS=-O3 -Wall -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -Iccan -I.
-ALL=$(patsubst %/test, %, $(wildcard */test))
+ALL=$(patsubst ccan/%/test, ccan/%, $(wildcard ccan/*/test))
ALL_DEPENDS=$(patsubst %, %/.depends, $(ALL))
test-all: $(ALL_DEPENDS)
$(ALL_DEPENDS): %/.depends: %/_info
@$< depends > $@ || ( rm -f $@; exit 1 )
-test-%: ccan_tools/run_tests
+test-ccan/%: tools/run_tests
@echo Testing $*...
- @if ccan_tools/run_tests $(V) $* | grep ^'not ok'; then exit 1; else exit 0; fi
+ @if tools/run_tests $(V) ccan/$* | grep ^'not ok'; then exit 1; else exit 0; fi
-ccanlint: ccan_tools/ccanlint/ccanlint
+ccanlint: tools/ccanlint/ccanlint
-clean: ccan_tools-clean
- rm -f `find . -name '*.o'`
+clean: tools-clean
+ rm -f `find . -name '*.o'` `find . -name '.depends'`
-include ccan_tools/Makefile
+include tools/Makefile
-ccan_tools:
+tools:
This is currently a bootstrap junkyard for ccan tools.
It is expected that some of this code, being generally useful, will be
shuffled out to their own modules over time.
-other:
+ccan:
The beginnings of a ccan repository.
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * alignof - ALIGNOF() macro to determine alignment of a type.
- *
- * Many platforms have requirements that certain types must be aligned
- * to certain address boundaries, such as ints needing to be on 4-byte
- * boundaries. Attempting to access variables with incorrect
- * alignment may cause performance loss or even program failure (eg. a
- * bus signal).
- *
- * There are times which it's useful to be able to programatically
- * access these requirements, such as for dynamic allocators.
- *
- * Example:
- * #include <stdio.h>
- * #include "alignof/alignoff.h"
- *
- * int main(int argc, char *argv[])
- * {
- * char arr[sizeof(int)];
- *
- * if ((unsigned long)arr % ALIGNOF(int)) {
- * printf("arr %p CANNOT hold an int\n", arr);
- * exit(1);
- * } else {
- * printf("arr %p CAN hold an int\n", arr);
- * exit(0);
- * }
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
- printf("build_assert\n");
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-#ifndef CCAN_ALIGNOF_H
-#define CCAN_ALIGNOF_H
-#include "config.h"
-
-/**
- * ALIGNOF - get the alignment of a type
- * @t: the type to test
- *
- * This returns a safe alignment for the given type.
- */
-#if HAVE_ALIGNOF
-/* A GCC extension. */
-#define ALIGNOF(t) __alignof__(t)
-#else
-/* Alignment by measuring structure padding. */
-#define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0)
-#endif
-
-#endif /* CCAN_ALIGNOF_H */
+++ /dev/null
-#include <stdlib.h>
-#include <stddef.h>
-#include <tap/tap.h>
-#include "alignof/alignof.h"
-
-/* Alignment is remarkably difficult to test. The rules may be more
- * complex than ALIGNOF() can know: eg. on i386 __alignof__(double) == 8, but
- * __alignof__(struct containing double) == 4.
- *
- * Technically, we can only test that we give *at least* the alignment which
- * naturally occurs, and that accesses work.
- *
- * For the moment, we work around double. */
-struct lots_of_types
-{
- char c;
- short s;
- char c2;
- int i;
- char c3;
- float f;
- char c4;
- double d;
- char c5;
-};
-
-int main(int argc, char *argv[])
-{
- struct lots_of_types lots_of_types, *lp = malloc(sizeof(*lp));
- char c;
- short s;
- char c2;
- int i;
- char c3;
- float f;
- char c4;
- double d;
-
- /* Make sure we use all the variables. */
- c = 0;
- c2 = c3 = c4 = c;
-
- plan_tests(15);
- ok1((unsigned long)&c % ALIGNOF(char) == 0);
- ok1((unsigned long)&s % ALIGNOF(short) == 0);
- ok1((unsigned long)&i % ALIGNOF(int) == 0);
- ok1((unsigned long)&f % ALIGNOF(float) == 0);
- ok1((unsigned long)&d % ALIGNOF(double) == 0);
-
- ok1((unsigned long)&lots_of_types.c % ALIGNOF(char) == 0);
- ok1((unsigned long)&lots_of_types.s % ALIGNOF(short) == 0);
- ok1((unsigned long)&lots_of_types.i % ALIGNOF(int) == 0);
- ok1((unsigned long)&lots_of_types.f % ALIGNOF(float) == 0);
- ok1(offsetof(struct lots_of_types, d) % ALIGNOF(double) == 0);
-
- ok1((unsigned long)&lp->c % ALIGNOF(char) == 0);
- ok1((unsigned long)&lp->s % ALIGNOF(short) == 0);
- ok1((unsigned long)&lp->i % ALIGNOF(int) == 0);
- ok1((unsigned long)&lp->f % ALIGNOF(float) == 0);
- ok1((unsigned long)&lp->d % ALIGNOF(double) == 0);
- exit(exit_status());
-}
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * alloc - memory allocator routines
- *
- * The alloc module implements a simple allocator which you can use to
- * dynamically allocate space within a region of memory. This can be useful
- * for suballocations within a given region, or a memory-mapped file.
- *
- * All metadata is kept within the memory handed to the allocator: you only
- * need hand the pointer and the size of the memory to each call.
- *
- * The region contents is always in offsets, so it can be mapped in different
- * places, but is not endian-safe.
- *
- * Example:
- * #include <sys/mman.h>
- * #include <unistd.h>
- * #include <sys/types.h>
- * #include <err.h>
- * #include "alloc/alloc.h"
- *
- * static void usage(const char *name)
- * {
- * errx(1, "Usage: %s --create <mapfile>\n"
- * " %s --check <mapfile>\n"
- * " %s --alloc <mapfile>\n"
- * " %s --free=<offset> <mapfile>\n", name, name, name);
- * }
- *
- * // Create a memory mapped file, and allocate from within it
- * int main(int argc, char *argv[])
- * {
- * void *a, *p;
- * int fd;
- * enum { CREATE, CHECK, ALLOC, FREE } cmd;
- *
- * if (argc != 3)
- * usage(argv[0]);
- *
- * if (strcmp(argv[1], "--create") == 0)
- * cmd = CREATE;
- * else if (strcmp(argv[1], "--check") == 0)
- * cmd = CHECK;
- * else if (strcmp(argv[1], "--alloc") == 0)
- * cmd = ALLOC;
- * else if (strncmp(argv[1], "--free=", strlen("--free=")) == 0)
- * cmd = FREE;
- * else
- * usage(argv[0]);
- *
- * if (cmd == CREATE) {
- * fd = open(argv[2], O_RDWR|O_CREAT|O_EXCL, 0600);
- * if (fd < 0)
- * err(1, "Could not create %s", argv[2]);
- * if (ftruncate(fd, 1048576) != 0)
- * err(1, "Could not set length on %s", argv[2]);
- * } else {
- * fd = open(argv[2], O_RDWR);
- * if (fd < 0)
- * err(1, "Could not open %s", argv[2]);
- * }
- *
- * a = mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_SHARED, fd,0);
- * if (a == MAP_FAILED)
- * err(1, "Could not map %s", argv[2]);
- *
- * switch (cmd) {
- * case CREATE:
- * alloc_init(a, 1048576);
- * break;
- * case CHECK:
- * if (!alloc_check(a, 1048576))
- * err(1, "Region is corrupt");
- * break;
- * case ALLOC:
- * p = alloc_get(a, 1048576, 1024, 16);
- * if (!p)
- * errx(1, "Could not allocate");
- * printf("%zu\n", (char *)p - (char *)a);
- * break;
- * case FREE:
- * p = (char *)a + atol(argv[1] + strlen("--free="));
- * alloc_free(a, 1048576, p);
- * break;
- * }
- * return 0;
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
- printf("build_assert\n");
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-#include <unistd.h>
-#include <stdint.h>
-#include <string.h>
-#include <limits.h>
-#include <assert.h>
-#include <stdlib.h>
-#include "alloc.h"
-#include "build_assert/build_assert.h"
-#include "alignof/alignof.h"
-#include "config.h"
-
-/* FIXME: We assume getpagesize() doesnt change. Remapping file with
- * different pagesize should still work. */
-
-/* FIXME: Doesn't handle non-page-aligned poolsize. */
-
-/* FIXME: Reduce. */
-#define MIN_SIZE (getpagesize() * 2)
-
-/* What's the granularity of sub-page allocs? */
-#define BITMAP_GRANULARITY 4
-
-/* File layout:
- *
- * file := pagestates pad uniform-cache metadata
- * pagestates := pages * 2-bits-per-page
- * pad := pad to next ALIGNOF(metaheader)
- *
- * metadata := metalen next-ptr metabits
- * metabits := freeblock | bitblock | uniformblock
- * freeblock := FREE +
- * bitblock := BITMAP + 2-bits-per-bit-in-page + pad-to-byte
- * uniformblock := UNIFORM + 14-bit-byte-len + bits + pad-to-byte
- */
-#define UNIFORM_CACHE_NUM 16
-struct uniform_cache
-{
- uint16_t size[UNIFORM_CACHE_NUM];
- /* These could be u32 if we're prepared to limit size. */
- unsigned long page[UNIFORM_CACHE_NUM];
-};
-
-struct metaheader
-{
- /* Next meta header, or 0 */
- unsigned long next;
- /* Bits start here. */
-};
-
-/* Assumes a is a power of two. */
-static unsigned long align_up(unsigned long x, unsigned long a)
-{
- return (x + a - 1) & ~(a - 1);
-}
-
-static unsigned long align_down(unsigned long x, unsigned long a)
-{
- return x & ~(a - 1);
-}
-
-static unsigned long div_up(unsigned long x, unsigned long a)
-{
- return (x + a - 1) / a;
-}
-
-/* It turns out that we spend a lot of time dealing with bit pairs.
- * These routines manipulate them.
- */
-static uint8_t get_bit_pair(const uint8_t *bits, unsigned long index)
-{
- return bits[index * 2 / CHAR_BIT] >> (index * 2 % CHAR_BIT) & 3;
-}
-
-static void set_bit_pair(uint8_t *bits, unsigned long index, uint8_t val)
-{
- bits[index * 2 / CHAR_BIT] &= ~(3 << (index * 2 % CHAR_BIT));
- bits[index * 2 / CHAR_BIT] |= (val << (index * 2 % CHAR_BIT));
-}
-
-/* This is used for page states and subpage allocations */
-enum alloc_state
-{
- FREE,
- TAKEN,
- TAKEN_START,
- SPECIAL, /* Sub-page allocation for page states. */
-};
-
-/* The types for subpage metadata. */
-enum sub_metadata_type
-{
- /* FREE is same as alloc state */
- BITMAP = 1, /* bitmap allocated page */
- UNIFORM, /* uniform size allocated page */
-};
-
-/* Page states are represented by bitpairs, at the start of the pool. */
-#define BITS_PER_PAGE 2
-
-/* How much metadata info per byte? */
-#define METADATA_PER_BYTE (CHAR_BIT / 2)
-
-static uint8_t *get_page_statebits(const void *pool)
-{
- return (uint8_t *)pool + sizeof(struct uniform_cache);
-}
-
-static enum alloc_state get_page_state(const void *pool, unsigned long page)
-{
- return get_bit_pair(get_page_statebits(pool), page);
-}
-
-static void set_page_state(void *pool, unsigned long page, enum alloc_state s)
-{
- set_bit_pair(get_page_statebits(pool), page, s);
-}
-
-/* The offset of metadata for a subpage allocation is found at the end
- * of the subpage */
-#define SUBPAGE_METAOFF (getpagesize() - sizeof(unsigned long))
-
-/* This is the length of metadata in bits. It consists of two bits
- * for every BITMAP_GRANULARITY of usable bytes in the page, then two
- * bits for the tailer.. */
-#define BITMAP_METABITLEN \
- ((div_up(SUBPAGE_METAOFF, BITMAP_GRANULARITY) + 1) * BITS_PER_PAGE)
-
-/* This is the length in bytes. */
-#define BITMAP_METALEN (div_up(BITMAP_METABITLEN, CHAR_BIT))
-
-static struct metaheader *first_mheader(void *pool, unsigned long poolsize)
-{
- unsigned int pagestatelen;
-
- pagestatelen = align_up(div_up(poolsize/getpagesize() * BITS_PER_PAGE,
- CHAR_BIT),
- ALIGNOF(struct metaheader));
- return (struct metaheader *)(get_page_statebits(pool) + pagestatelen);
-}
-
-static struct metaheader *next_mheader(void *pool, struct metaheader *mh)
-{
- if (!mh->next)
- return NULL;
-
- return (struct metaheader *)((char *)pool + mh->next);
-}
-
-static unsigned long pool_offset(void *pool, void *p)
-{
- return (char *)p - (char *)pool;
-}
-
-void alloc_init(void *pool, unsigned long poolsize)
-{
- /* FIXME: Alignment assumptions about pool. */
- unsigned long len, i;
- struct metaheader *mh;
-
- if (poolsize < MIN_SIZE)
- return;
-
- mh = first_mheader(pool, poolsize);
-
- /* Mark all page states FREE, all uniform caches zero, and all of
- * metaheader bitmap which takes rest of first page. */
- len = align_up(pool_offset(pool, mh + 1), getpagesize());
- BUILD_ASSERT(FREE == 0);
- memset(pool, 0, len);
-
- /* Mark the pagestate and metadata page(s) allocated. */
- set_page_state(pool, 0, TAKEN_START);
- for (i = 1; i < div_up(len, getpagesize()); i++)
- set_page_state(pool, i, TAKEN);
-}
-
-/* Two bits per element, representing page states. Returns 0 on fail.
- * off is used to allocate from subpage bitmaps, which use the first 2
- * bits as the type, so the real bitmap is offset by 1. */
-static unsigned long alloc_from_bitmap(uint8_t *bits, unsigned long off,
- unsigned long elems,
- unsigned long want, unsigned long align)
-{
- long i;
- unsigned long free;
-
- free = 0;
- /* We allocate from far end, to increase ability to expand metadata. */
- for (i = elems - 1; i >= 0; i--) {
- switch (get_bit_pair(bits, off+i)) {
- case FREE:
- if (++free >= want) {
- unsigned long j;
-
- /* They might ask for large alignment. */
- if (align && i % align)
- continue;
-
- set_bit_pair(bits, off+i, TAKEN_START);
- for (j = i+1; j < i + want; j++)
- set_bit_pair(bits, off+j, TAKEN);
- return off+i;
- }
- break;
- case SPECIAL:
- case TAKEN_START:
- case TAKEN:
- free = 0;
- break;
- }
- }
-
- return 0;
-}
-
-static unsigned long alloc_get_pages(void *pool, unsigned long poolsize,
- unsigned long pages, unsigned long align)
-{
- return alloc_from_bitmap(get_page_statebits(pool),
- 0, poolsize / getpagesize(), pages,
- align / getpagesize());
-}
-
-/* Offset to metadata is at end of page. */
-static unsigned long *metadata_off(void *pool, unsigned long page)
-{
- return (unsigned long *)
- ((char *)pool + (page+1)*getpagesize() - sizeof(unsigned long));
-}
-
-static uint8_t *get_page_metadata(void *pool, unsigned long page)
-{
- return (uint8_t *)pool + *metadata_off(pool, page);
-}
-
-static void set_page_metadata(void *pool, unsigned long page, uint8_t *meta)
-{
- *metadata_off(pool, page) = meta - (uint8_t *)pool;
-}
-
-static unsigned long sub_page_alloc(void *pool, unsigned long page,
- unsigned long size, unsigned long align)
-{
- uint8_t *bits = get_page_metadata(pool, page);
- unsigned long i;
- enum sub_metadata_type type;
-
- type = get_bit_pair(bits, 0);
-
- /* If this is a uniform page, we can't allocate from it. */
- if (type == UNIFORM)
- return 0;
-
- assert(type == BITMAP);
-
- /* We use a standart bitmap, but offset because of that BITMAP
- * header. */
- i = alloc_from_bitmap(bits, 1, SUBPAGE_METAOFF/BITMAP_GRANULARITY,
- div_up(size, BITMAP_GRANULARITY),
- align / BITMAP_GRANULARITY);
-
- /* Can't allocate? */
- if (i == 0)
- return 0;
-
- /* i-1 because of the header. */
- return page*getpagesize() + (i-1)*BITMAP_GRANULARITY;
-}
-
-/* We look at the page states to figure out where the allocation for this
- * metadata ends. */
-static unsigned long get_metalen(void *pool, unsigned long poolsize,
- struct metaheader *mh)
-{
- unsigned long i, first, pages = poolsize / getpagesize();
-
- first = pool_offset(pool, mh + 1)/getpagesize();
-
- for (i = first + 1; i < pages && get_page_state(pool,i) == TAKEN; i++);
-
- return i * getpagesize() - pool_offset(pool, mh + 1);
-}
-
-static unsigned int uniform_metalen(unsigned int usize)
-{
- unsigned int metalen;
-
- assert(usize < (1 << 14));
-
- /* Two bits for the header, 14 bits for size, then one bit for each
- * element the page can hold. Round up to number of bytes. */
- metalen = div_up(2 + 14 + SUBPAGE_METAOFF / usize, CHAR_BIT);
-
- /* To ensure metaheader is always aligned, round bytes up. */
- metalen = align_up(metalen, ALIGNOF(struct metaheader));
-
- return metalen;
-}
-
-static unsigned int decode_usize(uint8_t *meta)
-{
- return ((unsigned)meta[1] << (CHAR_BIT-2)) | (meta[0] >> 2);
-}
-
-static void encode_usize(uint8_t *meta, unsigned int usize)
-{
- meta[0] = (UNIFORM | (usize << 2));
- meta[1] = (usize >> (CHAR_BIT - 2));
-}
-
-static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
- struct metaheader *mh, unsigned long bytes,
- enum sub_metadata_type type)
-{
- uint8_t *meta = (uint8_t *)(mh + 1);
- unsigned long free = 0, len, i, metalen;
-
- metalen = get_metalen(pool, poolsize, mh);
-
- /* Walk through metadata looking for free. */
- for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
- switch (get_bit_pair(meta, i)) {
- case FREE:
- len = 1;
- free++;
- if (free == bytes * METADATA_PER_BYTE) {
- /* Mark this as a bitmap. */
- set_bit_pair(meta, i - free + 1, type);
- return meta + (i - free + 1)/METADATA_PER_BYTE;
- }
- break;
- case BITMAP:
- /* Skip over this allocated part. */
- len = BITMAP_METALEN * METADATA_PER_BYTE;
- free = 0;
- break;
- case UNIFORM:
- /* Figure metalen given usize. */
- len = decode_usize(meta + i / METADATA_PER_BYTE);
- len = uniform_metalen(len) * METADATA_PER_BYTE;
- free = 0;
- break;
- default:
- assert(0);
- return NULL;
- }
- }
- return NULL;
-}
-
-/* We need this many bytes of metadata. */
-static uint8_t *new_metadata(void *pool, unsigned long poolsize,
- unsigned long bytes, enum sub_metadata_type type)
-{
- struct metaheader *mh, *newmh;
- unsigned long page;
- uint8_t *meta;
-
- for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh))
- if ((meta = alloc_metaspace(pool, poolsize, mh, bytes, type)))
- return meta;
-
- /* No room for metadata? Can we expand an existing one? */
- for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
- unsigned long nextpage;
-
- /* We start on this page. */
- nextpage = pool_offset(pool, (char *)(mh+1))/getpagesize();
- /* Iterate through any other pages we own. */
- while (get_page_state(pool, ++nextpage) == TAKEN);
-
- /* Now, can we grab that page? */
- if (get_page_state(pool, nextpage) != FREE)
- continue;
-
- /* OK, expand metadata, do it again. */
- set_page_state(pool, nextpage, TAKEN);
- BUILD_ASSERT(FREE == 0);
- memset((char *)pool + nextpage*getpagesize(), 0, getpagesize());
- return alloc_metaspace(pool, poolsize, mh, bytes, type);
- }
-
- /* No metadata left at all? */
- page = alloc_get_pages(pool, poolsize, div_up(bytes, getpagesize()), 1);
- if (!page)
- return NULL;
-
- newmh = (struct metaheader *)((char *)pool + page * getpagesize());
- BUILD_ASSERT(FREE == 0);
- memset(newmh + 1, 0, getpagesize() - sizeof(*mh));
-
- /* Sew it into linked list */
- mh = first_mheader(pool,poolsize);
- newmh->next = mh->next;
- mh->next = pool_offset(pool, newmh);
-
- return alloc_metaspace(pool, poolsize, newmh, bytes, type);
-}
-
-static void alloc_free_pages(void *pool, unsigned long pagenum)
-{
- assert(get_page_state(pool, pagenum) == TAKEN_START);
- set_page_state(pool, pagenum, FREE);
- while (get_page_state(pool, ++pagenum) == TAKEN)
- set_page_state(pool, pagenum, FREE);
-}
-
-static void maybe_transform_uniform_page(void *pool, unsigned long offset)
-{
- /* FIXME: If possible and page isn't full, change to a bitmap */
-}
-
-/* Returns 0 or the size of the uniform alloc to use */
-static unsigned long suitable_for_uc(unsigned long size, unsigned long align)
-{
- unsigned long num_elems, wastage, usize;
- unsigned long bitmap_cost;
-
- if (size == 0)
- size = 1;
-
- /* Fix up silly alignments. */
- usize = align_up(size, align);
-
- /* How many can fit in this page? */
- num_elems = SUBPAGE_METAOFF / usize;
-
- /* Can happen with bigger alignments. */
- if (!num_elems)
- return 0;
-
- /* Usize maxes out at 14 bits. */
- if (usize >= (1 << 14))
- return 0;
-
- /* How many bytes would be left at the end? */
- wastage = SUBPAGE_METAOFF % usize;
-
- /* If we can get a larger allocation within alignment constraints, we
- * should do it, otherwise might as well leave wastage at the end. */
- usize += align_down(wastage / num_elems, align);
-
- /* Bitmap allocation costs 2 bits per BITMAP_GRANULARITY bytes, plus
- * however much we waste in rounding up to BITMAP_GRANULARITY. */
- bitmap_cost = 2 * div_up(size, BITMAP_GRANULARITY)
- + CHAR_BIT * (align_up(size, BITMAP_GRANULARITY) - size);
-
- /* Our cost is 1 bit, plus usize overhead */
- if (bitmap_cost < 1 + (usize - size) * CHAR_BIT)
- return 0;
-
- return usize;
-}
-
-static unsigned long uniform_alloc(void *pool, unsigned long poolsize,
- struct uniform_cache *uc,
- unsigned long ucnum)
-{
- uint8_t *metadata = get_page_metadata(pool, uc->page[ucnum]) + 2;
- unsigned long i, max;
-
- /* Simple one-bit-per-object bitmap. */
- max = SUBPAGE_METAOFF / uc->size[ucnum];
- for (i = 0; i < max; i++) {
- if (!(metadata[i / CHAR_BIT] & (1 << (i % CHAR_BIT)))) {
- metadata[i / CHAR_BIT] |= (1 << (i % CHAR_BIT));
- return uc->page[ucnum] * getpagesize()
- + i * uc->size[ucnum];
- }
- }
-
- return 0;
-}
-
-static unsigned long new_uniform_page(void *pool, unsigned long poolsize,
- unsigned long usize)
-{
- unsigned long page, metalen;
- uint8_t *metadata;
-
- page = alloc_get_pages(pool, poolsize, 1, 1);
- if (page == 0)
- return 0;
-
- metalen = uniform_metalen(usize);
-
- /* Get metadata for page. */
- metadata = new_metadata(pool, poolsize, metalen, UNIFORM);
- if (!metadata) {
- alloc_free_pages(pool, page);
- return 0;
- }
-
- encode_usize(metadata, usize);
-
- BUILD_ASSERT(FREE == 0);
- memset(metadata + 2, 0, metalen - 2);
-
- /* Actually, this is a subpage page now. */
- set_page_state(pool, page, SPECIAL);
-
- /* Set metadata pointer for page. */
- set_page_metadata(pool, page, metadata);
-
- return page;
-}
-
-static unsigned long alloc_sub_page(void *pool, unsigned long poolsize,
- unsigned long size, unsigned long align)
-{
- unsigned long i, usize;
- uint8_t *metadata;
- struct uniform_cache *uc = pool;
-
- usize = suitable_for_uc(size, align);
- if (usize) {
- /* Look for a uniform page. */
- for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
- if (uc->size[i] == usize) {
- unsigned long ret;
- ret = uniform_alloc(pool, poolsize, uc, i);
- if (ret != 0)
- return ret;
- /* OK, that one is full, remove from cache. */
- uc->size[i] = 0;
- break;
- }
- }
-
- /* OK, try a new uniform page. Use random discard for now. */
- i = random() % UNIFORM_CACHE_NUM;
- maybe_transform_uniform_page(pool, uc->page[i]);
-
- uc->page[i] = new_uniform_page(pool, poolsize, usize);
- if (uc->page[i]) {
- uc->size[i] = usize;
- return uniform_alloc(pool, poolsize, uc, i);
- }
- uc->size[i] = 0;
- }
-
- /* Look for partial page. */
- for (i = 0; i < poolsize / getpagesize(); i++) {
- unsigned long ret;
- if (get_page_state(pool, i) != SPECIAL)
- continue;
-
- ret = sub_page_alloc(pool, i, size, align);
- if (ret)
- return ret;
- }
-
- /* Create new SUBPAGE page. */
- i = alloc_get_pages(pool, poolsize, 1, 1);
- if (i == 0)
- return 0;
-
- /* Get metadata for page. */
- metadata = new_metadata(pool, poolsize, BITMAP_METALEN, BITMAP);
- if (!metadata) {
- alloc_free_pages(pool, i);
- return 0;
- }
-
- /* Actually, this is a subpage page now. */
- set_page_state(pool, i, SPECIAL);
-
- /* Set metadata pointer for page. */
- set_page_metadata(pool, i, metadata);
-
- /* Do allocation like normal */
- return sub_page_alloc(pool, i, size, align);
-}
-
-static bool bitmap_page_is_empty(uint8_t *meta)
-{
- unsigned int i;
-
- /* Skip the header (first bit of metadata). */
- for (i = 1; i < SUBPAGE_METAOFF/BITMAP_GRANULARITY+1; i++)
- if (get_bit_pair(meta, i) != FREE)
- return false;
-
- return true;
-}
-
-static bool uniform_page_is_empty(uint8_t *meta)
-{
- unsigned int i, metalen;
-
- metalen = uniform_metalen(decode_usize(meta));
-
- /* Skip the header (first two bytes of metadata). */
- for (i = 2; i < metalen + 2; i++) {
- BUILD_ASSERT(FREE == 0);
- if (meta[i])
- return false;
- }
- return true;
-}
-
-static bool special_page_is_empty(void *pool, unsigned long page)
-{
- uint8_t *meta;
- enum sub_metadata_type type;
-
- meta = get_page_metadata(pool, page);
- type = get_bit_pair(meta, 0);
-
- switch (type) {
- case UNIFORM:
- return uniform_page_is_empty(meta);
- case BITMAP:
- return bitmap_page_is_empty(meta);
- default:
- assert(0);
- }
-}
-
-static void clear_special_metadata(void *pool, unsigned long page)
-{
- uint8_t *meta;
- enum sub_metadata_type type;
-
- meta = get_page_metadata(pool, page);
- type = get_bit_pair(meta, 0);
-
- switch (type) {
- case UNIFORM:
- /* First two bytes are the header, rest is already FREE */
- BUILD_ASSERT(FREE == 0);
- memset(meta, 0, 2);
- break;
- case BITMAP:
- /* First two bits is the header. */
- BUILD_ASSERT(BITMAP_METALEN > 1);
- meta[0] = 0;
- break;
- default:
- assert(0);
- }
-}
-
-/* Returns true if we cleaned any pages. */
-static bool clean_empty_subpages(void *pool, unsigned long poolsize)
-{
- unsigned long i;
- bool progress = false;
-
- for (i = 0; i < poolsize/getpagesize(); i++) {
- if (get_page_state(pool, i) != SPECIAL)
- continue;
-
- if (special_page_is_empty(pool, i)) {
- clear_special_metadata(pool, i);
- set_page_state(pool, i, FREE);
- progress = true;
- }
- }
- return progress;
-}
-
-/* Returns true if we cleaned any pages. */
-static bool clean_metadata(void *pool, unsigned long poolsize)
-{
- struct metaheader *mh, *prev_mh = NULL;
- bool progress = false;
-
- for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
- uint8_t *meta;
- long i;
- unsigned long metalen = get_metalen(pool, poolsize, mh);
-
- meta = (uint8_t *)(mh + 1);
- BUILD_ASSERT(FREE == 0);
- for (i = metalen - 1; i > 0; i--)
- if (meta[i] != 0)
- break;
-
- /* Completely empty? */
- if (prev_mh && i == metalen) {
- alloc_free_pages(pool,
- pool_offset(pool, mh)/getpagesize());
- prev_mh->next = mh->next;
- mh = prev_mh;
- progress = true;
- } else {
- uint8_t *p;
-
- /* Some pages at end are free? */
- for (p = (uint8_t *)(mh+1) + metalen - getpagesize();
- p > meta + i;
- p -= getpagesize()) {
- set_page_state(pool,
- pool_offset(pool, p)
- / getpagesize(),
- FREE);
- progress = true;
- }
- }
- }
-
- return progress;
-}
-
-void *alloc_get(void *pool, unsigned long poolsize,
- unsigned long size, unsigned long align)
-{
- bool subpage_clean = false, metadata_clean = false;
- unsigned long ret;
-
- if (poolsize < MIN_SIZE)
- return NULL;
-
-again:
- /* Sub-page allocations have an overhead of ~12%. */
- if (size + size/8 >= getpagesize() || align >= getpagesize()) {
- unsigned long pages = div_up(size, getpagesize());
-
- ret = alloc_get_pages(pool, poolsize, pages, align)
- * getpagesize();
- } else
- ret = alloc_sub_page(pool, poolsize, size, align);
-
- if (ret != 0)
- return (char *)pool + ret;
-
- /* Allocation failed: garbage collection. */
- if (!subpage_clean) {
- subpage_clean = true;
- if (clean_empty_subpages(pool, poolsize))
- goto again;
- }
-
- if (!metadata_clean) {
- metadata_clean = true;
- if (clean_metadata(pool, poolsize))
- goto again;
- }
-
- /* FIXME: Compact metadata? */
- return NULL;
-}
-
-static void bitmap_free(void *pool, unsigned long pagenum, unsigned long off,
- uint8_t *metadata)
-{
- assert(off % BITMAP_GRANULARITY == 0);
-
- off /= BITMAP_GRANULARITY;
-
- /* Offset by one because first bit is used for header. */
- off++;
-
- set_bit_pair(metadata, off++, FREE);
- while (off < SUBPAGE_METAOFF / BITMAP_GRANULARITY
- && get_bit_pair(metadata, off) == TAKEN)
- set_bit_pair(metadata, off++, FREE);
-}
-
-static void uniform_free(void *pool, unsigned long pagenum, unsigned long off,
- uint8_t *metadata)
-{
- unsigned int usize, bit;
-
- usize = decode_usize(metadata);
- /* Must have been this size. */
- assert(off % usize == 0);
- bit = off / usize;
-
- /* Skip header. */
- metadata += 2;
-
- /* Must have been allocated. */
- assert(metadata[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT)));
- metadata[bit / CHAR_BIT] &= ~(1 << (bit % CHAR_BIT));
-}
-
-static void subpage_free(void *pool, unsigned long pagenum, void *free)
-{
- unsigned long off = (unsigned long)free % getpagesize();
- uint8_t *metadata = get_page_metadata(pool, pagenum);
- enum sub_metadata_type type;
-
- type = get_bit_pair(metadata, 0);
-
- assert(off < SUBPAGE_METAOFF);
-
- switch (type) {
- case BITMAP:
- bitmap_free(pool, pagenum, off, metadata);
- break;
- case UNIFORM:
- uniform_free(pool, pagenum, off, metadata);
- break;
- default:
- assert(0);
- }
-}
-
-void alloc_free(void *pool, unsigned long poolsize, void *free)
-{
- unsigned long pagenum;
- struct metaheader *mh;
-
- if (!free)
- return;
-
- assert(poolsize >= MIN_SIZE);
-
- mh = first_mheader(pool, poolsize);
- assert((char *)free >= (char *)(mh + 1));
- assert((char *)pool + poolsize > (char *)free);
-
- pagenum = pool_offset(pool, free) / getpagesize();
-
- if (get_page_state(pool, pagenum) == SPECIAL)
- subpage_free(pool, pagenum, free);
- else {
- assert((unsigned long)free % getpagesize() == 0);
- alloc_free_pages(pool, pagenum);
- }
-}
-
-static bool is_metadata_page(void *pool, unsigned long poolsize,
- unsigned long page)
-{
- struct metaheader *mh;
-
- for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
- unsigned long start, end;
-
- start = pool_offset(pool, mh);
- end = pool_offset(pool, (char *)(mh+1)
- + get_metalen(pool, poolsize, mh));
- if (page >= start/getpagesize() && page < end/getpagesize())
- return true;
- }
- return false;
-}
-
-static bool check_bitmap_metadata(void *pool, unsigned long *mhoff)
-{
- enum alloc_state last_state = FREE;
- unsigned int i;
-
- for (i = 0; i < SUBPAGE_METAOFF / BITMAP_GRANULARITY; i++) {
- enum alloc_state state;
-
- /* +1 because header is the first byte. */
- state = get_bit_pair((uint8_t *)pool + *mhoff, i+1);
- switch (state) {
- case SPECIAL:
- return false;
- case TAKEN:
- if (last_state == FREE)
- return false;
- break;
- default:
- break;
- }
- last_state = state;
- }
- return true;
-}
-
-static bool check_uniform_metadata(void *pool, unsigned long *mhoff)
-{
- uint8_t *meta = (uint8_t *)pool + *mhoff;
- unsigned int i, usize;
- struct uniform_cache *uc = pool;
-
- usize = decode_usize(meta);
- if (usize == 0 || suitable_for_uc(usize, 1) != usize)
- return false;
-
- /* If it's in uniform cache, make sure that agrees on size. */
- for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
- uint8_t *ucm;
-
- if (!uc->size[i])
- continue;
-
- ucm = get_page_metadata(pool, uc->page[i]);
- if (ucm != meta)
- continue;
-
- if (usize != uc->size[i])
- return false;
- }
- return true;
-}
-
-static bool check_subpage(void *pool, unsigned long poolsize,
- unsigned long page)
-{
- unsigned long *mhoff = metadata_off(pool, page);
-
- if (*mhoff + sizeof(struct metaheader) > poolsize)
- return false;
-
- if (*mhoff % ALIGNOF(struct metaheader) != 0)
- return false;
-
- /* It must point to a metadata page. */
- if (!is_metadata_page(pool, poolsize, *mhoff / getpagesize()))
- return false;
-
- /* Header at start of subpage allocation */
- switch (get_bit_pair((uint8_t *)pool + *mhoff, 0)) {
- case BITMAP:
- return check_bitmap_metadata(pool, mhoff);
- case UNIFORM:
- return check_uniform_metadata(pool, mhoff);
- default:
- return false;
- }
-
-}
-
-bool alloc_check(void *pool, unsigned long poolsize)
-{
- unsigned long i;
- struct metaheader *mh;
- enum alloc_state last_state = FREE;
- bool was_metadata = false;
-
- if (poolsize < MIN_SIZE)
- return true;
-
- if (get_page_state(pool, 0) != TAKEN_START)
- return false;
-
- /* First check metadata pages. */
- /* Metadata pages will be marked TAKEN. */
- for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
- unsigned long start, end;
-
- start = pool_offset(pool, mh);
- if (start + sizeof(*mh) > poolsize)
- return false;
-
- end = pool_offset(pool, (char *)(mh+1)
- + get_metalen(pool, poolsize, mh));
- if (end > poolsize)
- return false;
-
- /* Non-first pages should start on a page boundary. */
- if (mh != first_mheader(pool, poolsize)
- && start % getpagesize() != 0)
- return false;
-
- /* It should end on a page boundary. */
- if (end % getpagesize() != 0)
- return false;
- }
-
- for (i = 0; i < poolsize / getpagesize(); i++) {
- enum alloc_state state = get_page_state(pool, i);
- bool is_metadata = is_metadata_page(pool, poolsize,i);
-
- switch (state) {
- case FREE:
- /* metadata pages are never free. */
- if (is_metadata)
- return false;
- case TAKEN_START:
- break;
- case TAKEN:
- /* This should continue a previous block. */
- if (last_state == FREE)
- return false;
- if (is_metadata != was_metadata)
- return false;
- break;
- case SPECIAL:
- /* Check metadata pointer etc. */
- if (!check_subpage(pool, poolsize, i))
- return false;
- }
- last_state = state;
- was_metadata = is_metadata;
- }
- return true;
-}
-
-void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
-{
- struct metaheader *mh;
- struct uniform_cache *uc = pool;
- unsigned long pagebitlen, metadata_pages, count[1<<BITS_PER_PAGE], tot;
- long i;
-
- if (poolsize < MIN_SIZE) {
- fprintf(out, "Pool smaller than %u: no content\n", MIN_SIZE);
- return;
- }
-
- tot = 0;
- for (i = 0; i < UNIFORM_CACHE_NUM; i++)
- tot += (uc->size[i] != 0);
- fprintf(out, "Uniform cache (%lu entries):\n", tot);
- for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
- unsigned int j, total = 0;
- uint8_t *meta;
-
- if (!uc->size[i])
- continue;
-
- /* First two bytes are header. */
- meta = get_page_metadata(pool, uc->page[i]) + 2;
-
- for (j = 0; j < SUBPAGE_METAOFF / uc->size[i]; j++)
- if (meta[j / 8] & (1 << (j % 8)))
- total++;
-
- printf(" %u: %u/%u (%u%% density)\n",
- uc->size[j], total, SUBPAGE_METAOFF / uc->size[i],
- (total * 100) / (SUBPAGE_METAOFF / uc->size[i]));
- }
-
- memset(count, 0, sizeof(count));
- for (i = 0; i < poolsize / getpagesize(); i++)
- count[get_page_state(pool, i)]++;
-
- mh = first_mheader(pool, poolsize);
- pagebitlen = (uint8_t *)mh - get_page_statebits(pool);
- fprintf(out, "%lu bytes of page bits: FREE/TAKEN/TAKEN_START/SUBPAGE = %lu/%lu/%lu/%lu\n",
- pagebitlen, count[0], count[1], count[2], count[3]);
-
- /* One metadata page for every page of page bits. */
- metadata_pages = div_up(pagebitlen, getpagesize());
-
- /* Now do each metadata page. */
- for (; mh; mh = next_mheader(pool,mh)) {
- unsigned long free = 0, bitmapblocks = 0, uniformblocks = 0,
- len = 0, uniformlen = 0, bitmaplen = 0, metalen;
- uint8_t *meta = (uint8_t *)(mh + 1);
-
- metalen = get_metalen(pool, poolsize, mh);
- metadata_pages += (sizeof(*mh) + metalen) / getpagesize();
-
- for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
- switch (get_bit_pair(meta, i)) {
- case FREE:
- len = 1;
- free++;
- break;
- case BITMAP:
- /* Skip over this allocated part. */
- len = BITMAP_METALEN * CHAR_BIT;
- bitmapblocks++;
- bitmaplen += len;
- break;
- case UNIFORM:
- /* Skip over this part. */
- len = decode_usize(meta + i/METADATA_PER_BYTE);
- len = uniform_metalen(len) * METADATA_PER_BYTE;
- uniformblocks++;
- uniformlen += len;
- break;
- default:
- assert(0);
- }
- }
-
- fprintf(out, "Metadata %lu-%lu: %lu free, %lu bitmapblocks, %lu uniformblocks, %lu%% density\n",
- pool_offset(pool, mh),
- pool_offset(pool, (char *)(mh+1) + metalen),
- free, bitmapblocks, uniformblocks,
- (bitmaplen + uniformlen) * 100
- / (free + bitmaplen + uniformlen));
- }
-
- /* Account for total pages allocated. */
- tot = (count[1] + count[2] - metadata_pages) * getpagesize();
-
- fprintf(out, "Total metadata bytes = %lu\n",
- metadata_pages * getpagesize());
-
- /* Now do every subpage. */
- for (i = 0; i < poolsize / getpagesize(); i++) {
- uint8_t *meta;
- unsigned int j, allocated;
- enum sub_metadata_type type;
-
- if (get_page_state(pool, i) != SPECIAL)
- continue;
-
- memset(count, 0, sizeof(count));
-
- meta = get_page_metadata(pool, i);
- type = get_bit_pair(meta, 0);
-
- if (type == BITMAP) {
- for (j = 0; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY; j++)
- count[get_page_state(meta, j)]++;
- allocated = (count[1] + count[2]) * BITMAP_GRANULARITY;
- fprintf(out, "Subpage bitmap ");
- } else {
- unsigned int usize = decode_usize(meta);
-
- assert(type == UNIFORM);
- fprintf(out, "Subpage uniform (%u) ", usize);
- meta += 2;
- for (j = 0; j < SUBPAGE_METAOFF / usize; j++)
- count[!!(meta[j / 8] & (1 << (j % 8)))]++;
- allocated = count[1] * usize;
- }
- fprintf(out, "%lu: FREE/TAKEN/TAKEN_START = %lu/%lu/%lu %u%% density\n",
- i, count[0], count[1], count[2],
- allocated * 100 / getpagesize());
- tot += allocated;
- }
-
- /* This is optimistic, since we overalloc in several cases. */
- fprintf(out, "Best possible allocation density = %lu%%\n",
- tot * 100 / poolsize);
-}
+++ /dev/null
-#ifndef ALLOC_H
-#define ALLOC_H
-#include <stdio.h>
-#include <stdbool.h>
-
-void alloc_init(void *pool, unsigned long poolsize);
-void *alloc_get(void *pool, unsigned long poolsize,
- unsigned long size, unsigned long align);
-void alloc_free(void *pool, unsigned long poolsize, void *free);
-bool alloc_check(void *pool, unsigned long poolsize);
-
-void alloc_visualize(FILE *out, void *pool, unsigned long poolsize);
-#endif /* ALLOC_H */
+++ /dev/null
-#include "alloc/alloc.h"
-#include "tap/tap.h"
-#include "alloc/alloc.c"
-#include <stdlib.h>
-
-#define POOL_ORD 16
-#define POOL_SIZE (1 << POOL_ORD)
-
-#define sort(p, num, cmp) \
- qsort((p), (num), sizeof(*p), (int(*)(const void *, const void *))cmp)
-
-static int addr_cmp(void **a, void **b)
-{
- return (*a) - (*b);
-}
-
-static bool unique(void *p[], unsigned int num)
-{
- unsigned int i;
-
- for (i = 1; i < num; i++)
- if (p[i] == p[i-1])
- return false;
- return true;
-}
-
-static bool free_every_second_one(void *mem, unsigned int num, void *p[])
-{
- unsigned int i;
-
- /* Free every second one. */
- for (i = 0; i < num; i += 2) {
- alloc_free(mem, POOL_SIZE, p[i]);
- if (!alloc_check(mem, POOL_SIZE))
- return false;
- }
- for (i = 1; i < num; i += 2) {
- alloc_free(mem, POOL_SIZE, p[i]);
- if (!alloc_check(mem, POOL_SIZE))
- return false;
- }
- return true;
-}
-
-
-int main(int argc, char *argv[])
-{
- void *mem;
- unsigned int i, num, max_size;
- void *p[POOL_SIZE];
-
- plan_tests(139);
-
- /* FIXME: Needs to be page aligned for now. */
- posix_memalign(&mem, 1 << POOL_ORD, POOL_SIZE);
-
- /* Small pool, all allocs fail, even 0-length. */
- alloc_init(mem, 0);
- ok1(alloc_check(mem, 0));
- ok1(alloc_get(mem, 0, 1, 1) == NULL);
- ok1(alloc_get(mem, 0, 128, 1) == NULL);
- ok1(alloc_get(mem, 0, 0, 1) == NULL);
-
- /* Free of NULL should work. */
- alloc_free(mem, 0, NULL);
-
- alloc_init(mem, POOL_SIZE);
- ok1(alloc_check(mem, POOL_SIZE));
- /* Find largest allocation which works. */
- for (max_size = POOL_SIZE * 2; max_size; max_size--) {
- p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
- if (p[0])
- break;
- }
- ok1(max_size < POOL_SIZE);
- ok1(max_size > 0);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Free it, should be able to reallocate it. */
- alloc_free(mem, POOL_SIZE, p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
- ok1(p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
- alloc_free(mem, POOL_SIZE, p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Allocate a whole heap. */
- for (i = 0; i < POOL_SIZE; i++) {
- p[i] = alloc_get(mem, POOL_SIZE, 1, 1);
- if (!p[i])
- break;
- }
-
- /* Uncomment this for a more intuitive view of what the
- * allocator looks like after all these 1 byte allocs. */
-#if 0
- alloc_visualize(stderr, mem, POOL_SIZE);
-#endif
-
- num = i;
- /* Can't allocate this many. */
- ok1(num != POOL_SIZE);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Sort them. */
- sort(p, num, addr_cmp);
-
- /* Uniqueness check */
- ok1(unique(p, num));
-
- ok1(free_every_second_one(mem, num, p));
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Should be able to reallocate max size. */
- p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
- ok1(p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Re-initializing should be the same as freeing everything */
- alloc_init(mem, POOL_SIZE);
- ok1(alloc_check(mem, POOL_SIZE));
- p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
- ok1(p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
- alloc_free(mem, POOL_SIZE, p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Alignment constraints should be met, as long as powers of two */
- for (i = 0; i < POOL_ORD-1; i++) {
- p[i] = alloc_get(mem, POOL_SIZE, i, 1 << i);
- ok1(p[i]);
- ok1(((unsigned long)p[i] % (1 << i)) == 0);
- ok1(alloc_check(mem, POOL_SIZE));
- }
-
- for (i = 0; i < POOL_ORD-1; i++) {
- alloc_free(mem, POOL_SIZE, p[i]);
- ok1(alloc_check(mem, POOL_SIZE));
- }
-
- /* Alignment constraints for a single-byte allocation. */
- for (i = 0; i < POOL_ORD; i++) {
- p[0] = alloc_get(mem, POOL_SIZE, 1, 1 << i);
- ok1(p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
- alloc_free(mem, POOL_SIZE, p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
- }
-
- /* Alignment check for a 0-byte allocation. Corner case. */
- p[0] = alloc_get(mem, POOL_SIZE, 0, 1 << (POOL_ORD - 1));
- ok1(alloc_check(mem, POOL_SIZE));
- alloc_free(mem, POOL_SIZE, p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Force the testing of split metadata. */
- alloc_init(mem, POOL_SIZE);
- for (i = 0; i < POOL_SIZE; i++) {
- p[i] = alloc_get(mem, POOL_SIZE, getpagesize(), getpagesize());
- if (!p[i])
- break;
- }
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Sort them. */
- sort(p, i-1, addr_cmp);
-
- /* Free all but the one next to the metadata. */
- for (i = 1; p[i]; i++)
- alloc_free(mem, POOL_SIZE, p[i]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Now do a whole heap of subpage allocs. */
- for (i = 1; i < POOL_SIZE; i++) {
- p[i] = alloc_get(mem, POOL_SIZE, 1, 1);
- if (!p[i])
- break;
- }
- ok1(alloc_check(mem, POOL_SIZE));
-
- /* Free up our page next to metadata, and should be able to alloc */
- alloc_free(mem, POOL_SIZE, p[0]);
- ok1(alloc_check(mem, POOL_SIZE));
- p[0] = alloc_get(mem, POOL_SIZE, 1, 1);
- ok1(p[0]);
-
- /* Clean up. */
- for (i = 0; p[i]; i++)
- alloc_free(mem, POOL_SIZE, p[i]);
- ok1(alloc_check(mem, POOL_SIZE));
-
- return exit_status();
-}
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * build_assert - routines for build-time assertions
- *
- * This code provides routines which will cause compilation to fail should some
- * assertion be untrue: such failures are preferable to run-time assertions,
- * but much more limited since they can only depends on compile-time constants.
- *
- * These assertions are most useful when two parts of the code must be kept in
- * sync: it is better to avoid such cases if possible, but seconds best is to
- * detect invalid changes at build time.
- *
- * For example, a tricky piece of code might rely on a certain element being at
- * the start of the structure. To ensure that future changes don't break it,
- * you would catch such changes in your code like so:
- *
- * Example:
- * char *foo_string(struct foo *foo)
- * {
- * // This trick requires that the string be first in the structure
- * BUILD_ASSERT(offsetof(struct foo, string) == 0);
- * return (char *)foo;
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0)
- /* Nothing. */
- return 0;
-
- return 1;
-}
+++ /dev/null
-#ifndef CCAN_BUILD_ASSERT_H
-#define CCAN_BUILD_ASSERT_H
-
-/**
- * BUILD_ASSERT - assert a build-time dependency.
- * @cond: the compile-time condition which must be true.
- *
- * Your compile will fail if the condition isn't true, or can't be evaluated
- * by the compiler. This can only be used within a function.
- *
- * Example:
- * char *foo_to_char(struct foo *foo)
- * {
- * // This code needs string to be at start of foo.
- * BUILD_ASSERT(offsetof(struct foo, string) == 0);
- * return (char *)foo;
- * }
- */
-#define BUILD_ASSERT(cond) \
- do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
-
-/**
- * EXPR_BUILD_ASSERT - assert a build-time dependency, as an expression.
- * @cond: the compile-time condition which must be true.
- *
- * Your compile will fail if the condition isn't true, or can't be evaluated
- * by the compiler. This can be used in an expression: its value is "0".
- *
- * Example:
- * #define foo_to_char(foo) \
- * ((char *)(foo) \
- * + EXPR_BUILD_ASSERT(offsetof(struct foo, string) == 0))
- */
-#define EXPR_BUILD_ASSERT(cond) \
- (sizeof(char [1 - 2*!(cond)]) - 1)
-
-#endif /* CCAN_BUILD_ASSERT_H */
+++ /dev/null
-#include "build_assert/build_assert.h"
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- return EXPR_BUILD_ASSERT(1 == 0);
-#else
- return 0;
-#endif
-}
+++ /dev/null
-#include "build_assert/build_assert.h"
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- BUILD_ASSERT(1 == 0);
-#endif
- return 0;
-}
+++ /dev/null
-#include "build_assert/build_assert.h"
-
-int main(int argc, char *argv[])
-{
- BUILD_ASSERT(1 == 1);
- return 0;
-}
+++ /dev/null
-#include "build_assert/build_assert.h"
-#include "tap/tap.h"
-
-int main(int argc, char *argv[])
-{
- plan_tests(1);
- ok1(EXPR_BUILD_ASSERT(1 == 1) == 0);
- return exit_status();
-}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * alignof - ALIGNOF() macro to determine alignment of a type.
+ *
+ * Many platforms have requirements that certain types must be aligned
+ * to certain address boundaries, such as ints needing to be on 4-byte
+ * boundaries. Attempting to access variables with incorrect
+ * alignment may cause performance loss or even program failure (eg. a
+ * bus signal).
+ *
+ * There are times which it's useful to be able to programatically
+ * access these requirements, such as for dynamic allocators.
+ *
+ * Example:
+ * #include <stdio.h>
+ * #include "alignof/alignoff.h"
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * char arr[sizeof(int)];
+ *
+ * if ((unsigned long)arr % ALIGNOF(int)) {
+ * printf("arr %p CANNOT hold an int\n", arr);
+ * exit(1);
+ * } else {
+ * printf("arr %p CAN hold an int\n", arr);
+ * exit(0);
+ * }
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/build_assert\n");
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+#ifndef CCAN_ALIGNOF_H
+#define CCAN_ALIGNOF_H
+#include "config.h"
+
+/**
+ * ALIGNOF - get the alignment of a type
+ * @t: the type to test
+ *
+ * This returns a safe alignment for the given type.
+ */
+#if HAVE_ALIGNOF
+/* A GCC extension. */
+#define ALIGNOF(t) __alignof__(t)
+#else
+/* Alignment by measuring structure padding. */
+#define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0)
+#endif
+
+#endif /* CCAN_ALIGNOF_H */
--- /dev/null
+#include <stdlib.h>
+#include <stddef.h>
+#include <tap/tap.h>
+#include "alignof/alignof.h"
+
+/* Alignment is remarkably difficult to test. The rules may be more
+ * complex than ALIGNOF() can know: eg. on i386 __alignof__(double) == 8, but
+ * __alignof__(struct containing double) == 4.
+ *
+ * Technically, we can only test that we give *at least* the alignment which
+ * naturally occurs, and that accesses work.
+ *
+ * For the moment, we work around double. */
+struct lots_of_types
+{
+ char c;
+ short s;
+ char c2;
+ int i;
+ char c3;
+ float f;
+ char c4;
+ double d;
+ char c5;
+};
+
+int main(int argc, char *argv[])
+{
+ struct lots_of_types lots_of_types, *lp = malloc(sizeof(*lp));
+ char c;
+ short s;
+ char c2;
+ int i;
+ char c3;
+ float f;
+ char c4;
+ double d;
+
+ /* Make sure we use all the variables. */
+ c = 0;
+ c2 = c3 = c4 = c;
+
+ plan_tests(15);
+ ok1((unsigned long)&c % ALIGNOF(char) == 0);
+ ok1((unsigned long)&s % ALIGNOF(short) == 0);
+ ok1((unsigned long)&i % ALIGNOF(int) == 0);
+ ok1((unsigned long)&f % ALIGNOF(float) == 0);
+ ok1((unsigned long)&d % ALIGNOF(double) == 0);
+
+ ok1((unsigned long)&lots_of_types.c % ALIGNOF(char) == 0);
+ ok1((unsigned long)&lots_of_types.s % ALIGNOF(short) == 0);
+ ok1((unsigned long)&lots_of_types.i % ALIGNOF(int) == 0);
+ ok1((unsigned long)&lots_of_types.f % ALIGNOF(float) == 0);
+ ok1(offsetof(struct lots_of_types, d) % ALIGNOF(double) == 0);
+
+ ok1((unsigned long)&lp->c % ALIGNOF(char) == 0);
+ ok1((unsigned long)&lp->s % ALIGNOF(short) == 0);
+ ok1((unsigned long)&lp->i % ALIGNOF(int) == 0);
+ ok1((unsigned long)&lp->f % ALIGNOF(float) == 0);
+ ok1((unsigned long)&lp->d % ALIGNOF(double) == 0);
+ exit(exit_status());
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * alloc - memory allocator routines
+ *
+ * The alloc module implements a simple allocator which you can use to
+ * dynamically allocate space within a region of memory. This can be useful
+ * for suballocations within a given region, or a memory-mapped file.
+ *
+ * All metadata is kept within the memory handed to the allocator: you only
+ * need hand the pointer and the size of the memory to each call.
+ *
+ * The region contents is always in offsets, so it can be mapped in different
+ * places, but is not endian-safe.
+ *
+ * Example:
+ * #include <sys/mman.h>
+ * #include <unistd.h>
+ * #include <sys/types.h>
+ * #include <err.h>
+ * #include "alloc/alloc.h"
+ *
+ * static void usage(const char *name)
+ * {
+ * errx(1, "Usage: %s --create <mapfile>\n"
+ * " %s --check <mapfile>\n"
+ * " %s --alloc <mapfile>\n"
+ * " %s --free=<offset> <mapfile>\n", name, name, name);
+ * }
+ *
+ * // Create a memory mapped file, and allocate from within it
+ * int main(int argc, char *argv[])
+ * {
+ * void *a, *p;
+ * int fd;
+ * enum { CREATE, CHECK, ALLOC, FREE } cmd;
+ *
+ * if (argc != 3)
+ * usage(argv[0]);
+ *
+ * if (strcmp(argv[1], "--create") == 0)
+ * cmd = CREATE;
+ * else if (strcmp(argv[1], "--check") == 0)
+ * cmd = CHECK;
+ * else if (strcmp(argv[1], "--alloc") == 0)
+ * cmd = ALLOC;
+ * else if (strncmp(argv[1], "--free=", strlen("--free=")) == 0)
+ * cmd = FREE;
+ * else
+ * usage(argv[0]);
+ *
+ * if (cmd == CREATE) {
+ * fd = open(argv[2], O_RDWR|O_CREAT|O_EXCL, 0600);
+ * if (fd < 0)
+ * err(1, "Could not create %s", argv[2]);
+ * if (ftruncate(fd, 1048576) != 0)
+ * err(1, "Could not set length on %s", argv[2]);
+ * } else {
+ * fd = open(argv[2], O_RDWR);
+ * if (fd < 0)
+ * err(1, "Could not open %s", argv[2]);
+ * }
+ *
+ * a = mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_SHARED, fd,0);
+ * if (a == MAP_FAILED)
+ * err(1, "Could not map %s", argv[2]);
+ *
+ * switch (cmd) {
+ * case CREATE:
+ * alloc_init(a, 1048576);
+ * break;
+ * case CHECK:
+ * if (!alloc_check(a, 1048576))
+ * err(1, "Region is corrupt");
+ * break;
+ * case ALLOC:
+ * p = alloc_get(a, 1048576, 1024, 16);
+ * if (!p)
+ * errx(1, "Could not allocate");
+ * printf("%zu\n", (char *)p - (char *)a);
+ * break;
+ * case FREE:
+ * p = (char *)a + atol(argv[1] + strlen("--free="));
+ * alloc_free(a, 1048576, p);
+ * break;
+ * }
+ * return 0;
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/build_assert\n");
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "alloc.h"
+#include "build_assert/build_assert.h"
+#include "alignof/alignof.h"
+#include "config.h"
+
+/* FIXME: We assume getpagesize() doesnt change. Remapping file with
+ * different pagesize should still work. */
+
+/* FIXME: Doesn't handle non-page-aligned poolsize. */
+
+/* FIXME: Reduce. */
+#define MIN_SIZE (getpagesize() * 2)
+
+/* What's the granularity of sub-page allocs? */
+#define BITMAP_GRANULARITY 4
+
+/* File layout:
+ *
+ * file := pagestates pad uniform-cache metadata
+ * pagestates := pages * 2-bits-per-page
+ * pad := pad to next ALIGNOF(metaheader)
+ *
+ * metadata := metalen next-ptr metabits
+ * metabits := freeblock | bitblock | uniformblock
+ * freeblock := FREE +
+ * bitblock := BITMAP + 2-bits-per-bit-in-page + pad-to-byte
+ * uniformblock := UNIFORM + 14-bit-byte-len + bits + pad-to-byte
+ */
+#define UNIFORM_CACHE_NUM 16
+struct uniform_cache
+{
+ uint16_t size[UNIFORM_CACHE_NUM];
+ /* These could be u32 if we're prepared to limit size. */
+ unsigned long page[UNIFORM_CACHE_NUM];
+};
+
+struct metaheader
+{
+ /* Next meta header, or 0 */
+ unsigned long next;
+ /* Bits start here. */
+};
+
+/* Assumes a is a power of two. */
+static unsigned long align_up(unsigned long x, unsigned long a)
+{
+ return (x + a - 1) & ~(a - 1);
+}
+
+static unsigned long align_down(unsigned long x, unsigned long a)
+{
+ return x & ~(a - 1);
+}
+
+static unsigned long div_up(unsigned long x, unsigned long a)
+{
+ return (x + a - 1) / a;
+}
+
+/* It turns out that we spend a lot of time dealing with bit pairs.
+ * These routines manipulate them.
+ */
+static uint8_t get_bit_pair(const uint8_t *bits, unsigned long index)
+{
+ return bits[index * 2 / CHAR_BIT] >> (index * 2 % CHAR_BIT) & 3;
+}
+
+static void set_bit_pair(uint8_t *bits, unsigned long index, uint8_t val)
+{
+ bits[index * 2 / CHAR_BIT] &= ~(3 << (index * 2 % CHAR_BIT));
+ bits[index * 2 / CHAR_BIT] |= (val << (index * 2 % CHAR_BIT));
+}
+
+/* This is used for page states and subpage allocations */
+enum alloc_state
+{
+ FREE,
+ TAKEN,
+ TAKEN_START,
+ SPECIAL, /* Sub-page allocation for page states. */
+};
+
+/* The types for subpage metadata. */
+enum sub_metadata_type
+{
+ /* FREE is same as alloc state */
+ BITMAP = 1, /* bitmap allocated page */
+ UNIFORM, /* uniform size allocated page */
+};
+
+/* Page states are represented by bitpairs, at the start of the pool. */
+#define BITS_PER_PAGE 2
+
+/* How much metadata info per byte? */
+#define METADATA_PER_BYTE (CHAR_BIT / 2)
+
+static uint8_t *get_page_statebits(const void *pool)
+{
+ return (uint8_t *)pool + sizeof(struct uniform_cache);
+}
+
+static enum alloc_state get_page_state(const void *pool, unsigned long page)
+{
+ return get_bit_pair(get_page_statebits(pool), page);
+}
+
+static void set_page_state(void *pool, unsigned long page, enum alloc_state s)
+{
+ set_bit_pair(get_page_statebits(pool), page, s);
+}
+
+/* The offset of metadata for a subpage allocation is found at the end
+ * of the subpage */
+#define SUBPAGE_METAOFF (getpagesize() - sizeof(unsigned long))
+
+/* This is the length of metadata in bits. It consists of two bits
+ * for every BITMAP_GRANULARITY of usable bytes in the page, then two
+ * bits for the tailer.. */
+#define BITMAP_METABITLEN \
+ ((div_up(SUBPAGE_METAOFF, BITMAP_GRANULARITY) + 1) * BITS_PER_PAGE)
+
+/* This is the length in bytes. */
+#define BITMAP_METALEN (div_up(BITMAP_METABITLEN, CHAR_BIT))
+
+static struct metaheader *first_mheader(void *pool, unsigned long poolsize)
+{
+ unsigned int pagestatelen;
+
+ pagestatelen = align_up(div_up(poolsize/getpagesize() * BITS_PER_PAGE,
+ CHAR_BIT),
+ ALIGNOF(struct metaheader));
+ return (struct metaheader *)(get_page_statebits(pool) + pagestatelen);
+}
+
+static struct metaheader *next_mheader(void *pool, struct metaheader *mh)
+{
+ if (!mh->next)
+ return NULL;
+
+ return (struct metaheader *)((char *)pool + mh->next);
+}
+
+static unsigned long pool_offset(void *pool, void *p)
+{
+ return (char *)p - (char *)pool;
+}
+
+void alloc_init(void *pool, unsigned long poolsize)
+{
+ /* FIXME: Alignment assumptions about pool. */
+ unsigned long len, i;
+ struct metaheader *mh;
+
+ if (poolsize < MIN_SIZE)
+ return;
+
+ mh = first_mheader(pool, poolsize);
+
+ /* Mark all page states FREE, all uniform caches zero, and all of
+ * metaheader bitmap which takes rest of first page. */
+ len = align_up(pool_offset(pool, mh + 1), getpagesize());
+ BUILD_ASSERT(FREE == 0);
+ memset(pool, 0, len);
+
+ /* Mark the pagestate and metadata page(s) allocated. */
+ set_page_state(pool, 0, TAKEN_START);
+ for (i = 1; i < div_up(len, getpagesize()); i++)
+ set_page_state(pool, i, TAKEN);
+}
+
+/* Two bits per element, representing page states. Returns 0 on fail.
+ * off is used to allocate from subpage bitmaps, which use the first 2
+ * bits as the type, so the real bitmap is offset by 1. */
+static unsigned long alloc_from_bitmap(uint8_t *bits, unsigned long off,
+ unsigned long elems,
+ unsigned long want, unsigned long align)
+{
+ long i;
+ unsigned long free;
+
+ free = 0;
+ /* We allocate from far end, to increase ability to expand metadata. */
+ for (i = elems - 1; i >= 0; i--) {
+ switch (get_bit_pair(bits, off+i)) {
+ case FREE:
+ if (++free >= want) {
+ unsigned long j;
+
+ /* They might ask for large alignment. */
+ if (align && i % align)
+ continue;
+
+ set_bit_pair(bits, off+i, TAKEN_START);
+ for (j = i+1; j < i + want; j++)
+ set_bit_pair(bits, off+j, TAKEN);
+ return off+i;
+ }
+ break;
+ case SPECIAL:
+ case TAKEN_START:
+ case TAKEN:
+ free = 0;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned long alloc_get_pages(void *pool, unsigned long poolsize,
+ unsigned long pages, unsigned long align)
+{
+ return alloc_from_bitmap(get_page_statebits(pool),
+ 0, poolsize / getpagesize(), pages,
+ align / getpagesize());
+}
+
+/* Offset to metadata is at end of page. */
+static unsigned long *metadata_off(void *pool, unsigned long page)
+{
+ return (unsigned long *)
+ ((char *)pool + (page+1)*getpagesize() - sizeof(unsigned long));
+}
+
+static uint8_t *get_page_metadata(void *pool, unsigned long page)
+{
+ return (uint8_t *)pool + *metadata_off(pool, page);
+}
+
+static void set_page_metadata(void *pool, unsigned long page, uint8_t *meta)
+{
+ *metadata_off(pool, page) = meta - (uint8_t *)pool;
+}
+
+static unsigned long sub_page_alloc(void *pool, unsigned long page,
+ unsigned long size, unsigned long align)
+{
+ uint8_t *bits = get_page_metadata(pool, page);
+ unsigned long i;
+ enum sub_metadata_type type;
+
+ type = get_bit_pair(bits, 0);
+
+ /* If this is a uniform page, we can't allocate from it. */
+ if (type == UNIFORM)
+ return 0;
+
+ assert(type == BITMAP);
+
+ /* We use a standart bitmap, but offset because of that BITMAP
+ * header. */
+ i = alloc_from_bitmap(bits, 1, SUBPAGE_METAOFF/BITMAP_GRANULARITY,
+ div_up(size, BITMAP_GRANULARITY),
+ align / BITMAP_GRANULARITY);
+
+ /* Can't allocate? */
+ if (i == 0)
+ return 0;
+
+ /* i-1 because of the header. */
+ return page*getpagesize() + (i-1)*BITMAP_GRANULARITY;
+}
+
+/* We look at the page states to figure out where the allocation for this
+ * metadata ends. */
+static unsigned long get_metalen(void *pool, unsigned long poolsize,
+ struct metaheader *mh)
+{
+ unsigned long i, first, pages = poolsize / getpagesize();
+
+ first = pool_offset(pool, mh + 1)/getpagesize();
+
+ for (i = first + 1; i < pages && get_page_state(pool,i) == TAKEN; i++);
+
+ return i * getpagesize() - pool_offset(pool, mh + 1);
+}
+
+static unsigned int uniform_metalen(unsigned int usize)
+{
+ unsigned int metalen;
+
+ assert(usize < (1 << 14));
+
+ /* Two bits for the header, 14 bits for size, then one bit for each
+ * element the page can hold. Round up to number of bytes. */
+ metalen = div_up(2 + 14 + SUBPAGE_METAOFF / usize, CHAR_BIT);
+
+ /* To ensure metaheader is always aligned, round bytes up. */
+ metalen = align_up(metalen, ALIGNOF(struct metaheader));
+
+ return metalen;
+}
+
+static unsigned int decode_usize(uint8_t *meta)
+{
+ return ((unsigned)meta[1] << (CHAR_BIT-2)) | (meta[0] >> 2);
+}
+
+static void encode_usize(uint8_t *meta, unsigned int usize)
+{
+ meta[0] = (UNIFORM | (usize << 2));
+ meta[1] = (usize >> (CHAR_BIT - 2));
+}
+
+static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
+ struct metaheader *mh, unsigned long bytes,
+ enum sub_metadata_type type)
+{
+ uint8_t *meta = (uint8_t *)(mh + 1);
+ unsigned long free = 0, len, i, metalen;
+
+ metalen = get_metalen(pool, poolsize, mh);
+
+ /* Walk through metadata looking for free. */
+ for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
+ switch (get_bit_pair(meta, i)) {
+ case FREE:
+ len = 1;
+ free++;
+ if (free == bytes * METADATA_PER_BYTE) {
+ /* Mark this as a bitmap. */
+ set_bit_pair(meta, i - free + 1, type);
+ return meta + (i - free + 1)/METADATA_PER_BYTE;
+ }
+ break;
+ case BITMAP:
+ /* Skip over this allocated part. */
+ len = BITMAP_METALEN * METADATA_PER_BYTE;
+ free = 0;
+ break;
+ case UNIFORM:
+ /* Figure metalen given usize. */
+ len = decode_usize(meta + i / METADATA_PER_BYTE);
+ len = uniform_metalen(len) * METADATA_PER_BYTE;
+ free = 0;
+ break;
+ default:
+ assert(0);
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+/* We need this many bytes of metadata. */
+static uint8_t *new_metadata(void *pool, unsigned long poolsize,
+ unsigned long bytes, enum sub_metadata_type type)
+{
+ struct metaheader *mh, *newmh;
+ unsigned long page;
+ uint8_t *meta;
+
+ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh))
+ if ((meta = alloc_metaspace(pool, poolsize, mh, bytes, type)))
+ return meta;
+
+ /* No room for metadata? Can we expand an existing one? */
+ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
+ unsigned long nextpage;
+
+ /* We start on this page. */
+ nextpage = pool_offset(pool, (char *)(mh+1))/getpagesize();
+ /* Iterate through any other pages we own. */
+ while (get_page_state(pool, ++nextpage) == TAKEN);
+
+ /* Now, can we grab that page? */
+ if (get_page_state(pool, nextpage) != FREE)
+ continue;
+
+ /* OK, expand metadata, do it again. */
+ set_page_state(pool, nextpage, TAKEN);
+ BUILD_ASSERT(FREE == 0);
+ memset((char *)pool + nextpage*getpagesize(), 0, getpagesize());
+ return alloc_metaspace(pool, poolsize, mh, bytes, type);
+ }
+
+ /* No metadata left at all? */
+ page = alloc_get_pages(pool, poolsize, div_up(bytes, getpagesize()), 1);
+ if (!page)
+ return NULL;
+
+ newmh = (struct metaheader *)((char *)pool + page * getpagesize());
+ BUILD_ASSERT(FREE == 0);
+ memset(newmh + 1, 0, getpagesize() - sizeof(*mh));
+
+ /* Sew it into linked list */
+ mh = first_mheader(pool,poolsize);
+ newmh->next = mh->next;
+ mh->next = pool_offset(pool, newmh);
+
+ return alloc_metaspace(pool, poolsize, newmh, bytes, type);
+}
+
+static void alloc_free_pages(void *pool, unsigned long pagenum)
+{
+ assert(get_page_state(pool, pagenum) == TAKEN_START);
+ set_page_state(pool, pagenum, FREE);
+ while (get_page_state(pool, ++pagenum) == TAKEN)
+ set_page_state(pool, pagenum, FREE);
+}
+
+static void maybe_transform_uniform_page(void *pool, unsigned long offset)
+{
+ /* FIXME: If possible and page isn't full, change to a bitmap */
+}
+
+/* Returns 0 or the size of the uniform alloc to use */
+static unsigned long suitable_for_uc(unsigned long size, unsigned long align)
+{
+ unsigned long num_elems, wastage, usize;
+ unsigned long bitmap_cost;
+
+ if (size == 0)
+ size = 1;
+
+ /* Fix up silly alignments. */
+ usize = align_up(size, align);
+
+ /* How many can fit in this page? */
+ num_elems = SUBPAGE_METAOFF / usize;
+
+ /* Can happen with bigger alignments. */
+ if (!num_elems)
+ return 0;
+
+ /* Usize maxes out at 14 bits. */
+ if (usize >= (1 << 14))
+ return 0;
+
+ /* How many bytes would be left at the end? */
+ wastage = SUBPAGE_METAOFF % usize;
+
+ /* If we can get a larger allocation within alignment constraints, we
+ * should do it, otherwise might as well leave wastage at the end. */
+ usize += align_down(wastage / num_elems, align);
+
+ /* Bitmap allocation costs 2 bits per BITMAP_GRANULARITY bytes, plus
+ * however much we waste in rounding up to BITMAP_GRANULARITY. */
+ bitmap_cost = 2 * div_up(size, BITMAP_GRANULARITY)
+ + CHAR_BIT * (align_up(size, BITMAP_GRANULARITY) - size);
+
+ /* Our cost is 1 bit, plus usize overhead */
+ if (bitmap_cost < 1 + (usize - size) * CHAR_BIT)
+ return 0;
+
+ return usize;
+}
+
+static unsigned long uniform_alloc(void *pool, unsigned long poolsize,
+ struct uniform_cache *uc,
+ unsigned long ucnum)
+{
+ uint8_t *metadata = get_page_metadata(pool, uc->page[ucnum]) + 2;
+ unsigned long i, max;
+
+ /* Simple one-bit-per-object bitmap. */
+ max = SUBPAGE_METAOFF / uc->size[ucnum];
+ for (i = 0; i < max; i++) {
+ if (!(metadata[i / CHAR_BIT] & (1 << (i % CHAR_BIT)))) {
+ metadata[i / CHAR_BIT] |= (1 << (i % CHAR_BIT));
+ return uc->page[ucnum] * getpagesize()
+ + i * uc->size[ucnum];
+ }
+ }
+
+ return 0;
+}
+
+static unsigned long new_uniform_page(void *pool, unsigned long poolsize,
+ unsigned long usize)
+{
+ unsigned long page, metalen;
+ uint8_t *metadata;
+
+ page = alloc_get_pages(pool, poolsize, 1, 1);
+ if (page == 0)
+ return 0;
+
+ metalen = uniform_metalen(usize);
+
+ /* Get metadata for page. */
+ metadata = new_metadata(pool, poolsize, metalen, UNIFORM);
+ if (!metadata) {
+ alloc_free_pages(pool, page);
+ return 0;
+ }
+
+ encode_usize(metadata, usize);
+
+ BUILD_ASSERT(FREE == 0);
+ memset(metadata + 2, 0, metalen - 2);
+
+ /* Actually, this is a subpage page now. */
+ set_page_state(pool, page, SPECIAL);
+
+ /* Set metadata pointer for page. */
+ set_page_metadata(pool, page, metadata);
+
+ return page;
+}
+
+static unsigned long alloc_sub_page(void *pool, unsigned long poolsize,
+ unsigned long size, unsigned long align)
+{
+ unsigned long i, usize;
+ uint8_t *metadata;
+ struct uniform_cache *uc = pool;
+
+ usize = suitable_for_uc(size, align);
+ if (usize) {
+ /* Look for a uniform page. */
+ for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
+ if (uc->size[i] == usize) {
+ unsigned long ret;
+ ret = uniform_alloc(pool, poolsize, uc, i);
+ if (ret != 0)
+ return ret;
+ /* OK, that one is full, remove from cache. */
+ uc->size[i] = 0;
+ break;
+ }
+ }
+
+ /* OK, try a new uniform page. Use random discard for now. */
+ i = random() % UNIFORM_CACHE_NUM;
+ maybe_transform_uniform_page(pool, uc->page[i]);
+
+ uc->page[i] = new_uniform_page(pool, poolsize, usize);
+ if (uc->page[i]) {
+ uc->size[i] = usize;
+ return uniform_alloc(pool, poolsize, uc, i);
+ }
+ uc->size[i] = 0;
+ }
+
+ /* Look for partial page. */
+ for (i = 0; i < poolsize / getpagesize(); i++) {
+ unsigned long ret;
+ if (get_page_state(pool, i) != SPECIAL)
+ continue;
+
+ ret = sub_page_alloc(pool, i, size, align);
+ if (ret)
+ return ret;
+ }
+
+ /* Create new SUBPAGE page. */
+ i = alloc_get_pages(pool, poolsize, 1, 1);
+ if (i == 0)
+ return 0;
+
+ /* Get metadata for page. */
+ metadata = new_metadata(pool, poolsize, BITMAP_METALEN, BITMAP);
+ if (!metadata) {
+ alloc_free_pages(pool, i);
+ return 0;
+ }
+
+ /* Actually, this is a subpage page now. */
+ set_page_state(pool, i, SPECIAL);
+
+ /* Set metadata pointer for page. */
+ set_page_metadata(pool, i, metadata);
+
+ /* Do allocation like normal */
+ return sub_page_alloc(pool, i, size, align);
+}
+
+static bool bitmap_page_is_empty(uint8_t *meta)
+{
+ unsigned int i;
+
+ /* Skip the header (first bit of metadata). */
+ for (i = 1; i < SUBPAGE_METAOFF/BITMAP_GRANULARITY+1; i++)
+ if (get_bit_pair(meta, i) != FREE)
+ return false;
+
+ return true;
+}
+
+static bool uniform_page_is_empty(uint8_t *meta)
+{
+ unsigned int i, metalen;
+
+ metalen = uniform_metalen(decode_usize(meta));
+
+ /* Skip the header (first two bytes of metadata). */
+ for (i = 2; i < metalen + 2; i++) {
+ BUILD_ASSERT(FREE == 0);
+ if (meta[i])
+ return false;
+ }
+ return true;
+}
+
+static bool special_page_is_empty(void *pool, unsigned long page)
+{
+ uint8_t *meta;
+ enum sub_metadata_type type;
+
+ meta = get_page_metadata(pool, page);
+ type = get_bit_pair(meta, 0);
+
+ switch (type) {
+ case UNIFORM:
+ return uniform_page_is_empty(meta);
+ case BITMAP:
+ return bitmap_page_is_empty(meta);
+ default:
+ assert(0);
+ }
+}
+
+static void clear_special_metadata(void *pool, unsigned long page)
+{
+ uint8_t *meta;
+ enum sub_metadata_type type;
+
+ meta = get_page_metadata(pool, page);
+ type = get_bit_pair(meta, 0);
+
+ switch (type) {
+ case UNIFORM:
+ /* First two bytes are the header, rest is already FREE */
+ BUILD_ASSERT(FREE == 0);
+ memset(meta, 0, 2);
+ break;
+ case BITMAP:
+ /* First two bits is the header. */
+ BUILD_ASSERT(BITMAP_METALEN > 1);
+ meta[0] = 0;
+ break;
+ default:
+ assert(0);
+ }
+}
+
+/* Returns true if we cleaned any pages. */
+static bool clean_empty_subpages(void *pool, unsigned long poolsize)
+{
+ unsigned long i;
+ bool progress = false;
+
+ for (i = 0; i < poolsize/getpagesize(); i++) {
+ if (get_page_state(pool, i) != SPECIAL)
+ continue;
+
+ if (special_page_is_empty(pool, i)) {
+ clear_special_metadata(pool, i);
+ set_page_state(pool, i, FREE);
+ progress = true;
+ }
+ }
+ return progress;
+}
+
+/* Returns true if we cleaned any pages. */
+static bool clean_metadata(void *pool, unsigned long poolsize)
+{
+ struct metaheader *mh, *prev_mh = NULL;
+ bool progress = false;
+
+ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
+ uint8_t *meta;
+ long i;
+ unsigned long metalen = get_metalen(pool, poolsize, mh);
+
+ meta = (uint8_t *)(mh + 1);
+ BUILD_ASSERT(FREE == 0);
+ for (i = metalen - 1; i > 0; i--)
+ if (meta[i] != 0)
+ break;
+
+ /* Completely empty? */
+ if (prev_mh && i == metalen) {
+ alloc_free_pages(pool,
+ pool_offset(pool, mh)/getpagesize());
+ prev_mh->next = mh->next;
+ mh = prev_mh;
+ progress = true;
+ } else {
+ uint8_t *p;
+
+ /* Some pages at end are free? */
+ for (p = (uint8_t *)(mh+1) + metalen - getpagesize();
+ p > meta + i;
+ p -= getpagesize()) {
+ set_page_state(pool,
+ pool_offset(pool, p)
+ / getpagesize(),
+ FREE);
+ progress = true;
+ }
+ }
+ }
+
+ return progress;
+}
+
+void *alloc_get(void *pool, unsigned long poolsize,
+ unsigned long size, unsigned long align)
+{
+ bool subpage_clean = false, metadata_clean = false;
+ unsigned long ret;
+
+ if (poolsize < MIN_SIZE)
+ return NULL;
+
+again:
+ /* Sub-page allocations have an overhead of ~12%. */
+ if (size + size/8 >= getpagesize() || align >= getpagesize()) {
+ unsigned long pages = div_up(size, getpagesize());
+
+ ret = alloc_get_pages(pool, poolsize, pages, align)
+ * getpagesize();
+ } else
+ ret = alloc_sub_page(pool, poolsize, size, align);
+
+ if (ret != 0)
+ return (char *)pool + ret;
+
+ /* Allocation failed: garbage collection. */
+ if (!subpage_clean) {
+ subpage_clean = true;
+ if (clean_empty_subpages(pool, poolsize))
+ goto again;
+ }
+
+ if (!metadata_clean) {
+ metadata_clean = true;
+ if (clean_metadata(pool, poolsize))
+ goto again;
+ }
+
+ /* FIXME: Compact metadata? */
+ return NULL;
+}
+
+static void bitmap_free(void *pool, unsigned long pagenum, unsigned long off,
+ uint8_t *metadata)
+{
+ assert(off % BITMAP_GRANULARITY == 0);
+
+ off /= BITMAP_GRANULARITY;
+
+ /* Offset by one because first bit is used for header. */
+ off++;
+
+ set_bit_pair(metadata, off++, FREE);
+ while (off < SUBPAGE_METAOFF / BITMAP_GRANULARITY
+ && get_bit_pair(metadata, off) == TAKEN)
+ set_bit_pair(metadata, off++, FREE);
+}
+
+static void uniform_free(void *pool, unsigned long pagenum, unsigned long off,
+ uint8_t *metadata)
+{
+ unsigned int usize, bit;
+
+ usize = decode_usize(metadata);
+ /* Must have been this size. */
+ assert(off % usize == 0);
+ bit = off / usize;
+
+ /* Skip header. */
+ metadata += 2;
+
+ /* Must have been allocated. */
+ assert(metadata[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT)));
+ metadata[bit / CHAR_BIT] &= ~(1 << (bit % CHAR_BIT));
+}
+
+static void subpage_free(void *pool, unsigned long pagenum, void *free)
+{
+ unsigned long off = (unsigned long)free % getpagesize();
+ uint8_t *metadata = get_page_metadata(pool, pagenum);
+ enum sub_metadata_type type;
+
+ type = get_bit_pair(metadata, 0);
+
+ assert(off < SUBPAGE_METAOFF);
+
+ switch (type) {
+ case BITMAP:
+ bitmap_free(pool, pagenum, off, metadata);
+ break;
+ case UNIFORM:
+ uniform_free(pool, pagenum, off, metadata);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+void alloc_free(void *pool, unsigned long poolsize, void *free)
+{
+ unsigned long pagenum;
+ struct metaheader *mh;
+
+ if (!free)
+ return;
+
+ assert(poolsize >= MIN_SIZE);
+
+ mh = first_mheader(pool, poolsize);
+ assert((char *)free >= (char *)(mh + 1));
+ assert((char *)pool + poolsize > (char *)free);
+
+ pagenum = pool_offset(pool, free) / getpagesize();
+
+ if (get_page_state(pool, pagenum) == SPECIAL)
+ subpage_free(pool, pagenum, free);
+ else {
+ assert((unsigned long)free % getpagesize() == 0);
+ alloc_free_pages(pool, pagenum);
+ }
+}
+
+static bool is_metadata_page(void *pool, unsigned long poolsize,
+ unsigned long page)
+{
+ struct metaheader *mh;
+
+ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
+ unsigned long start, end;
+
+ start = pool_offset(pool, mh);
+ end = pool_offset(pool, (char *)(mh+1)
+ + get_metalen(pool, poolsize, mh));
+ if (page >= start/getpagesize() && page < end/getpagesize())
+ return true;
+ }
+ return false;
+}
+
+static bool check_bitmap_metadata(void *pool, unsigned long *mhoff)
+{
+ enum alloc_state last_state = FREE;
+ unsigned int i;
+
+ for (i = 0; i < SUBPAGE_METAOFF / BITMAP_GRANULARITY; i++) {
+ enum alloc_state state;
+
+ /* +1 because header is the first byte. */
+ state = get_bit_pair((uint8_t *)pool + *mhoff, i+1);
+ switch (state) {
+ case SPECIAL:
+ return false;
+ case TAKEN:
+ if (last_state == FREE)
+ return false;
+ break;
+ default:
+ break;
+ }
+ last_state = state;
+ }
+ return true;
+}
+
+static bool check_uniform_metadata(void *pool, unsigned long *mhoff)
+{
+ uint8_t *meta = (uint8_t *)pool + *mhoff;
+ unsigned int i, usize;
+ struct uniform_cache *uc = pool;
+
+ usize = decode_usize(meta);
+ if (usize == 0 || suitable_for_uc(usize, 1) != usize)
+ return false;
+
+ /* If it's in uniform cache, make sure that agrees on size. */
+ for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
+ uint8_t *ucm;
+
+ if (!uc->size[i])
+ continue;
+
+ ucm = get_page_metadata(pool, uc->page[i]);
+ if (ucm != meta)
+ continue;
+
+ if (usize != uc->size[i])
+ return false;
+ }
+ return true;
+}
+
+static bool check_subpage(void *pool, unsigned long poolsize,
+ unsigned long page)
+{
+ unsigned long *mhoff = metadata_off(pool, page);
+
+ if (*mhoff + sizeof(struct metaheader) > poolsize)
+ return false;
+
+ if (*mhoff % ALIGNOF(struct metaheader) != 0)
+ return false;
+
+ /* It must point to a metadata page. */
+ if (!is_metadata_page(pool, poolsize, *mhoff / getpagesize()))
+ return false;
+
+ /* Header at start of subpage allocation */
+ switch (get_bit_pair((uint8_t *)pool + *mhoff, 0)) {
+ case BITMAP:
+ return check_bitmap_metadata(pool, mhoff);
+ case UNIFORM:
+ return check_uniform_metadata(pool, mhoff);
+ default:
+ return false;
+ }
+
+}
+
+bool alloc_check(void *pool, unsigned long poolsize)
+{
+ unsigned long i;
+ struct metaheader *mh;
+ enum alloc_state last_state = FREE;
+ bool was_metadata = false;
+
+ if (poolsize < MIN_SIZE)
+ return true;
+
+ if (get_page_state(pool, 0) != TAKEN_START)
+ return false;
+
+ /* First check metadata pages. */
+ /* Metadata pages will be marked TAKEN. */
+ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
+ unsigned long start, end;
+
+ start = pool_offset(pool, mh);
+ if (start + sizeof(*mh) > poolsize)
+ return false;
+
+ end = pool_offset(pool, (char *)(mh+1)
+ + get_metalen(pool, poolsize, mh));
+ if (end > poolsize)
+ return false;
+
+ /* Non-first pages should start on a page boundary. */
+ if (mh != first_mheader(pool, poolsize)
+ && start % getpagesize() != 0)
+ return false;
+
+ /* It should end on a page boundary. */
+ if (end % getpagesize() != 0)
+ return false;
+ }
+
+ for (i = 0; i < poolsize / getpagesize(); i++) {
+ enum alloc_state state = get_page_state(pool, i);
+ bool is_metadata = is_metadata_page(pool, poolsize,i);
+
+ switch (state) {
+ case FREE:
+ /* metadata pages are never free. */
+ if (is_metadata)
+ return false;
+ case TAKEN_START:
+ break;
+ case TAKEN:
+ /* This should continue a previous block. */
+ if (last_state == FREE)
+ return false;
+ if (is_metadata != was_metadata)
+ return false;
+ break;
+ case SPECIAL:
+ /* Check metadata pointer etc. */
+ if (!check_subpage(pool, poolsize, i))
+ return false;
+ }
+ last_state = state;
+ was_metadata = is_metadata;
+ }
+ return true;
+}
+
+void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
+{
+ struct metaheader *mh;
+ struct uniform_cache *uc = pool;
+ unsigned long pagebitlen, metadata_pages, count[1<<BITS_PER_PAGE], tot;
+ long i;
+
+ if (poolsize < MIN_SIZE) {
+ fprintf(out, "Pool smaller than %u: no content\n", MIN_SIZE);
+ return;
+ }
+
+ tot = 0;
+ for (i = 0; i < UNIFORM_CACHE_NUM; i++)
+ tot += (uc->size[i] != 0);
+ fprintf(out, "Uniform cache (%lu entries):\n", tot);
+ for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
+ unsigned int j, total = 0;
+ uint8_t *meta;
+
+ if (!uc->size[i])
+ continue;
+
+ /* First two bytes are header. */
+ meta = get_page_metadata(pool, uc->page[i]) + 2;
+
+ for (j = 0; j < SUBPAGE_METAOFF / uc->size[i]; j++)
+ if (meta[j / 8] & (1 << (j % 8)))
+ total++;
+
+ printf(" %u: %u/%u (%u%% density)\n",
+ uc->size[j], total, SUBPAGE_METAOFF / uc->size[i],
+ (total * 100) / (SUBPAGE_METAOFF / uc->size[i]));
+ }
+
+ memset(count, 0, sizeof(count));
+ for (i = 0; i < poolsize / getpagesize(); i++)
+ count[get_page_state(pool, i)]++;
+
+ mh = first_mheader(pool, poolsize);
+ pagebitlen = (uint8_t *)mh - get_page_statebits(pool);
+ fprintf(out, "%lu bytes of page bits: FREE/TAKEN/TAKEN_START/SUBPAGE = %lu/%lu/%lu/%lu\n",
+ pagebitlen, count[0], count[1], count[2], count[3]);
+
+ /* One metadata page for every page of page bits. */
+ metadata_pages = div_up(pagebitlen, getpagesize());
+
+ /* Now do each metadata page. */
+ for (; mh; mh = next_mheader(pool,mh)) {
+ unsigned long free = 0, bitmapblocks = 0, uniformblocks = 0,
+ len = 0, uniformlen = 0, bitmaplen = 0, metalen;
+ uint8_t *meta = (uint8_t *)(mh + 1);
+
+ metalen = get_metalen(pool, poolsize, mh);
+ metadata_pages += (sizeof(*mh) + metalen) / getpagesize();
+
+ for (i = 0; i < metalen * METADATA_PER_BYTE; i += len) {
+ switch (get_bit_pair(meta, i)) {
+ case FREE:
+ len = 1;
+ free++;
+ break;
+ case BITMAP:
+ /* Skip over this allocated part. */
+ len = BITMAP_METALEN * CHAR_BIT;
+ bitmapblocks++;
+ bitmaplen += len;
+ break;
+ case UNIFORM:
+ /* Skip over this part. */
+ len = decode_usize(meta + i/METADATA_PER_BYTE);
+ len = uniform_metalen(len) * METADATA_PER_BYTE;
+ uniformblocks++;
+ uniformlen += len;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ fprintf(out, "Metadata %lu-%lu: %lu free, %lu bitmapblocks, %lu uniformblocks, %lu%% density\n",
+ pool_offset(pool, mh),
+ pool_offset(pool, (char *)(mh+1) + metalen),
+ free, bitmapblocks, uniformblocks,
+ (bitmaplen + uniformlen) * 100
+ / (free + bitmaplen + uniformlen));
+ }
+
+ /* Account for total pages allocated. */
+ tot = (count[1] + count[2] - metadata_pages) * getpagesize();
+
+ fprintf(out, "Total metadata bytes = %lu\n",
+ metadata_pages * getpagesize());
+
+ /* Now do every subpage. */
+ for (i = 0; i < poolsize / getpagesize(); i++) {
+ uint8_t *meta;
+ unsigned int j, allocated;
+ enum sub_metadata_type type;
+
+ if (get_page_state(pool, i) != SPECIAL)
+ continue;
+
+ memset(count, 0, sizeof(count));
+
+ meta = get_page_metadata(pool, i);
+ type = get_bit_pair(meta, 0);
+
+ if (type == BITMAP) {
+ for (j = 0; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY; j++)
+ count[get_page_state(meta, j)]++;
+ allocated = (count[1] + count[2]) * BITMAP_GRANULARITY;
+ fprintf(out, "Subpage bitmap ");
+ } else {
+ unsigned int usize = decode_usize(meta);
+
+ assert(type == UNIFORM);
+ fprintf(out, "Subpage uniform (%u) ", usize);
+ meta += 2;
+ for (j = 0; j < SUBPAGE_METAOFF / usize; j++)
+ count[!!(meta[j / 8] & (1 << (j % 8)))]++;
+ allocated = count[1] * usize;
+ }
+ fprintf(out, "%lu: FREE/TAKEN/TAKEN_START = %lu/%lu/%lu %u%% density\n",
+ i, count[0], count[1], count[2],
+ allocated * 100 / getpagesize());
+ tot += allocated;
+ }
+
+ /* This is optimistic, since we overalloc in several cases. */
+ fprintf(out, "Best possible allocation density = %lu%%\n",
+ tot * 100 / poolsize);
+}
--- /dev/null
+#ifndef ALLOC_H
+#define ALLOC_H
+#include <stdio.h>
+#include <stdbool.h>
+
+void alloc_init(void *pool, unsigned long poolsize);
+void *alloc_get(void *pool, unsigned long poolsize,
+ unsigned long size, unsigned long align);
+void alloc_free(void *pool, unsigned long poolsize, void *free);
+bool alloc_check(void *pool, unsigned long poolsize);
+
+void alloc_visualize(FILE *out, void *pool, unsigned long poolsize);
+#endif /* ALLOC_H */
--- /dev/null
+#include "alloc/alloc.h"
+#include "tap/tap.h"
+#include "alloc/alloc.c"
+#include <stdlib.h>
+
+#define POOL_ORD 16
+#define POOL_SIZE (1 << POOL_ORD)
+
+#define sort(p, num, cmp) \
+ qsort((p), (num), sizeof(*p), (int(*)(const void *, const void *))cmp)
+
+static int addr_cmp(void **a, void **b)
+{
+ return (*a) - (*b);
+}
+
+static bool unique(void *p[], unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 1; i < num; i++)
+ if (p[i] == p[i-1])
+ return false;
+ return true;
+}
+
+static bool free_every_second_one(void *mem, unsigned int num, void *p[])
+{
+ unsigned int i;
+
+ /* Free every second one. */
+ for (i = 0; i < num; i += 2) {
+ alloc_free(mem, POOL_SIZE, p[i]);
+ if (!alloc_check(mem, POOL_SIZE))
+ return false;
+ }
+ for (i = 1; i < num; i += 2) {
+ alloc_free(mem, POOL_SIZE, p[i]);
+ if (!alloc_check(mem, POOL_SIZE))
+ return false;
+ }
+ return true;
+}
+
+
+int main(int argc, char *argv[])
+{
+ void *mem;
+ unsigned int i, num, max_size;
+ void *p[POOL_SIZE];
+
+ plan_tests(139);
+
+ /* FIXME: Needs to be page aligned for now. */
+ posix_memalign(&mem, 1 << POOL_ORD, POOL_SIZE);
+
+ /* Small pool, all allocs fail, even 0-length. */
+ alloc_init(mem, 0);
+ ok1(alloc_check(mem, 0));
+ ok1(alloc_get(mem, 0, 1, 1) == NULL);
+ ok1(alloc_get(mem, 0, 128, 1) == NULL);
+ ok1(alloc_get(mem, 0, 0, 1) == NULL);
+
+ /* Free of NULL should work. */
+ alloc_free(mem, 0, NULL);
+
+ alloc_init(mem, POOL_SIZE);
+ ok1(alloc_check(mem, POOL_SIZE));
+ /* Find largest allocation which works. */
+ for (max_size = POOL_SIZE * 2; max_size; max_size--) {
+ p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
+ if (p[0])
+ break;
+ }
+ ok1(max_size < POOL_SIZE);
+ ok1(max_size > 0);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Free it, should be able to reallocate it. */
+ alloc_free(mem, POOL_SIZE, p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
+ ok1(p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+ alloc_free(mem, POOL_SIZE, p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Allocate a whole heap. */
+ for (i = 0; i < POOL_SIZE; i++) {
+ p[i] = alloc_get(mem, POOL_SIZE, 1, 1);
+ if (!p[i])
+ break;
+ }
+
+ /* Uncomment this for a more intuitive view of what the
+ * allocator looks like after all these 1 byte allocs. */
+#if 0
+ alloc_visualize(stderr, mem, POOL_SIZE);
+#endif
+
+ num = i;
+ /* Can't allocate this many. */
+ ok1(num != POOL_SIZE);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Sort them. */
+ sort(p, num, addr_cmp);
+
+ /* Uniqueness check */
+ ok1(unique(p, num));
+
+ ok1(free_every_second_one(mem, num, p));
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Should be able to reallocate max size. */
+ p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
+ ok1(p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Re-initializing should be the same as freeing everything */
+ alloc_init(mem, POOL_SIZE);
+ ok1(alloc_check(mem, POOL_SIZE));
+ p[0] = alloc_get(mem, POOL_SIZE, max_size, 1);
+ ok1(p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+ alloc_free(mem, POOL_SIZE, p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Alignment constraints should be met, as long as powers of two */
+ for (i = 0; i < POOL_ORD-1; i++) {
+ p[i] = alloc_get(mem, POOL_SIZE, i, 1 << i);
+ ok1(p[i]);
+ ok1(((unsigned long)p[i] % (1 << i)) == 0);
+ ok1(alloc_check(mem, POOL_SIZE));
+ }
+
+ for (i = 0; i < POOL_ORD-1; i++) {
+ alloc_free(mem, POOL_SIZE, p[i]);
+ ok1(alloc_check(mem, POOL_SIZE));
+ }
+
+ /* Alignment constraints for a single-byte allocation. */
+ for (i = 0; i < POOL_ORD; i++) {
+ p[0] = alloc_get(mem, POOL_SIZE, 1, 1 << i);
+ ok1(p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+ alloc_free(mem, POOL_SIZE, p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+ }
+
+ /* Alignment check for a 0-byte allocation. Corner case. */
+ p[0] = alloc_get(mem, POOL_SIZE, 0, 1 << (POOL_ORD - 1));
+ ok1(alloc_check(mem, POOL_SIZE));
+ alloc_free(mem, POOL_SIZE, p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Force the testing of split metadata. */
+ alloc_init(mem, POOL_SIZE);
+ for (i = 0; i < POOL_SIZE; i++) {
+ p[i] = alloc_get(mem, POOL_SIZE, getpagesize(), getpagesize());
+ if (!p[i])
+ break;
+ }
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Sort them. */
+ sort(p, i-1, addr_cmp);
+
+ /* Free all but the one next to the metadata. */
+ for (i = 1; p[i]; i++)
+ alloc_free(mem, POOL_SIZE, p[i]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Now do a whole heap of subpage allocs. */
+ for (i = 1; i < POOL_SIZE; i++) {
+ p[i] = alloc_get(mem, POOL_SIZE, 1, 1);
+ if (!p[i])
+ break;
+ }
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ /* Free up our page next to metadata, and should be able to alloc */
+ alloc_free(mem, POOL_SIZE, p[0]);
+ ok1(alloc_check(mem, POOL_SIZE));
+ p[0] = alloc_get(mem, POOL_SIZE, 1, 1);
+ ok1(p[0]);
+
+ /* Clean up. */
+ for (i = 0; p[i]; i++)
+ alloc_free(mem, POOL_SIZE, p[i]);
+ ok1(alloc_check(mem, POOL_SIZE));
+
+ return exit_status();
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * build_assert - routines for build-time assertions
+ *
+ * This code provides routines which will cause compilation to fail should some
+ * assertion be untrue: such failures are preferable to run-time assertions,
+ * but much more limited since they can only depends on compile-time constants.
+ *
+ * These assertions are most useful when two parts of the code must be kept in
+ * sync: it is better to avoid such cases if possible, but seconds best is to
+ * detect invalid changes at build time.
+ *
+ * For example, a tricky piece of code might rely on a certain element being at
+ * the start of the structure. To ensure that future changes don't break it,
+ * you would catch such changes in your code like so:
+ *
+ * Example:
+ * char *foo_string(struct foo *foo)
+ * {
+ * // This trick requires that the string be first in the structure
+ * BUILD_ASSERT(offsetof(struct foo, string) == 0);
+ * return (char *)foo;
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0)
+ /* Nothing. */
+ return 0;
+
+ return 1;
+}
--- /dev/null
+#ifndef CCAN_BUILD_ASSERT_H
+#define CCAN_BUILD_ASSERT_H
+
+/**
+ * BUILD_ASSERT - assert a build-time dependency.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can only be used within a function.
+ *
+ * Example:
+ * char *foo_to_char(struct foo *foo)
+ * {
+ * // This code needs string to be at start of foo.
+ * BUILD_ASSERT(offsetof(struct foo, string) == 0);
+ * return (char *)foo;
+ * }
+ */
+#define BUILD_ASSERT(cond) \
+ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
+
+/**
+ * EXPR_BUILD_ASSERT - assert a build-time dependency, as an expression.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can be used in an expression: its value is "0".
+ *
+ * Example:
+ * #define foo_to_char(foo) \
+ * ((char *)(foo) \
+ * + EXPR_BUILD_ASSERT(offsetof(struct foo, string) == 0))
+ */
+#define EXPR_BUILD_ASSERT(cond) \
+ (sizeof(char [1 - 2*!(cond)]) - 1)
+
+#endif /* CCAN_BUILD_ASSERT_H */
--- /dev/null
+#include "build_assert/build_assert.h"
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ return EXPR_BUILD_ASSERT(1 == 0);
+#else
+ return 0;
+#endif
+}
--- /dev/null
+#include "build_assert/build_assert.h"
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ BUILD_ASSERT(1 == 0);
+#endif
+ return 0;
+}
--- /dev/null
+#include "build_assert/build_assert.h"
+
+int main(int argc, char *argv[])
+{
+ BUILD_ASSERT(1 == 1);
+ return 0;
+}
--- /dev/null
+#include "build_assert/build_assert.h"
+#include "tap/tap.h"
+
+int main(int argc, char *argv[])
+{
+ plan_tests(1);
+ ok1(EXPR_BUILD_ASSERT(1 == 1) == 0);
+ return exit_status();
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * check_type - routines for compile time type checking
+ *
+ * C has fairly weak typing: ints get automatically converted to longs, signed
+ * to unsigned, etc. There are some cases where this is best avoided, and
+ * these macros provide methods for evoking warnings (or build errors) when
+ * a precise type isn't used.
+ *
+ * On compilers which don't support typeof() these routines are less effective,
+ * since they have to use sizeof() which can only distiguish between types of
+ * different size.
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+#if !HAVE_TYPEOF
+ printf("ccan/build_assert\n");
+#endif
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+#ifndef CCAN_CHECK_TYPE_H
+#define CCAN_CHECK_TYPE_H
+#include "config.h"
+
+/**
+ * check_type - issue a warning or build failure if type is not correct.
+ * @expr: the expression whose type we should check (not evaluated).
+ * @type: the exact type we expect the expression to be.
+ *
+ * This macro is usually used within other macros to try to ensure that a macro
+ * argument is of the expected type. No type promotion of the expression is
+ * done: an unsigned int is not the same as an int!
+ *
+ * check_type() always evaluates to 1.
+ *
+ * If your compiler does not support typeof, then the best we can do is fail
+ * to compile if the sizes of the types are unequal (a less complete check).
+ *
+ * Example:
+ * // They should always pass a 64-bit value to _set_some_value!
+ * #define set_some_value(expr) \
+ * _set_some_value((check_type((expr), uint64_t), (expr)))
+ */
+
+/**
+ * check_types_match - issue a warning or build failure if types are not same.
+ * @expr1: the first expression (not evaluated).
+ * @expr2: the second expression (not evaluated).
+ *
+ * This macro is usually used within other macros to try to ensure that
+ * arguments are of identical types. No type promotion of the expressions is
+ * done: an unsigned int is not the same as an int!
+ *
+ * check_types_match() always evaluates to 1.
+ *
+ * If your compiler does not support typeof, then the best we can do is fail
+ * to compile if the sizes of the types are unequal (a less complete check).
+ *
+ * Example:
+ * // Do subtraction to get to enclosing type, but make sure that
+ * // pointer is of correct type for that member.
+ * #define container_of(mbr_ptr, encl_type, mbr) \
+ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
+ * ((encl_type *) \
+ * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
+ */
+#if HAVE_TYPEOF
+#define check_type(expr, type) \
+ ((typeof(expr) *)0 != (type *)0)
+
+#define check_types_match(expr1, expr2) \
+ ((typeof(expr1) *)0 != (typeof(expr2) *)0)
+#else
+#include "build_assert/build_assert.h"
+/* Without typeof, we can only test the sizes. */
+#define check_type(expr, type) \
+ EXPR_BUILD_ASSERT(sizeof(expr) == sizeof(type))
+
+#define check_types_match(expr1, expr2) \
+ EXPR_BUILD_ASSERT(sizeof(expr1) == sizeof(expr2))
+#endif /* HAVE_TYPEOF */
+
+#endif /* CCAN_CHECK_TYPE_H */
--- /dev/null
+#include "check_type/check_type.h"
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ check_type(argc, char);
+#endif
+ return 0;
+}
--- /dev/null
+#include "check_type/check_type.h"
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+#if HAVE_TYPEOF
+ check_type(argc, unsigned int);
+#else
+ /* This doesn't work without typeof, so just fail */
+#error "Fail without typeof"
+#endif
+#endif
+ return 0;
+}
--- /dev/null
+#include "check_type/check_type.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned char x = argc;
+#ifdef FAIL
+ check_types_match(argc, x);
+#endif
+ return x;
+}
--- /dev/null
+#include "check_type/check_type.h"
+#include "tap/tap.h"
+
+int main(int argc, char *argv[])
+{
+ int x = 0, y = 0;
+
+ plan_tests(9);
+
+ ok1(check_type(argc, int) == 0);
+ ok1(check_type(&argc, int *) == 0);
+ ok1(check_types_match(argc, argc) == 0);
+ ok1(check_types_match(argc, x) == 0);
+ ok1(check_types_match(&argc, &x) == 0);
+
+ ok1(check_type(x++, int) == 0);
+ ok(x == 0, "check_type does not evaluate expression");
+ ok1(check_types_match(x++, y++) == 0);
+ ok(x == 0 && y == 0, "check_types_match does not evaluate expressions");
+
+ return exit_status();
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * container_of - routine for upcasting
+ *
+ * It is often convenient to create code where the caller registers a pointer
+ * to a generic structure and a callback. The callback might know that the
+ * pointer points to within a larger structure, and container_of gives a
+ * convenient and fairly type-safe way of returning to the enclosing structure.
+ *
+ * This idiom is an alternative to providing a void * pointer for every
+ * callback.
+ *
+ * Example:
+ * struct info
+ * {
+ * int my_stuff;
+ * struct timer timer;
+ * };
+ *
+ * static void my_timer_callback(struct timer *timer)
+ * {
+ * struct info *info = container_of(timer, struct info, timer);
+ * printf("my_stuff is %u\n", info->my_stuff);
+ * }
+ *
+ * int main()
+ * {
+ * struct info info = { .my_stuff = 1 };
+ *
+ * register_timer(&info.timer);
+ * ...
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/check_type\n");
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+#ifndef CCAN_CONTAINER_OF_H
+#define CCAN_CONTAINER_OF_H
+#include <stddef.h>
+
+#include "config.h"
+#include "check_type/check_type.h"
+
+/**
+ * container_of - get pointer to enclosing structure
+ * @member_ptr: pointer to the structure member
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type.
+ *
+ * Example:
+ * struct info
+ * {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * struct info *foo_to_info(struct foo *foop)
+ * {
+ * return container_of(foo, struct info, my_foo);
+ * }
+ */
+#define container_of(member_ptr, containing_type, member) \
+ ((containing_type *) \
+ ((char *)(member_ptr) - offsetof(containing_type, member)) \
+ - check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+
+/**
+ * container_of_var - get pointer to enclosing structure using a variable
+ * @member_ptr: pointer to the structure member
+ * @var: a pointer to a structure of same type as this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type.
+ *
+ * Example:
+ * struct info
+ * {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * struct info *foo_to_info(struct foo *foop)
+ * {
+ * struct info *i = container_of_var(foo, i, my_foo);
+ * return i;
+ * }
+ */
+#ifdef HAVE_TYPEOF
+#define container_of_var(member_ptr, var, member) \
+ container_of(member_ptr, typeof(*var), member)
+#else
+#define container_of_var(member_ptr, var, member) \
+ ((void *)((char *)(member_ptr) - offsetof(containing_type, member)))
+#endif
+
+#endif /* CCAN_CONTAINER_OF_H */
--- /dev/null
+#include "container_of/container_of.h"
+#include <stdlib.h>
+
+struct foo {
+ int a;
+ char b;
+};
+
+int main(int argc, char *argv[])
+{
+ struct foo foo = { .a = 1, .b = 2 };
+ int *intp = &foo.a;
+ char *p;
+
+#ifdef FAIL
+ /* p is a char *, but this gives a struct foo * */
+ p = container_of(intp, struct foo, a);
+#else
+ p = (char *)intp;
+#endif
+ return p == NULL;
+}
--- /dev/null
+#include "container_of/container_of.h"
+#include <stdlib.h>
+
+struct foo {
+ int a;
+ char b;
+};
+
+int main(int argc, char *argv[])
+{
+ struct foo foo = { .a = 1, .b = 2 }, *foop;
+ int *intp = &foo.a;
+
+#ifdef FAIL
+ /* b is a char, but intp is an int * */
+ foop = container_of(intp, struct foo, b);
+#else
+ foop = NULL;
+#endif
+ return intp == NULL;
+}
--- /dev/null
+#include "container_of/container_of.h"
+#include <stdlib.h>
+
+struct foo {
+ int a;
+ char b;
+};
+
+int main(int argc, char *argv[])
+{
+ struct foo foo = { .a = 1, .b = 2 }, *foop;
+ int *intp = &foo.a;
+
+#ifdef FAIL
+ /* b is a char, but intp is an int * */
+ foop = container_of_var(intp, foop, b);
+#else
+ foop = NULL;
+#endif
+ return intp == NULL;
+}
--- /dev/null
+#include "container_of/container_of.h"
+#include "tap/tap.h"
+
+struct foo {
+ int a;
+ char b;
+};
+
+int main(int argc, char *argv[])
+{
+ struct foo foo = { .a = 1, .b = 2 };
+ int *intp = &foo.a;
+ char *charp = &foo.b;
+
+ plan_tests(4);
+ ok1(container_of(intp, struct foo, a) == &foo);
+ ok1(container_of(charp, struct foo, b) == &foo);
+ ok1(container_of_var(intp, &foo, a) == &foo);
+ ok1(container_of_var(charp, &foo, b) == &foo);
+ return exit_status();
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * list - double linked list routines
+ *
+ * The list header contains routines for manipulating double linked lists.
+ * It defines two types: struct list_head used for anchoring lists, and
+ * struct list_node which is usually embedded in the structure which is placed
+ * in the list.
+ *
+ * Example:
+ * #include <err.h>
+ * #include "list/list.h"
+ *
+ * struct parent {
+ * const char *name;
+ * struct list_head children;
+ * unsigned int num_children;
+ * };
+ *
+ * struct child {
+ * const char *name;
+ * struct list_node list;
+ * };
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * struct parent p;
+ * struct child *c;
+ * unsigned int i;
+ *
+ * if (argc < 2)
+ * errx(1, "Usage: %s parent children...", argv[0]);
+ *
+ * p.name = argv[1];
+ * for (i = 2; i < argc, i++) {
+ * c = malloc(sizeof(*c));
+ * c->name = argv[i];
+ * list_add(&p.children, &c->list);
+ * p.num_children++;
+ * }
+ *
+ * printf("%s has %u children:", p.name, p.num_children);
+ * list_for_each(&p.children, c, list)
+ * printf("%s ", c->name);
+ * printf("\n");
+ * return 0;
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/container_of\n");
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include "list/list.h"
+
+struct list_head *list_check(struct list_head *h, const char *abortstr)
+{
+ struct list_node *n, *p;
+ int count = 0;
+
+ if (h->n.next == &h->n) {
+ if (h->n.prev != &h->n) {
+ if (!abortstr)
+ return NULL;
+ fprintf(stderr, "%s: prev corrupt in empty %p\n",
+ abortstr, h);
+ abort();
+ }
+ return h;
+ }
+
+ for (p = &h->n, n = h->n.next; n != &h->n; p = n, n = n->next) {
+ count++;
+ if (n->prev != p) {
+ if (!abortstr)
+ return NULL;
+ fprintf(stderr,
+ "%s: prev corrupt in node %p (%u) of %p\n",
+ abortstr, n, count, h);
+ abort();
+ }
+ }
+ return h;
+}
--- /dev/null
+#ifndef CCAN_LIST_H
+#define CCAN_LIST_H
+#include <stdbool.h>
+#include "container_of/container_of.h"
+
+/**
+ * struct list_node - an entry in a doubly-linked list
+ * @next: next entry (self if empty)
+ * @prev: previous entry (self if empty)
+ *
+ * This is used as an entry in a linked list.
+ * Example:
+ * struct child {
+ * const char *name;
+ * // Linked list of all us children.
+ * struct list_node list;
+ * };
+ */
+struct list_node
+{
+ struct list_node *next, *prev;
+};
+
+/**
+ * struct list_head - the head of a doubly-linked list
+ * @h: the list_head (containing next and prev pointers)
+ *
+ * This is used as the head of a linked list.
+ * Example:
+ * struct parent {
+ * const char *name;
+ * struct list_head children;
+ * unsigned int num_children;
+ * };
+ */
+struct list_head
+{
+ struct list_node n;
+};
+
+/**
+ * list_check - check a list for consistency
+ * @h: the list_head
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Because list_nodes have redundant information, consistency checking between
+ * the back and forward links can be done. This is useful as a debugging check.
+ * If @abortstr is non-NULL, that will be printed in a diagnostic if the list
+ * is inconsistent, and the function will abort.
+ *
+ * Returns the list head if the list is consistent, NULL if not (it
+ * can never return NULL if @abortstr is set).
+ *
+ * Example:
+ * static void dump_parent(struct parent *p)
+ * {
+ * struct child *c;
+ *
+ * printf("%s (%u children):\n", p->name, parent->num_children);
+ * list_check(&p->children, "bad child list");
+ * list_for_each(&p->children, c, list)
+ * printf(" -> %s\n", c->name);
+ * }
+ */
+struct list_head *list_check(struct list_head *h, const char *abortstr);
+
+#ifdef CCAN_LIST_DEBUG
+#define debug_list(h) list_check((h), __func__)
+#else
+#define debug_list(h) (h)
+#endif
+
+/**
+ * list_head_init - initialize a list_head
+ * @h: the list_head to set to the empty list
+ *
+ * Example:
+ * list_head_init(&parent->children);
+ * parent->num_children = 0;
+ */
+static inline void list_head_init(struct list_head *h)
+{
+ h->n.next = h->n.prev = &h->n;
+}
+
+/**
+ * LIST_HEAD - define and initalized empty list_head
+ * @name: the name of the list.
+ *
+ * The LIST_HEAD macro defines a list_head and initializes it to an empty
+ * list. It can be prepended by "static" to define a static list_head.
+ *
+ * Example:
+ * // Header:
+ * extern struct list_head my_list;
+ *
+ * // C file:
+ * LIST_HEAD(my_list);
+ */
+#define LIST_HEAD(name) \
+ struct list_head name = { { &name.n, &name.n } }
+
+/**
+ * list_add - add an entry at the start of a linked list.
+ * @h: the list_head to add the node to
+ * @n: the list_node to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * list_add(&parent->children, &child->list);
+ * parent->num_children++;
+ */
+static inline void list_add(struct list_head *h, struct list_node *n)
+{
+ n->next = h->n.next;
+ n->prev = &h->n;
+ h->n.next->prev = n;
+ h->n.next = n;
+ (void)debug_list(h);
+}
+
+/**
+ * list_add_tail - add an entry at the end of a linked list.
+ * @h: the list_head to add the node to
+ * @n: the list_node to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * list_add_tail(&parent->children, &child->list);
+ * parent->num_children++;
+ */
+static inline void list_add_tail(struct list_head *h, struct list_node *n)
+{
+ n->next = &h->n;
+ n->prev = h->n.prev;
+ h->n.prev->next = n;
+ h->n.prev = n;
+ (void)debug_list(h);
+}
+
+/**
+ * list_del - delete an entry from a linked list.
+ * @n: the list_node to delete from the list.
+ *
+ * Example:
+ * list_del(&child->list);
+ * parent->num_children--;
+ */
+static inline void list_del(struct list_node *n)
+{
+ n->next->prev = n->prev;
+ n->prev->next = n->next;
+ (void)debug_list(n->next);
+#ifdef CCAN_LIST_DEBUG
+ /* Catch use-after-del. */
+ n->next = n->prev = NULL;
+#endif
+}
+
+/**
+ * list_empty - is a list empty?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ *
+ * Example:
+ * assert(list_empty(&parent->children) == (parent->num_children == 0));
+ */
+static inline bool list_empty(struct list_head *h)
+{
+ (void)debug_list(h);
+ return h->n.next == &h->n;
+}
+
+/**
+ * list_entry - convert a list_node back into the structure containing it.
+ * @n: the list_node
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * Example:
+ * struct child *c;
+ * // First list entry is children.next; convert back to child.
+ * c = list_entry(parent->children.next, struct child, list);
+ */
+#define list_entry(n, type, member) container_of(n, type, member)
+
+/**
+ * list_top - get the first entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *first;
+ * first = list_top(&parent->children, struct child, list);
+ */
+#define list_top(h, type, member) \
+ list_entry(_list_top(h), type, member)
+
+static inline struct list_node *_list_top(struct list_head *h)
+{
+ (void)debug_list(h);
+ if (list_empty(h))
+ return NULL;
+ return h->n.next;
+}
+
+/**
+ * list_for_each - iterate through a list.
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ * struct child *c;
+ * list_for_each(&parent->children, c, list)
+ * printf("Name: %s\n", c->name);
+ */
+#define list_for_each(h, i, member) \
+ for (i = container_of_var(debug_list(h)->n.next, i, member); \
+ &i->member != &(h)->n; \
+ i = container_of_var(i->member.next, i, member))
+
+/**
+ * list_for_each_safe - iterate through a list, maybe during deletion
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @nxt: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal. The extra variable
+ * @nxt is used to hold the next element, so you can delete @i from the list.
+ *
+ * Example:
+ * struct child *c, *n;
+ * list_for_each_safe(&parent->children, c, n, list) {
+ * list_del(&c->list);
+ * parent->num_children--;
+ * }
+ */
+#define list_for_each_safe(h, i, nxt, member) \
+ for (i = container_of_var(debug_list(h)->n.next, i, member), \
+ nxt = container_of_var(i->member.next, i, member); \
+ &i->member != &(h)->n; \
+ i = nxt, nxt = container_of_var(i->member.next, i, member))
+#endif /* CCAN_LIST_H */
--- /dev/null
+#include "list/list.h"
+#include "tap/tap.h"
+#include "list/list.c"
+
+struct parent {
+ const char *name;
+ struct list_head children;
+ unsigned int num_children;
+};
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+static LIST_HEAD(static_list);
+
+int main(int argc, char *argv[])
+{
+ struct parent parent;
+ struct child c1, c2, c3, *c, *n;
+ unsigned int i;
+
+ plan_tests(41);
+ /* Test LIST_HEAD, list_empty and check_list */
+ ok1(list_empty(&static_list));
+ ok1(list_check(&static_list, NULL));
+
+ parent.num_children = 0;
+ list_head_init(&parent.children);
+ /* Test list_head_init */
+ ok1(list_empty(&parent.children));
+ ok1(list_check(&parent.children, NULL));
+
+ c2.name = "c2";
+ list_add(&parent.children, &c2.list);
+ /* Test list_add and !list_empty. */
+ ok1(!list_empty(&parent.children));
+ ok1(c2.list.next == &parent.children.n);
+ ok1(c2.list.prev == &parent.children.n);
+ ok1(parent.children.n.next == &c2.list);
+ ok1(parent.children.n.prev == &c2.list);
+ /* Test list_check */
+ ok1(list_check(&parent.children, NULL));
+
+ c1.name = "c1";
+ list_add(&parent.children, &c1.list);
+ /* Test list_add and !list_empty. */
+ ok1(!list_empty(&parent.children));
+ ok1(c2.list.next == &parent.children.n);
+ ok1(c2.list.prev == &c1.list);
+ ok1(parent.children.n.next == &c1.list);
+ ok1(parent.children.n.prev == &c2.list);
+ ok1(c1.list.next == &c2.list);
+ ok1(c1.list.prev == &parent.children.n);
+ /* Test list_check */
+ ok1(list_check(&parent.children, NULL));
+
+ c3.name = "c3";
+ list_add_tail(&parent.children, &c3.list);
+ /* Test list_add_tail and !list_empty. */
+ ok1(!list_empty(&parent.children));
+ ok1(parent.children.n.next == &c1.list);
+ ok1(parent.children.n.prev == &c3.list);
+ ok1(c1.list.next == &c2.list);
+ ok1(c1.list.prev == &parent.children.n);
+ ok1(c2.list.next == &c3.list);
+ ok1(c2.list.prev == &c1.list);
+ ok1(c3.list.next == &parent.children.n);
+ ok1(c3.list.prev == &c2.list);
+ /* Test list_check */
+ ok1(list_check(&parent.children, NULL));
+
+ /* Test list_top */
+ ok1(list_top(&parent.children, struct child, list) == &c1);
+
+ /* Test list_for_each. */
+ i = 0;
+ list_for_each(&parent.children, c, list) {
+ switch (i++) {
+ case 0:
+ ok1(c == &c1);
+ break;
+ case 1:
+ ok1(c == &c2);
+ break;
+ case 2:
+ ok1(c == &c3);
+ break;
+ }
+ if (i > 2)
+ break;
+ }
+ ok1(i == 3);
+
+ /* Test list_for_each_safe and list_del. */
+ i = 0;
+ list_for_each_safe(&parent.children, c, n, list) {
+ switch (i++) {
+ case 0:
+ ok1(c == &c1);
+ break;
+ case 1:
+ ok1(c == &c2);
+ break;
+ case 2:
+ ok1(c == &c3);
+ break;
+ }
+ list_del(&c->list);
+ ok1(list_check(&parent.children, NULL));
+ if (i > 2)
+ break;
+ }
+ ok1(i == 3);
+ ok1(list_empty(&parent.children));
+ return exit_status();
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * noerr - routines for cleaning up without blatting errno
+ *
+ * It is a good idea to follow the standard C convention of setting errno in
+ * your own helper functions. Unfortunately, care must be taken in the error
+ * paths as most standard functions can (and do) overwrite errno, even if they
+ * succeed.
+ *
+ * Example:
+ * #include <sys/types.h>
+ * #include <sys/stat.h>
+ * #include <fcntl.h>
+ *
+ * bool write_string_to_file(const char *file, const char *string)
+ * {
+ * int ret, fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0600);
+ * if (fd < 0)
+ * return false;
+ * ret = write(fd, string, strlen(string));
+ * if (ret < 0) {
+ * // Preserve errno from write above.
+ * close_noerr(fd);
+ * unlink_noerr(file);
+ * return false;
+ * }
+ * if (close(fd) != 0) {
+ * // Again, preserve errno.
+ * unlink_noerr(file);
+ * return false;
+ * }
+ * // A short write means out of space.
+ * if (ret < strlen(string)) {
+ * unlink(file);
+ * errno = ENOSPC;
+ * return false;
+ * }
+ * return true;
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0)
+ /* Nothing. */
+ return 0;
+
+ return 1;
+}
--- /dev/null
+#include "noerr.h"
+#include <unistd.h>
+#include <errno.h>
+
+int close_noerr(int fd)
+{
+ int saved_errno = errno, ret;
+
+ if (close(fd) != 0)
+ ret = errno;
+ else
+ ret = 0;
+
+ errno = saved_errno;
+ return ret;
+}
+
+int unlink_noerr(const char *pathname)
+{
+ int saved_errno = errno, ret;
+
+ if (unlink(pathname) != 0)
+ ret = errno;
+ else
+ ret = 0;
+
+ errno = saved_errno;
+ return ret;
+}
--- /dev/null
+#ifndef NOERR_H
+#define NOERR_H
+
+/**
+ * close_noerr - close without stomping errno.
+ * @fd: the file descriptor to close.
+ *
+ * errno is saved and restored across the call to close: if an error occurs,
+ * the resulting (non-zero) errno is returned.
+ */
+int close_noerr(int fd);
+
+/**
+ * unlink_noerr - unlink a file without stomping errno.
+ * @pathname: the path to unlink.
+ *
+ * errno is saved and restored across the call to unlink: if an error occurs,
+ * the resulting (non-zero) errno is returned.
+ */
+int unlink_noerr(const char *pathname);
+
+#endif /* NOERR_H */
--- /dev/null
+#include "noerr/noerr.h"
+#include "tap/tap.h"
+#include "noerr/noerr.c"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <assert.h>
+
+int main(int argc, char *argv[])
+{
+ /* tempnam(3) is generally a bad idea, but OK here. */
+ char *name = tempnam(NULL, "noerr");
+ int fd;
+
+ plan_tests(12);
+ /* Should fail to unlink. */
+ ok1(unlink(name) != 0);
+ ok1(errno == ENOENT);
+
+ /* This one should not set errno. */
+ errno = 100;
+ ok1(unlink_noerr(name) == ENOENT);
+ ok1(errno == 100);
+
+ /* Should fail to close. */
+ ok1(close(-1) != 0);
+ ok1(errno == EBADF);
+
+ /* This one should not set errno. */
+ errno = 100;
+ ok1(close_noerr(-1) == EBADF);
+ ok1(errno == 100);
+
+ /* Test successful close/unlink doesn't hit errno either. */
+ fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600);
+ assert(fd >= 0);
+
+ errno = 100;
+ ok1(close_noerr(fd) == 0);
+ ok1(errno == 100);
+
+ errno = 100;
+ ok1(unlink_noerr(name) == 0);
+ ok1(errno == 100);
+
+ return exit_status();
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * string - string helper routines
+ *
+ * This is a grab bag of modules for string comparisons, designed to enhance
+ * the standard string.h.
+ *
+ * Example:
+ * #include "string/string.h"
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * if (argv[1] && streq(argv[1], "--verbose"))
+ * printf("verbose set\n");
+ * if (argv[1] && strstarts(argv[1], "--"))
+ * printf("Some option set\n");
+ * if (argv[1] && strends(argv[1], "cow-powers"))
+ * printf("Magic option set\n");
+ * return 0;
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0)
+ /* Nothing. */
+ return 0;
+
+ return 1;
+}
--- /dev/null
+#ifndef CCAN_STRING_H
+#define CCAN_STRING_H
+#include <string.h>
+#include <stdbool.h>
+
+/**
+ * streq - Are two strings equal?
+ * @a: first string
+ * @b: first string
+ *
+ * This macro is arguably more readable than "!strcmp(a, b)".
+ *
+ * Example:
+ * if (streq(str, ""))
+ * printf("String is empty!\n");
+ */
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/**
+ * strstarts - Does this string start with this prefix?
+ * @str: string to test
+ * @prefix: prefix to look for at start of str
+ *
+ * Example:
+ * if (strstarts(str, "foo"))
+ * printf("String %s begins with 'foo'!\n", str);
+ */
+#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
+
+/**
+ * strends - Does this string end with this postfix?
+ * @str: string to test
+ * @postfix: postfix to look for at end of str
+ *
+ * Example:
+ * if (strends(str, "foo"))
+ * printf("String %s end with 'foo'!\n", str);
+ */
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return streq(str + strlen(str) - strlen(postfix), postfix);
+}
+#endif /* CCAN_STRING_H */
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include "string/string.h"
+#include "tap/tap.h"
+
+/* FIXME: ccanize */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+static char *substrings[] = { "far", "bar", "baz", "b", "ba", "z", "ar" };
+
+static char *strdup_rev(const char *s)
+{
+ char *ret = strdup(s);
+ unsigned int i;
+
+ for (i = 0; i < strlen(s); i++)
+ ret[i] = s[strlen(s) - i - 1];
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j, n;
+ char *strings[ARRAY_SIZE(substrings) * ARRAY_SIZE(substrings)];
+
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(substrings); i++) {
+ for (j = 0; j < ARRAY_SIZE(substrings); j++) {
+ strings[n] = malloc(strlen(substrings[i])
+ + strlen(substrings[j]) + 1);
+ sprintf(strings[n++], "%s%s",
+ substrings[i], substrings[j]);
+ }
+ }
+
+ plan_tests(n * n * 5);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ unsigned int k, identical = 0;
+ char *reva, *revb;
+
+ /* Find first difference. */
+ for (k = 0; strings[i][k]==strings[j][k]; k++) {
+ if (k == strlen(strings[i])) {
+ identical = 1;
+ break;
+ }
+ }
+
+ if (identical)
+ ok1(streq(strings[i], strings[j]));
+ else
+ ok1(!streq(strings[i], strings[j]));
+
+ /* Postfix test should be equivalent to prefix
+ * test on reversed string. */
+ reva = strdup_rev(strings[i]);
+ revb = strdup_rev(strings[j]);
+
+ if (!strings[i][k]) {
+ ok1(strstarts(strings[j], strings[i]));
+ ok1(strends(revb, reva));
+ } else {
+ ok1(!strstarts(strings[j], strings[i]));
+ ok1(!strends(revb, reva));
+ }
+ if (!strings[j][k]) {
+ ok1(strstarts(strings[i], strings[j]));
+ ok1(strends(reva, revb));
+ } else {
+ ok1(!strstarts(strings[i], strings[j]));
+ ok1(!strends(reva, revb));
+ }
+ }
+ }
+ return exit_status();
+}
--- /dev/null
+- Remove talloc.h cruft
+- Restore errno around (successful) talloc_free.
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * talloc - tree allocator routines
+ *
+ * Talloc is a hierarchical memory pool system with destructors: you keep your
+ * objects in heirarchies reflecting their lifetime. Every pointer returned
+ * from talloc() is itself a valid talloc context, from which other talloc()s
+ * can be attached. This means you can do this:
+ *
+ * struct foo *X = talloc(mem_ctx, struct foo);
+ * X->name = talloc_strdup(X, "foo");
+ *
+ * and the pointer X->name would be a "child" of the talloc context "X" which
+ * is itself a child of mem_ctx. So if you do talloc_free(mem_ctx) then it is
+ * all destroyed, whereas if you do talloc_free(X) then just X and X->name are
+ * destroyed, and if you do talloc_free(X->name) then just the name element of
+ * X is destroyed.
+ *
+ * If you think about this, then what this effectively gives you is an n-ary
+ * tree, where you can free any part of the tree with talloc_free().
+ *
+ * Talloc has been measured with a time overhead of around 4% over glibc
+ * malloc, and 48/80 bytes per allocation (32/64 bit).
+ *
+ * This version is based on svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc revision 23158.
+ *
+ * Example:
+ * #include <stdio.h>
+ * #include <stdarg.h>
+ * #include <err.h>
+ * #include "talloc/talloc.h"
+ *
+ * // A structure containing a popened comman.
+ * struct command
+ * {
+ * FILE *f;
+ * const char *command;
+ * };
+ *
+ * // When struct command is freed, we also want to pclose pipe.
+ * static int close_cmd(struct command *cmd)
+ * {
+ * pclose(cmd->f);
+ * // 0 means "we succeeded, continue freeing"
+ * return 0;
+ * }
+ *
+ * // This function opens a writable pipe to the given command.
+ * struct command *open_output_cmd(const void *ctx, char *fmt, ...)
+ * {
+ * va_list ap;
+ * struct command *cmd = talloc(ctx, struct command);
+ *
+ * if (!cmd)
+ * return NULL;
+ *
+ * va_start(ap, fmt);
+ * cmd->command = talloc_vasprintf(cmd, fmt, ap);
+ * va_end(ap);
+ * if (!cmd->command) {
+ * talloc_free(cmd);
+ * return NULL;
+ * }
+ *
+ * cmd->f = popen(cmd->command, "w");
+ * if (!cmd->f) {
+ * talloc_free(cmd);
+ * return NULL;
+ * }
+ * talloc_set_destructor(cmd, close_cmd);
+ * return cmd;
+ * }
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * struct command *cmd;
+ *
+ * if (argc != 2)
+ * errx(1, "Usage: %s <command>\n");
+ *
+ * cmd = open_output_cmd(NULL, "%s hello", argv[1]);
+ * if (!cmd)
+ * err(1, "Running '%s hello'", argv[1]);
+ * fprintf(cmd->f, "This is a test\n");
+ * talloc_free(cmd);
+ * return 0;
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ printf("ccan/typesafe_cb\n");
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry>
+ <refmeta>
+ <refentrytitle>talloc</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>talloc</refname>
+<refpurpose>hierarchical reference counted memory pool system with destructors</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+<synopsis>#include <talloc/talloc.h></synopsis>
+ </refsynopsisdiv>
+ <refsect1><title>DESCRIPTION</title>
+ <para>
+ If you are used to talloc from Samba3 then please read this
+ carefully, as talloc has changed a lot.
+ </para>
+ <para>
+ The new talloc is a hierarchical, reference counted memory pool
+ system with destructors. Quite a mouthful really, but not too bad
+ once you get used to it.
+ </para>
+ <para>
+ Perhaps the biggest change from Samba3 is that there is no
+ distinction between a "talloc context" and a "talloc pointer". Any
+ pointer returned from talloc() is itself a valid talloc context.
+ This means you can do this:
+ </para>
+ <programlisting>
+ struct foo *X = talloc(mem_ctx, struct foo);
+ X->name = talloc_strdup(X, "foo");
+ </programlisting>
+ <para>
+ and the pointer <literal role="code">X->name</literal>
+ would be a "child" of the talloc context <literal
+ role="code">X</literal> which is itself a child of
+ <literal role="code">mem_ctx</literal>. So if you do
+ <literal role="code">talloc_free(mem_ctx)</literal> then
+ it is all destroyed, whereas if you do <literal
+ role="code">talloc_free(X)</literal> then just <literal
+ role="code">X</literal> and <literal
+ role="code">X->name</literal> are destroyed, and if
+ you do <literal
+ role="code">talloc_free(X->name)</literal> then just
+ the name element of <literal role="code">X</literal> is
+ destroyed.
+ </para>
+ <para>
+ If you think about this, then what this effectively gives you is an
+ n-ary tree, where you can free any part of the tree with
+ talloc_free().
+ </para>
+ <para>
+ If you find this confusing, then I suggest you run the <literal
+ role="code">testsuite</literal> program to watch talloc
+ in action. You may also like to add your own tests to <literal
+ role="code">testsuite.c</literal> to clarify how some
+ particular situation is handled.
+ </para>
+ </refsect1>
+ <refsect1><title>TALLOC API</title>
+ <para>
+ The following is a complete guide to the talloc API. Read it all at
+ least twice.
+ </para>
+ <refsect2><title>(type *)talloc(const void *ctx, type);</title>
+ <para>
+ The talloc() macro is the core of the talloc library. It takes a
+ memory <emphasis role="italic">ctx</emphasis> and a <emphasis
+ role="italic">type</emphasis>, and returns a pointer to a new
+ area of memory of the given <emphasis
+ role="italic">type</emphasis>.
+ </para>
+ <para>
+ The returned pointer is itself a talloc context, so you can use
+ it as the <emphasis role="italic">ctx</emphasis> argument to more
+ calls to talloc() if you wish.
+ </para>
+ <para>
+ The returned pointer is a "child" of the supplied context. This
+ means that if you talloc_free() the <emphasis
+ role="italic">ctx</emphasis> then the new child disappears as
+ well. Alternatively you can free just the child.
+ </para>
+ <para>
+ The <emphasis role="italic">ctx</emphasis> argument to talloc()
+ can be NULL, in which case a new top level context is created.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_size(const void *ctx, size_t size);</title>
+ <para>
+ The function talloc_size() should be used when you don't have a
+ convenient type to pass to talloc(). Unlike talloc(), it is not
+ type safe (as it returns a void *), so you are on your own for
+ type checking.
+ </para>
+ </refsect2>
+ <refsect2><title>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</title>
+ <para>
+ The talloc_ptrtype() macro should be used when you have a pointer and
+ want to allocate memory to point at with this pointer. When compiling
+ with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+ and talloc_get_name() will return the current location in the source file.
+ and not the type.
+ </para>
+ </refsect2>
+ <refsect2><title>int talloc_free(void *ptr);</title>
+ <para>
+ The talloc_free() function frees a piece of talloc memory, and
+ all its children. You can call talloc_free() on any pointer
+ returned by talloc().
+ </para>
+ <para>
+ The return value of talloc_free() indicates success or failure,
+ with 0 returned for success and -1 for failure. The only
+ possible failure condition is if <emphasis
+ role="italic">ptr</emphasis> had a destructor attached to it and
+ the destructor returned -1. See <link
+ linkend="talloc_set_destructor"><quote>talloc_set_destructor()</quote></link>
+ for details on destructors.
+ </para>
+ <para>
+ If this pointer has an additional parent when talloc_free() is
+ called then the memory is not actually released, but instead the
+ most recently established parent is destroyed. See <link
+ linkend="talloc_reference"><quote>talloc_reference()</quote></link>
+ for details on establishing additional parents.
+ </para>
+ <para>
+ For more control on which parent is removed, see <link
+ linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+ </para>
+ <para>
+ talloc_free() operates recursively on its children.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_reference"><title>void *talloc_reference(const void *ctx, const void *ptr);</title>
+ <para>
+ The talloc_reference() function makes <emphasis
+ role="italic">ctx</emphasis> an additional parent of <emphasis
+ role="italic">ptr</emphasis>.
+ </para>
+ <para>
+ The return value of talloc_reference() is always the original
+ pointer <emphasis role="italic">ptr</emphasis>, unless talloc ran
+ out of memory in creating the reference in which case it will
+ return NULL (each additional reference consumes around 48 bytes
+ of memory on intel x86 platforms).
+ </para>
+ <para>
+ If <emphasis role="italic">ptr</emphasis> is NULL, then the
+ function is a no-op, and simply returns NULL.
+ </para>
+ <para>
+ After creating a reference you can free it in one of the
+ following ways:
+ </para>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ you can talloc_free() any parent of the original pointer.
+ That will reduce the number of parents of this pointer by 1,
+ and will cause this pointer to be freed if it runs out of
+ parents.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ you can talloc_free() the pointer itself. That will destroy
+ the most recently established parent to the pointer and leave
+ the pointer as a child of its current parent.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ For more control on which parent to remove, see <link
+ linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_unlink"><title>int talloc_unlink(const void *ctx, const void *ptr);</title>
+ <para>
+ The talloc_unlink() function removes a specific parent from
+ <emphasis role="italic">ptr</emphasis>. The <emphasis
+ role="italic">ctx</emphasis> passed must either be a context used
+ in talloc_reference() with this pointer, or must be a direct
+ parent of ptr.
+ </para>
+ <para>
+ Note that if the parent has already been removed using
+ talloc_free() then this function will fail and will return -1.
+ Likewise, if <emphasis role="italic">ptr</emphasis> is NULL, then
+ the function will make no modifications and return -1.
+ </para>
+ <para>
+ Usually you can just use talloc_free() instead of
+ talloc_unlink(), but sometimes it is useful to have the
+ additional control on which parent is removed.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_set_destructor"><title>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</title>
+ <para>
+ The function talloc_set_destructor() sets the <emphasis
+ role="italic">destructor</emphasis> for the pointer <emphasis
+ role="italic">ptr</emphasis>. A <emphasis
+ role="italic">destructor</emphasis> is a function that is called
+ when the memory used by a pointer is about to be released. The
+ destructor receives <emphasis role="italic">ptr</emphasis> as an
+ argument, and should return 0 for success and -1 for failure.
+ </para>
+ <para>
+ The <emphasis role="italic">destructor</emphasis> can do anything
+ it wants to, including freeing other pieces of memory. A common
+ use for destructors is to clean up operating system resources
+ (such as open file descriptors) contained in the structure the
+ destructor is placed on.
+ </para>
+ <para>
+ You can only place one destructor on a pointer. If you need more
+ than one destructor then you can create a zero-length child of
+ the pointer and place an additional destructor on that.
+ </para>
+ <para>
+ To remove a destructor call talloc_set_destructor() with NULL for
+ the destructor.
+ </para>
+ <para>
+ If your destructor attempts to talloc_free() the pointer that it
+ is the destructor for then talloc_free() will return -1 and the
+ free will be ignored. This would be a pointless operation
+ anyway, as the destructor is only called when the memory is just
+ about to go away.
+ </para>
+ </refsect2>
+ <refsect2><title>int talloc_increase_ref_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_increase_ref_count(<emphasis
+ role="italic">ptr</emphasis>) function is exactly equivalent to:
+ </para>
+ <programlisting>talloc_reference(NULL, ptr);</programlisting>
+ <para>
+ You can use either syntax, depending on which you think is
+ clearer in your code.
+ </para>
+ <para>
+ It returns 0 on success and -1 on failure.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_reference_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ Return the number of references to the pointer.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_set_name"><title>void talloc_set_name(const void *ptr, const char *fmt, ...);</title>
+ <para>
+ Each talloc pointer has a "name". The name is used principally
+ for debugging purposes, although it is also possible to set and
+ get the name on a pointer in as a way of "marking" pointers in
+ your code.
+ </para>
+ <para>
+ The main use for names on pointer is for "talloc reports". See
+ <link
+ linkend="talloc_report"><quote>talloc_report_depth_cb()</quote></link>,
+ <link
+ linkend="talloc_report"><quote>talloc_report_depth_file()</quote></link>,
+ <link
+ linkend="talloc_report"><quote>talloc_report()</quote></link>
+ <link
+ linkend="talloc_report"><quote>talloc_report()</quote></link>
+ and <link
+ linkend="talloc_report_full"><quote>talloc_report_full()</quote></link>
+ for details. Also see <link
+ linkend="talloc_enable_leak_report"><quote>talloc_enable_leak_report()</quote></link>
+ and <link
+ linkend="talloc_enable_leak_report_full"><quote>talloc_enable_leak_report_full()</quote></link>.
+ </para>
+ <para>
+ The talloc_set_name() function allocates memory as a child of the
+ pointer. It is logically equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</programlisting>
+ <para>
+ Note that multiple calls to talloc_set_name() will allocate more
+ memory without releasing the name. All of the memory is released
+ when the ptr is freed using talloc_free().
+ </para>
+ </refsect2>
+ <refsect2><title>void talloc_set_name_const(const void *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+ <para>
+ The function talloc_set_name_const() is just like
+ talloc_set_name(), but it takes a string constant, and is much
+ faster. It is extensively used by the "auto naming" macros, such
+ as talloc_p().
+ </para>
+ <para>
+ This function does not allocate any memory. It just copies the
+ supplied pointer into the internal representation of the talloc
+ ptr. This means you must not pass a <emphasis
+ role="italic">name</emphasis> pointer to memory that will
+ disappear before <emphasis role="italic">ptr</emphasis> is freed
+ with talloc_free().
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ The talloc_named() function creates a named talloc pointer. It
+ is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name(ptr, fmt, ....);</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_named_const(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+ <para>
+ This is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name_const(ptr, name);</programlisting>
+ </refsect2>
+ <refsect2><title>const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ This returns the current name for the given talloc pointer,
+ <emphasis role="italic">ptr</emphasis>. See <link
+ linkend="talloc_set_name"><quote>talloc_set_name()</quote></link>
+ for details.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ This function creates a zero length named talloc context as a top
+ level context. It is equivalent to:
+ </para>
+ <programlisting>talloc_named(NULL, 0, fmt, ...);</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_new(void *<emphasis role="italic">ctx</emphasis>);</title>
+ <para>
+ This is a utility macro that creates a new memory context hanging
+ off an exiting context, automatically naming it "talloc_new:
+ __location__" where __location__ is the source line it is called
+ from. It is particularly useful for creating a new temporary
+ working context.
+ </para>
+ </refsect2>
+ <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_realloc(const void *<emphasis role="italic">ctx</emphasis>, void *<emphasis role="italic">ptr</emphasis>, <emphasis role="italic">type</emphasis>, <emphasis role="italic">count</emphasis>);</title>
+ <para>
+ The talloc_realloc() macro changes the size of a talloc pointer.
+ It has the following equivalences:
+ </para>
+ <programlisting>talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr);</programlisting>
+ <para>
+ The <emphasis role="italic">ctx</emphasis> argument is only used
+ if <emphasis role="italic">ptr</emphasis> is not NULL, otherwise
+ it is ignored.
+ </para>
+ <para>
+ talloc_realloc() returns the new pointer, or NULL on failure.
+ The call will fail either due to a lack of memory, or because the
+ pointer has more than one parent (see <link
+ linkend="talloc_reference"><quote>talloc_reference()</quote></link>).
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</title>
+ <para>
+ the talloc_realloc_size() function is useful when the type is not
+ known so the type-safe talloc_realloc() cannot be used.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_steal() function changes the parent context of a
+ talloc pointer. It is typically used when the context that the
+ pointer is currently a child of is going to be freed and you wish
+ to keep the memory for a longer time.
+ </para>
+ <para>
+ The talloc_steal() function returns the pointer that you pass it.
+ It does not have any failure modes.
+ </para>
+ <para>
+ NOTE: It is possible to produce loops in the parent/child
+ relationship if you are not careful with talloc_steal(). No
+ guarantees are provided as to your sanity or the safety of your
+ data if you do this.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_move() function is a wrapper around
+ talloc_steal() which zeros the source pointer after the
+ move. This avoids a potential source of bugs where a
+ programmer leaves a pointer in two structures, and uses the
+ pointer from the old structure after it has been moved to a
+ new one.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_total_size() function returns the total size in bytes
+ used by this pointer and all child pointers. Mostly useful for
+ debugging.
+ </para>
+ <para>
+ Passing NULL is allowed, but it will only give a meaningful
+ result if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() has been called.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_total_blocks(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_total_blocks() function returns the total memory block
+ count used by this pointer and all child pointers. Mostly useful
+ for debugging.
+ </para>
+ <para>
+ Passing NULL is allowed, but it will only give a meaningful
+ result if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report"><title>void talloc_report(const void *ptr, FILE *f);</title>
+ <para>
+ The talloc_report() function prints a summary report of all
+ memory used by <emphasis role="italic">ptr</emphasis>. One line
+ of report is printed for each immediate child of ptr, showing the
+ total memory and number of blocks used by that child.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_full"><title>void talloc_report_full(const void *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>);</title>
+ <para>
+ This provides a more detailed report than talloc_report(). It
+ will recursively print the entire tree of memory referenced by
+ the pointer. References in the tree are shown by giving the name
+ of the pointer that is referenced.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_depth_cb">
+ <funcsynopsis><funcprototype>
+ <funcdef>void <function>talloc_report_depth_cb</function></funcdef>
+ <paramdef><parameter>const void *ptr</parameter></paramdef>
+ <paramdef><parameter>int depth</parameter></paramdef>
+ <paramdef><parameter>int max_depth</parameter></paramdef>
+ <paramdef><parameter>void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</parameter></paramdef>
+ <paramdef><parameter>void *priv</parameter></paramdef>
+ </funcprototype></funcsynopsis>
+ <para>
+ This provides a more flexible reports than talloc_report(). It
+ will recursively call the callback for the entire tree of memory
+ referenced by the pointer. References in the tree are passed with
+ <emphasis role="italic">is_ref = 1</emphasis> and the pointer that is referenced.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ <para>
+ The recursion is stopped when depth >= max_depth.
+ max_depth = -1 means only stop at leaf nodes.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_depth_file">
+ <funcsynopsis><funcprototype>
+ <funcdef>void <function>talloc_report_depth_file</function></funcdef>
+ <paramdef><parameter>const void *ptr</parameter></paramdef>
+ <paramdef><parameter>int depth</parameter></paramdef>
+ <paramdef><parameter>int max_depth</parameter></paramdef>
+ <paramdef><parameter>FILE *f</parameter></paramdef>
+ </funcprototype></funcsynopsis>
+ <para>
+ This provides a more flexible reports than talloc_report(). It
+ will let you specify the depth and max_depth.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_enable_leak_report"><title>void talloc_enable_leak_report(void);</title>
+ <para>
+ This enables calling of talloc_report(NULL, stderr) when the
+ program exits. In Samba4 this is enabled by using the
+ --leak-report command line option.
+ </para>
+ <para>
+ For it to be useful, this function must be called before any
+ other talloc function as it establishes a "null context" that
+ acts as the top of the tree. If you don't call this function
+ first then passing NULL to talloc_report() or
+ talloc_report_full() won't give you the full tree printout.
+ </para>
+ <para>
+ Here is a typical talloc report:
+ </para>
+ <screen format="linespecific">talloc report on 'null_context' (total 267 bytes in 15 blocks)
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+ </screen>
+ </refsect2>
+ <refsect2 id="talloc_enable_leak_report_full"><title>void talloc_enable_leak_report_full(void);</title>
+ <para>
+ This enables calling of talloc_report_full(NULL, stderr) when the
+ program exits. In Samba4 this is enabled by using the
+ --leak-report-full command line option.
+ </para>
+ <para>
+ For it to be useful, this function must be called before any
+ other talloc function as it establishes a "null context" that
+ acts as the top of the tree. If you don't call this function
+ first then passing NULL to talloc_report() or
+ talloc_report_full() won't give you the full tree printout.
+ </para>
+ <para>
+ Here is a typical full report:
+ </para>
+ <screen format="linespecific">full talloc report on 'root' (total 18 bytes in 8 blocks)
+p1 contains 18 bytes in 7 blocks (ref 0)
+ r1 contains 13 bytes in 2 blocks (ref 0)
+ reference to: p2
+ p2 contains 1 bytes in 1 blocks (ref 1)
+ x3 contains 1 bytes in 1 blocks (ref 0)
+ x2 contains 1 bytes in 1 blocks (ref 0)
+ x1 contains 1 bytes in 1 blocks (ref 0)
+ </screen>
+ </refsect2>
+ <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>);</title>
+ <para>
+ The talloc_zero() macro is equivalent to:
+ </para>
+ <programlisting>ptr = talloc(ctx, type);
+if (ptr) memset(ptr, 0, sizeof(type));</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>)</title>
+ <para>
+ The talloc_zero_size() function is useful when you don't have a
+ known type.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, size_t size);</title>
+ <para>
+ The talloc_memdup() function is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+if (ptr) memcpy(ptr, p, size);</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_strdup(const void *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>);</title>
+ <para>
+ The talloc_strdup() function is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, strlen(p)+1);
+if (ptr) memcpy(ptr, p, strlen(p)+1);</programlisting>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_strndup(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>);</title>
+ <para>
+ The talloc_strndup() function is the talloc equivalent of the C
+ library function strndup(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_append_string(const void *<emphasis role="italic">t</emphasis>, char *<emphasis role="italic">orig</emphasis>, const char *<emphasis role="italic">append</emphasis>);</title>
+ <para>
+ The talloc_append_string() function appends the given formatted
+ string to the given string.
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_vasprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>);</title>
+ <para>
+ The talloc_vasprintf() function is the talloc equivalent of the C
+ library function vasprintf(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ The talloc_asprintf() function is the talloc equivalent of the C
+ library function asprintf(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_asprintf_append(char *s, const char *fmt, ...);</title>
+ <para>
+ The talloc_asprintf_append() function appends the given formatted
+ string to the given string.
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>(type *)talloc_array(const void *ctx, type, uint_t count);</title>
+ <para>
+ The talloc_array() macro is equivalent to:
+ </para>
+ <programlisting>(type *)talloc_size(ctx, sizeof(type) * count);</programlisting>
+ <para>
+ except that it provides integer overflow protection for the
+ multiply, returning NULL if the multiply overflows.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_array_size(const void *ctx, size_t size, uint_t count);</title>
+ <para>
+ The talloc_array_size() function is useful when the type is not
+ known. It operates in the same way as talloc_array(), but takes a
+ size instead of a type.
+ </para>
+ </refsect2>
+ <refsect2><title>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count);</title>
+ <para>
+ The talloc_ptrtype() macro should be used when you have a pointer to an array
+ and want to allocate memory of an array to point at with this pointer. When compiling
+ with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+ and talloc_get_name() will return the current location in the source file.
+ and not the type.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</title>
+ <para>
+ This is a non-macro version of talloc_realloc(), which is useful
+ as libraries sometimes want a realloc function pointer. A
+ realloc(3) implementation encapsulates the functionality of
+ malloc(3), free(3) and realloc(3) in one call, which is why it is
+ useful to be able to pass around a single function pointer.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_autofree_context(void);</title>
+ <para>
+ This is a handy utility function that returns a talloc context
+ which will be automatically freed on program exit. This can be
+ used to reduce the noise in memory leak reports.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_check_name(const void *ptr, const char *name);</title>
+ <para>
+ This function checks if a pointer has the specified <emphasis
+ role="italic">name</emphasis>. If it does then the pointer is
+ returned. It it doesn't then NULL is returned.
+ </para>
+ </refsect2>
+ <refsect2><title>(type *)talloc_get_type(const void *ptr, type);</title>
+ <para>
+ This macro allows you to do type checking on talloc pointers. It
+ is particularly useful for void* private pointers. It is
+ equivalent to this:
+ </para>
+ <programlisting>(type *)talloc_check_name(ptr, #type)</programlisting>
+ </refsect2>
+ <refsect2><title>talloc_set_type(const void *ptr, type);</title>
+ <para>
+ This macro allows you to force the name of a pointer to be a
+ particular <emphasis>type</emphasis>. This can be
+ used in conjunction with talloc_get_type() to do type checking on
+ void* pointers.
+ </para>
+ <para>
+ It is equivalent to this:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, #type)</programlisting>
+ </refsect2>
+ </refsect1>
+ <refsect1><title>PERFORMANCE</title>
+ <para>
+ All the additional features of talloc(3) over malloc(3) do come at a
+ price. We have a simple performance test in Samba4 that measures
+ talloc() versus malloc() performance, and it seems that talloc() is
+ about 10% slower than malloc() on my x86 Debian Linux box. For
+ Samba, the great reduction in code complexity that we get by using
+ talloc makes this worthwhile, especially as the total overhead of
+ talloc/malloc in Samba is already quite small.
+ </para>
+ </refsect1>
+ <refsect1><title>SEE ALSO</title>
+ <para>
+ malloc(3), strndup(3), vasprintf(3), asprintf(3),
+ <ulink url="http://talloc.samba.org/"/>
+ </para>
+ </refsect1>
+ <refsect1><title>COPYRIGHT/LICENSE</title>
+ <para>
+ Copyright (C) Andrew Tridgell 2004
+ </para>
+ <para>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at
+ your option) any later version.
+ </para>
+ <para>
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ </para>
+ <para>
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ </para>
+ </refsect1>
+</refentry>
--- /dev/null
+/*
+ Samba Unix SMB/CIFS implementation.
+
+ Samba trivial allocation library - new interface
+
+ NOTE: Please read talloc_guide.txt for full documentation
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ inspired by http://swapped.cc/halloc/
+*/
+
+#include "talloc.h"
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+/* use this to force every realloc to change the pointer, to stress test
+ code that might not cope */
+#define ALWAYS_REALLOC 0
+
+
+#define MAX_TALLOC_SIZE 0x10000000
+#define TALLOC_MAGIC 0xe814ec70
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is called
+ on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(INTPTR_MIN)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* these macros gain us a few percent of speed on gcc */
+#if HAVE_BUILTIN_EXPECT
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) x
+#define unlikely(x) x
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() is called, otherwise it remains
+ NULL
+*/
+static void *null_context;
+static void *autofree_context;
+
+struct talloc_reference_handle {
+ struct talloc_reference_handle *next, *prev;
+ void *ptr;
+};
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_chunk {
+ struct talloc_chunk *next, *prev;
+ struct talloc_chunk *parent, *child;
+ struct talloc_reference_handle *refs;
+ talloc_destructor_t destructor;
+ const char *name;
+ size_t size;
+ unsigned flags;
+};
+
+/* 16 byte alignment seems to keep everyone happy */
+#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
+#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+
+/* panic if we get a bad magic value */
+static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+ const char *pp = (const char *)ptr;
+ struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
+ if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
+ if (tc->flags & TALLOC_FLAG_FREE) {
+ TALLOC_ABORT("Bad talloc magic value - double free");
+ } else {
+ TALLOC_ABORT("Bad talloc magic value - unknown value");
+ }
+ }
+ return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+ return the parent chunk of a pointer
+*/
+static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ while (tc->prev) tc=tc->prev;
+
+ return tc->parent;
+}
+
+void *talloc_parent(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
+}
+
+/*
+ find parents name
+*/
+const char *talloc_parent_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? tc->name : NULL;
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+static inline void *__talloc(const void *context, size_t size)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
+ if (unlikely(tc == NULL)) return NULL;
+
+ tc->size = size;
+ tc->flags = TALLOC_MAGIC;
+ tc->destructor = NULL;
+ tc->child = NULL;
+ tc->name = NULL;
+ tc->refs = NULL;
+
+ if (likely(context)) {
+ struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
+
+ if (parent->child) {
+ parent->child->parent = NULL;
+ tc->next = parent->child;
+ tc->next->prev = tc;
+ } else {
+ tc->next = NULL;
+ }
+ tc->parent = parent;
+ tc->prev = NULL;
+ parent->child = tc;
+ } else {
+ tc->next = tc->prev = tc->parent = NULL;
+ }
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ setup a destructor to be called on free of a pointer
+ the destructor should return 0 on success, or -1 on failure.
+ if the destructor fails then the free is failed, and the memory can
+ be continued to be used
+*/
+void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->destructor = destructor;
+}
+
+/*
+ increase the reference count on a piece of memory.
+*/
+int talloc_increase_ref_count(const void *ptr)
+{
+ if (unlikely(!talloc_reference(null_context, ptr))) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ helper for talloc_reference()
+
+ this is referenced by a function pointer and should not be inline
+*/
+static int talloc_reference_destructor(struct talloc_reference_handle *handle)
+{
+ struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
+ _TLIST_REMOVE(ptr_tc->refs, handle);
+ return 0;
+}
+
+/*
+ more efficient way to add a name to a pointer - the name must point to a
+ true string constant
+*/
+static inline void _talloc_set_name_const(const void *ptr, const char *name)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->name = name;
+}
+
+/*
+ internal talloc_named_const()
+*/
+static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
+{
+ void *ptr;
+
+ ptr = __talloc(context, size);
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ _talloc_set_name_const(ptr, name);
+
+ return ptr;
+}
+
+/*
+ make a secondary reference to a pointer, hanging off the given context.
+ the pointer remains valid until both the original caller and this given
+ context are freed.
+
+ the major use for this is when two different structures need to reference the
+ same underlying data, and you want to be able to free the two instances separately,
+ and in either order
+*/
+void *_talloc_reference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc;
+ struct talloc_reference_handle *handle;
+ if (unlikely(ptr == NULL)) return NULL;
+
+ tc = talloc_chunk_from_ptr(ptr);
+ handle = (struct talloc_reference_handle *)_talloc_named_const(context,
+ sizeof(struct talloc_reference_handle),
+ TALLOC_MAGIC_REFERENCE);
+ if (unlikely(handle == NULL)) return NULL;
+
+ /* note that we hang the destructor off the handle, not the
+ main context as that allows the caller to still setup their
+ own destructor on the context if they want to */
+ talloc_set_destructor(handle, talloc_reference_destructor);
+ handle->ptr = discard_const_p(void, ptr);
+ _TLIST_ADD(tc->refs, handle);
+ return handle->ptr;
+}
+
+
+/*
+ internal talloc_free call
+*/
+static inline int _talloc_free(void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return -1;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(tc->refs)) {
+ int is_child;
+ /* check this is a reference from a child or grantchild
+ * back to it's parent or grantparent
+ *
+ * in that case we need to remove the reference and
+ * call another instance of talloc_free() on the current
+ * pointer.
+ */
+ is_child = talloc_is_parent(tc->refs, ptr);
+ _talloc_free(tc->refs);
+ if (is_child) {
+ return _talloc_free(ptr);
+ }
+ return -1;
+ }
+
+ if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
+ /* we have a free loop - stop looping */
+ return 0;
+ }
+
+ if (unlikely(tc->destructor)) {
+ talloc_destructor_t d = tc->destructor;
+ if (d == (talloc_destructor_t)-1) {
+ return -1;
+ }
+ tc->destructor = (talloc_destructor_t)-1;
+ if (d(ptr) == -1) {
+ tc->destructor = d;
+ return -1;
+ }
+ tc->destructor = NULL;
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_talloc_free(child) == -1)) {
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ talloc_steal(new_parent, child);
+ }
+ }
+
+ tc->flags |= TALLOC_FLAG_FREE;
+ free(tc);
+ return 0;
+}
+
+/*
+ move a lump of memory from one talloc context to another return the
+ ptr on success, or NULL if it could not be transferred.
+ passing NULL as ptr will always return NULL with no side effects.
+*/
+void *_talloc_steal(const void *new_ctx, const void *ptr)
+{
+ struct talloc_chunk *tc, *new_tc;
+
+ if (unlikely(!ptr)) {
+ return NULL;
+ }
+
+ if (unlikely(new_ctx == NULL)) {
+ new_ctx = null_context;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(new_ctx == NULL)) {
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = tc->next = tc->prev = NULL;
+ return discard_const_p(void, ptr);
+ }
+
+ new_tc = talloc_chunk_from_ptr(new_ctx);
+
+ if (unlikely(tc == new_tc || tc->parent == new_tc)) {
+ return discard_const_p(void, ptr);
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = new_tc;
+ if (new_tc->child) new_tc->child->parent = NULL;
+ _TLIST_ADD(new_tc->child, tc);
+
+ return discard_const_p(void, ptr);
+}
+
+
+
+/*
+ remove a secondary reference to a pointer. This undo's what
+ talloc_reference() has done. The context and pointer arguments
+ must match those given to a talloc_reference()
+*/
+static inline int talloc_unreference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ for (h=tc->refs;h;h=h->next) {
+ struct talloc_chunk *p = talloc_parent_chunk(h);
+ if (p == NULL) {
+ if (context == NULL) break;
+ } else if (TC_PTR_FROM_CHUNK(p) == context) {
+ break;
+ }
+ }
+ if (h == NULL) {
+ return -1;
+ }
+
+ return _talloc_free(h);
+}
+
+/*
+ remove a specific parent context from a pointer. This is a more
+ controlled varient of talloc_free()
+*/
+int talloc_unlink(const void *context, void *ptr)
+{
+ struct talloc_chunk *tc_p, *new_p;
+ void *new_parent;
+
+ if (ptr == NULL) {
+ return -1;
+ }
+
+ if (context == NULL) {
+ context = null_context;
+ }
+
+ if (talloc_unreference(context, ptr) == 0) {
+ return 0;
+ }
+
+ if (context == NULL) {
+ if (talloc_parent_chunk(ptr) != NULL) {
+ return -1;
+ }
+ } else {
+ if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
+ return -1;
+ }
+ }
+
+ tc_p = talloc_chunk_from_ptr(ptr);
+
+ if (tc_p->refs == NULL) {
+ return _talloc_free(ptr);
+ }
+
+ new_p = talloc_parent_chunk(tc_p->refs);
+ if (new_p) {
+ new_parent = TC_PTR_FROM_CHUNK(new_p);
+ } else {
+ new_parent = NULL;
+ }
+
+ if (talloc_unreference(new_parent, ptr) != 0) {
+ return -1;
+ }
+
+ talloc_steal(new_parent, ptr);
+
+ return 0;
+}
+
+/*
+ add a name to an existing pointer - va_list version
+*/
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->name = talloc_vasprintf(ptr, fmt, ap);
+ if (likely(tc->name)) {
+ _talloc_set_name_const(tc->name, ".name");
+ }
+ return tc->name;
+}
+
+/*
+ add a name to an existing pointer
+*/
+const char *talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+ const char *name;
+ va_list ap;
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+ return name;
+}
+
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+
+ ptr = __talloc(context, size);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ return the name of a talloc ptr, or "UNNAMED"
+*/
+const char *talloc_get_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
+ return ".reference";
+ }
+ if (likely(tc->name)) {
+ return tc->name;
+ }
+ return "UNNAMED";
+}
+
+
+/*
+ check if a pointer has the given name. If it does, return the pointer,
+ otherwise return NULL
+*/
+void *talloc_check_name(const void *ptr, const char *name)
+{
+ const char *pname;
+ if (unlikely(ptr == NULL)) return NULL;
+ pname = talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+ return NULL;
+}
+
+
+/*
+ this is for compatibility with older versions of talloc
+*/
+void *talloc_init(const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+
+ /*
+ * samba3 expects talloc_report_depth_cb(NULL, ...)
+ * reports all talloc'ed memory, so we need to enable
+ * null_tracking
+ */
+ talloc_enable_null_tracking();
+
+ ptr = __talloc(NULL, 0);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+ should probably not be used in new code. It's in here to keep the talloc
+ code consistent across Samba 3 and 4.
+*/
+void talloc_free_children(void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_talloc_free(child) == -1)) {
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ talloc_steal(new_parent, child);
+ }
+ }
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+void *_talloc(const void *context, size_t size)
+{
+ return __talloc(context, size);
+}
+
+/*
+ externally callable talloc_set_name_const()
+*/
+void talloc_set_name_const(const void *ptr, const char *name)
+{
+ _talloc_set_name_const(ptr, name);
+}
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+ return _talloc_named_const(context, size, name);
+}
+
+/*
+ free a talloc pointer. This also frees all child pointers of this
+ pointer recursively
+
+ return 0 if the memory is actually freed, otherwise -1. The memory
+ will not be freed if the ref_count is > 1 or the destructor (if
+ any) returns non-zero
+*/
+int talloc_free(void *ptr)
+{
+ int saved_errno = errno, ret;
+ ret = _talloc_free(ptr);
+ if (ret == 0)
+ errno = saved_errno;
+ return ret;
+}
+
+
+
+/*
+ A talloc version of realloc. The context argument is only used if
+ ptr is NULL
+*/
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
+{
+ struct talloc_chunk *tc;
+ void *new_ptr;
+
+ /* size zero is equivalent to free() */
+ if (unlikely(size == 0)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ /* realloc(NULL) is equivalent to malloc() */
+ if (ptr == NULL) {
+ return _talloc_named_const(context, size, name);
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ /* don't allow realloc on referenced pointers */
+ if (unlikely(tc->refs)) {
+ return NULL;
+ }
+
+ /* by resetting magic we catch users of the old memory */
+ tc->flags |= TALLOC_FLAG_FREE;
+
+#if ALWAYS_REALLOC
+ new_ptr = malloc(size + TC_HDR_SIZE);
+ if (new_ptr) {
+ memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
+ free(tc);
+ }
+#else
+ new_ptr = realloc(tc, size + TC_HDR_SIZE);
+#endif
+ if (unlikely(!new_ptr)) {
+ tc->flags &= ~TALLOC_FLAG_FREE;
+ return NULL;
+ }
+
+ tc = (struct talloc_chunk *)new_ptr;
+ tc->flags &= ~TALLOC_FLAG_FREE;
+ if (tc->parent) {
+ tc->parent->child = tc;
+ }
+ if (tc->child) {
+ tc->child->parent = tc;
+ }
+
+ if (tc->prev) {
+ tc->prev->next = tc;
+ }
+ if (tc->next) {
+ tc->next->prev = tc;
+ }
+
+ tc->size = size;
+ _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ a wrapper around talloc_steal() for situations where you are moving a pointer
+ between two structures, and want the old pointer to be set to NULL
+*/
+void *_talloc_move(const void *new_ctx, const void *_pptr)
+{
+ const void **pptr = discard_const_p(const void *,_pptr);
+ void *ret = _talloc_steal(new_ctx, *pptr);
+ (*pptr) = NULL;
+ return ret;
+}
+
+/*
+ return the total size of a talloc pool (subtree)
+*/
+size_t talloc_total_size(const void *ptr)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ total = tc->size;
+ for (c=tc->child;c;c=c->next) {
+ total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the total number of blocks in a talloc pool (subtree)
+*/
+size_t talloc_total_blocks(const void *ptr)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ total++;
+ for (c=tc->child;c;c=c->next) {
+ total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the number of external references to a pointer
+*/
+size_t talloc_reference_count(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+ size_t ret = 0;
+
+ for (h=tc->refs;h;h=h->next) {
+ ret++;
+ }
+ return ret;
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data)
+{
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) return;
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return;
+ }
+
+ callback(ptr, depth, max_depth, 0, private_data);
+
+ if (max_depth >= 0 && depth >= max_depth) {
+ return;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+ for (c=tc->child;c;c=c->next) {
+ if (c->name == TALLOC_MAGIC_REFERENCE) {
+ struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
+ callback(h->ptr, depth + 1, max_depth, 1, private_data);
+ } else {
+ talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
+ }
+ }
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+}
+
+static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
+{
+ const char *name = talloc_get_name(ptr);
+ FILE *f = (FILE *)_f;
+
+ if (is_ref) {
+ fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+ return;
+ }
+
+ if (depth == 0) {
+ fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr));
+ return;
+ }
+
+ fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
+ depth*4, "",
+ name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ (int)talloc_reference_count(ptr), ptr);
+
+#if 0
+ fprintf(f, "content: ");
+ if (talloc_total_size(ptr)) {
+ int tot = talloc_total_size(ptr);
+ int i;
+
+ for (i = 0; i < tot; i++) {
+ if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
+ fprintf(f, "%c", ((char *)ptr)[i]);
+ } else {
+ fprintf(f, "~%02x", ((char *)ptr)[i]);
+ }
+ }
+ }
+ fprintf(f, "\n");
+#endif
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
+{
+ talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
+ fflush(f);
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_full(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, -1, f);
+}
+
+/*
+ report on memory usage by all children of a pointer
+*/
+void talloc_report(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, 1, f);
+}
+
+/*
+ report on any memory hanging off the null context
+*/
+static void talloc_report_null(void)
+{
+ if (talloc_total_size(null_context) != 0) {
+ talloc_report(null_context, stderr);
+ }
+}
+
+/*
+ report on any memory hanging off the null context
+*/
+static void talloc_report_null_full(void)
+{
+ if (talloc_total_size(null_context) != 0) {
+ talloc_report_full(null_context, stderr);
+ }
+}
+
+/*
+ enable tracking of the NULL context
+*/
+void talloc_enable_null_tracking(void)
+{
+ if (null_context == NULL) {
+ null_context = _talloc_named_const(NULL, 0, "null_context");
+ }
+}
+
+/*
+ disable tracking of the NULL context
+*/
+void talloc_disable_null_tracking(void)
+{
+ _talloc_free(null_context);
+ null_context = NULL;
+}
+
+/*
+ enable leak reporting on exit
+*/
+void talloc_enable_leak_report(void)
+{
+ talloc_enable_null_tracking();
+ atexit(talloc_report_null);
+}
+
+/*
+ enable full leak reporting on exit
+*/
+void talloc_enable_leak_report_full(void)
+{
+ talloc_enable_null_tracking();
+ atexit(talloc_report_null_full);
+}
+
+/*
+ talloc and zero memory.
+*/
+void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+ void *p = _talloc_named_const(ctx, size, name);
+
+ if (p) {
+ memset(p, '\0', size);
+ }
+
+ return p;
+}
+
+/*
+ memdup with a talloc.
+*/
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+ void *newp = _talloc_named_const(t, size, name);
+
+ if (likely(newp)) {
+ memcpy(newp, p, size);
+ }
+
+ return newp;
+}
+
+/*
+ strdup with a talloc
+*/
+char *talloc_strdup(const void *t, const char *p)
+{
+ char *ret;
+ if (!p) {
+ return NULL;
+ }
+ ret = (char *)talloc_memdup(t, p, strlen(p) + 1);
+ if (likely(ret)) {
+ _talloc_set_name_const(ret, ret);
+ }
+ return ret;
+}
+
+/*
+ append to a talloced string
+*/
+char *talloc_append_string(char *orig, const char *append)
+{
+ char *ret;
+ size_t olen = strlen(orig);
+ size_t alenz;
+
+ if (!append)
+ return orig;
+
+ alenz = strlen(append) + 1;
+
+ ret = talloc_realloc(NULL, orig, char, olen + alenz);
+ if (!ret)
+ return NULL;
+
+ /* append the string with the trailing \0 */
+ memcpy(&ret[olen], append, alenz);
+
+ _talloc_set_name_const(ret, ret);
+
+ return ret;
+}
+
+/*
+ strndup with a talloc
+*/
+char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+ size_t len;
+ char *ret;
+
+ for (len=0; len<n && p[len]; len++) ;
+
+ ret = (char *)__talloc(t, len + 1);
+ if (!ret) { return NULL; }
+ memcpy(ret, p, len);
+ ret[len] = 0;
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+ int len;
+ char *ret;
+ va_list ap2;
+ char c;
+
+ /* this call looks strange, but it makes it work on older solaris boxes */
+ va_copy(ap2, ap);
+ len = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+ if (len < 0) {
+ return NULL;
+ }
+
+ ret = (char *)__talloc(t, len+1);
+ if (ret) {
+ va_copy(ap2, ap);
+ vsnprintf(ret, len+1, fmt, ap2);
+ va_end(ap2);
+ _talloc_set_name_const(ret, ret);
+ }
+
+ return ret;
+}
+
+
+/*
+ Perform string formatting, and return a pointer to newly allocated
+ memory holding the result, inside a memory pool.
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Good for gradually
+ * accumulating output into a string buffer.
+ **/
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+ struct talloc_chunk *tc;
+ int len, s_len;
+ va_list ap2;
+ char c;
+
+ if (s == NULL) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ tc = talloc_chunk_from_ptr(s);
+
+ s_len = tc->size - 1;
+
+ va_copy(ap2, ap);
+ len = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+
+ if (len <= 0) {
+ /* Either the vsnprintf failed or the format resulted in
+ * no characters being formatted. In the former case, we
+ * ought to return NULL, in the latter we ought to return
+ * the original string. Most current callers of this
+ * function expect it to never return NULL.
+ */
+ return s;
+ }
+
+ s = talloc_realloc(NULL, s, char, s_len + len+1);
+ if (!s) return NULL;
+
+ va_copy(ap2, ap);
+ vsnprintf(s+s_len, len+1, fmt, ap2);
+ va_end(ap2);
+ _talloc_set_name_const(s, s);
+
+ return s;
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a string buffer.
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+/*
+ alloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+ alloc an zero array, checking for integer overflow in the array size
+*/
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_zero(ctx, el_size * count, name);
+}
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+ a function version of talloc_realloc(), so it can be passed as a function pointer
+ to libraries that want a realloc function (a realloc function encapsulates
+ all the basic capabilities of an allocation library, which is why this is useful)
+*/
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+ return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static int talloc_autofree_destructor(void *ptr)
+{
+ autofree_context = NULL;
+ return 0;
+}
+
+static void talloc_autofree(void)
+{
+ _talloc_free(autofree_context);
+}
+
+/*
+ return a context which will be auto-freed on exit
+ this is useful for reducing the noise in leak reports
+*/
+void *talloc_autofree_context(void)
+{
+ if (autofree_context == NULL) {
+ autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
+ talloc_set_destructor(autofree_context, talloc_autofree_destructor);
+ atexit(talloc_autofree);
+ }
+ return autofree_context;
+}
+
+size_t talloc_get_size(const void *context)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL)
+ return 0;
+
+ tc = talloc_chunk_from_ptr(context);
+
+ return tc->size;
+}
+
+/*
+ find a parent of this context that has the given name, if any
+*/
+void *talloc_find_parent_byname(const void *context, const char *name)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (tc->name && strcmp(tc->name, name) == 0) {
+ return TC_PTR_FROM_CHUNK(tc);
+ }
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return NULL;
+}
+
+/*
+ show the parentage of a context
+*/
+void talloc_show_parents(const void *context, FILE *file)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ fprintf(file, "talloc no parents for NULL\n");
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
+ while (tc) {
+ fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ fflush(file);
+}
+
+/*
+ return 1 if ptr is a parent of context
+*/
+int talloc_is_parent(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return 0;
+}
--- /dev/null
+#ifndef CCAN_TALLOC_H
+#define CCAN_TALLOC_H
+/*
+ Copyright (C) Andrew Tridgell 2004-2005
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "config.h"
+#include "ccan/typesafe_cb/typesafe_cb.h"
+
+/*
+ this uses a little trick to allow __LINE__ to be stringified
+*/
+#ifndef __location__
+#define __TALLOC_STRING_LINE1__(s) #s
+#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
+#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
+#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
+#endif
+
+#if HAVE_ATTRIBUTE_PRINTF
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+
+/* try to make talloc_set_destructor() and talloc_steal() type safe,
+ if we have a recent gcc */
+#if HAVE_TYPEOF
+#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
+#else
+#define _TALLOC_TYPEOF(ptr) void *
+#endif
+
+#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
+
+/**
+ * talloc - allocate dynamic memory for a type
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @type: the type to be allocated.
+ *
+ * The talloc() macro is the core of the talloc library. It takes a memory
+ * context and a type, and returns a pointer to a new area of memory of the
+ * given type.
+ *
+ * The returned pointer is itself a talloc context, so you can use it as the
+ * context argument to more calls to talloc if you wish.
+ *
+ * The returned pointer is a "child" of @ctx. This means that if you
+ * talloc_free() @ctx then the new child disappears as well. Alternatively you
+ * can free just the child.
+ *
+ * @ctx can be NULL, in which case a new top level context is created.
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ *
+ * See Also:
+ * talloc_zero, talloc_array, talloc_steal, talloc_free.
+ */
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+
+/**
+ * talloc_free - free talloc'ed memory and its children
+ * @ptr: the talloced pointer to free
+ *
+ * The talloc_free() function frees a piece of talloc memory, and all its
+ * children. You can call talloc_free() on any pointer returned by talloc().
+ *
+ * The return value of talloc_free() indicates success or failure, with 0
+ * returned for success and -1 for failure. The only possible failure condition
+ * is if the pointer had a destructor attached to it and the destructor
+ * returned -1. See talloc_set_destructor() for details on destructors.
+ * errno will be preserved unless the talloc_free fails.
+ *
+ * If this pointer has an additional parent when talloc_free() is called then
+ * the memory is not actually released, but instead the most recently
+ * established parent is destroyed. See talloc_reference() for details on
+ * establishing additional parents.
+ *
+ * For more control on which parent is removed, see talloc_unlink().
+ *
+ * talloc_free() operates recursively on its children.
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * // Frees a and b
+ * talloc_free(a);
+ *
+ * See Also:
+ * talloc_set_destructor, talloc_unlink
+ */
+int talloc_free(void *ptr);
+
+/**
+ * talloc_set_destructor: set a destructor for when this pointer is freed
+ * @ptr: the talloc pointer to set the destructor on
+ * @destructor: the function to be called
+ *
+ * The function talloc_set_destructor() sets the "destructor" for the pointer
+ * @ptr. A destructor is a function that is called when the memory used by a
+ * pointer is about to be released. The destructor receives the pointer as an
+ * argument, and should return 0 for success and -1 for failure.
+ *
+ * The destructor can do anything it wants to, including freeing other pieces
+ * of memory. A common use for destructors is to clean up operating system
+ * resources (such as open file descriptors) contained in the structure the
+ * destructor is placed on.
+ *
+ * You can only place one destructor on a pointer. If you need more than one
+ * destructor then you can create a zero-length child of the pointer and place
+ * an additional destructor on that.
+ *
+ * To remove a destructor call talloc_set_destructor() with NULL for the
+ * destructor.
+ *
+ * If your destructor attempts to talloc_free() the pointer that it is the
+ * destructor for then talloc_free() will return -1 and the free will be
+ * ignored. This would be a pointless operation anyway, as the destructor is
+ * only called when the memory is just about to go away.
+ *
+ * Example:
+ * static int destroy_fd(int *fd)
+ * {
+ * close(*fd);
+ * return 0;
+ * }
+ *
+ * int *open_file(const char *filename)
+ * {
+ * int *fd = talloc(NULL, int);
+ * *fd = open(filename, O_RDONLY);
+ * if (*fd < 0) {
+ * talloc_free(fd);
+ * return NULL;
+ * }
+ * // Whenever they free this, we close the file.
+ * talloc_set_destructor(fd, destroy_fd);
+ * return fd;
+ * }
+ *
+ * See Also:
+ * talloc, talloc_free
+ */
+#define talloc_set_destructor(ptr, function) \
+ _talloc_set_destructor((ptr), typesafe_cb(int, (function), (ptr)))
+
+/**
+ * talloc_zero - allocate zeroed dynamic memory for a type
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @type: the type to be allocated.
+ *
+ * The talloc_zero() macro is equivalent to:
+ *
+ * ptr = talloc(ctx, type);
+ * if (ptr) memset(ptr, 0, sizeof(type));
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc_zero(NULL, unsigned int);
+ * b = talloc_zero(a, unsigned int);
+ *
+ * See Also:
+ * talloc, talloc_zero_size, talloc_zero_array
+ */
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+
+/**
+ * talloc_array - allocate dynamic memory for an array of a given type
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @type: the type to be allocated.
+ * @count: the number of elements to be allocated.
+ *
+ * The talloc_array() macro is a safe way of allocating an array. It is
+ * equivalent to:
+ *
+ * (type *)talloc_size(ctx, sizeof(type) * count);
+ *
+ * except that it provides integer overflow protection for the multiply,
+ * returning NULL if the multiply overflows.
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc_zero(NULL, unsigned int);
+ * b = talloc_array(a, unsigned int, 100);
+ *
+ * See Also:
+ * talloc, talloc_zero_array
+ */
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+
+/**
+ * talloc_size - allocate a particular size of memory
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @size: the number of bytes to allocate
+ *
+ * The function talloc_size() should be used when you don't have a convenient
+ * type to pass to talloc(). Unlike talloc(), it is not type safe (as it
+ * returns a void *), so you are on your own for type checking.
+ *
+ * Best to use talloc() or talloc_array() instead.
+ *
+ * Example:
+ * void *mem = talloc_size(NULL, 100);
+ *
+ * See Also:
+ * talloc, talloc_array, talloc_zero_size
+ */
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+
+#ifdef HAVE_TYPEOF
+/**
+ * talloc_steal - change/set the parent context of a talloc pointer
+ * @ctx: the new parent
+ * @ptr: the talloc pointer to reparent
+ *
+ * The talloc_steal() function changes the parent context of a talloc
+ * pointer. It is typically used when the context that the pointer is currently
+ * a child of is going to be freed and you wish to keep the memory for a longer
+ * time.
+ *
+ * The talloc_steal() function returns the pointer that you pass it. It does
+ * not have any failure modes.
+ *
+ * NOTE: It is possible to produce loops in the parent/child relationship if
+ * you are not careful with talloc_steal(). No guarantees are provided as to
+ * your sanity or the safety of your data if you do this.
+ *
+ * talloc_steal (new_ctx, NULL) will return NULL with no sideeffects.
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(NULL, unsigned int);
+ * // Reparent b to a as if we'd done 'b = talloc(a, unsigned int)'.
+ * talloc_steal(a, b);
+ *
+ * See Also:
+ * talloc_reference
+ */
+#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) _talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); _talloc_steal_ret; }) /* this extremely strange macro is to avoid some braindamaged warning stupidity in gcc 4.1.x */
+#else
+#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
+#endif /* HAVE_TYPEOF */
+
+/**
+ * talloc_report_full - report all the memory used by a pointer and children.
+ * @ptr: the context to report on
+ * @f: the file to report to
+ *
+ * Recursively print the entire tree of memory referenced by the
+ * pointer. References in the tree are shown by giving the name of the pointer
+ * that is referenced.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed for the
+ * top level memory context, but only if talloc_enable_null_tracking() has been
+ * called.
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * fprintf(stderr, "Dumping memory tree for a:\n");
+ * talloc_report_full(a, stderr);
+ *
+ * See Also:
+ * talloc_report
+ */
+void talloc_report_full(const void *ptr, FILE *f);
+
+/**
+ * talloc_reference - add an additional parent to a context
+ * @ctx: the additional parent
+ * @ptr: the talloc pointer
+ *
+ * The talloc_reference() function makes @ctx an additional parent of @ptr.
+ *
+ * The return value of talloc_reference() is always the original pointer @ptr,
+ * unless talloc ran out of memory in creating the reference in which case it
+ * will return NULL (each additional reference consumes around 48 bytes of
+ * memory on intel x86 platforms).
+ *
+ * If @ptr is NULL, then the function is a no-op, and simply returns NULL.
+ *
+ * After creating a reference you can free it in one of the following ways:
+ *
+ * - you can talloc_free() any parent of the original pointer. That will
+ * reduce the number of parents of this pointer by 1, and will cause this
+ * pointer to be freed if it runs out of parents.
+ *
+ * - you can talloc_free() the pointer itself. That will destroy the most
+ * recently established parent to the pointer and leave the pointer as a
+ * child of its current parent.
+ *
+ * For more control on which parent to remove, see talloc_unlink().
+ * Example:
+ * unsigned int *a, *b, *c;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(NULL, unsigned int);
+ * c = talloc(a, unsigned int);
+ * // b also serves as a parent of c.
+ * talloc_reference(b, c);
+ */
+#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
+
+/**
+ * talloc_unlink: remove a specific parent from a talloc pointer.
+ * @context: the parent to remove
+ * @ptr: the talloc pointer
+ *
+ * The talloc_unlink() function removes a specific parent from @ptr. The
+ * context passed must either be a context used in talloc_reference() with this
+ * pointer, or must be a direct parent of @ptr.
+ *
+ * Note that if the parent has already been removed using talloc_free() then
+ * this function will fail and will return -1. Likewise, if @ptr is NULL,
+ * then the function will make no modifications and return -1.
+ *
+ * Usually you can just use talloc_free() instead of talloc_unlink(), but
+ * sometimes it is useful to have the additional control on which parent is
+ * removed.
+ * Example:
+ * unsigned int *a, *b, *c;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(NULL, unsigned int);
+ * c = talloc(a, unsigned int);
+ * // b also serves as a parent of c.
+ * talloc_reference(b, c);
+ * talloc_unlink(b, c);
+ */
+int talloc_unlink(const void *context, void *ptr);
+
+/**
+ * talloc_report - print a summary of memory used by a pointer
+ *
+ * The talloc_report() function prints a summary report of all memory
+ * used by @ptr. One line of report is printed for each immediate child of
+ * @ptr, showing the total memory and number of blocks used by that child.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed for the
+ * top level memory context, but only if talloc_enable_null_tracking() has been
+ * called.
+ *
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * fprintf(stderr, "Summary of memory tree for a:\n");
+ * talloc_report(a, stderr);
+ *
+ * See Also:
+ * talloc_report_full
+ */
+void talloc_report(const void *ptr, FILE *f);
+
+/**
+ * talloc_ptrtype - allocate a size of memory suitable for this pointer
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @ptr: the pointer whose type we are to allocate
+ *
+ * The talloc_ptrtype() macro should be used when you have a pointer and
+ * want to allocate memory to point at with this pointer. When compiling
+ * with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+ * and talloc_get_name() will return the current location in the source file.
+ * and not the type.
+ *
+ * Example:
+ * unsigned int *a = talloc_ptrtype(NULL, a);
+ */
+#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
+
+/**
+ * talloc_free_children - free talloc'ed memory's children only
+ * @ptr: the talloced pointer whose children we want to free
+ *
+ * talloc_free_children() walks along the list of all children of a talloc
+ * context @ptr and talloc_free()s only the children, not the context itself.
+ * Example:
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * // Frees b
+ * talloc_free_children(a);
+ */
+void talloc_free_children(void *ptr);
+
+/**
+ * talloc_new - create a new context
+ * @ctx: the context to use as a parent.
+ *
+ * This is a utility macro that creates a new memory context hanging off an
+ * exiting context, automatically naming it "talloc_new: __location__" where
+ * __location__ is the source line it is called from. It is particularly useful
+ * for creating a new temporary working context.
+ */
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+
+/**
+ * talloc_zero_size - allocate a particular size of zeroed memory
+ *
+ * The talloc_zero_size() function is useful when you don't have a known type.
+ */
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+
+/**
+ * talloc_zero_array - allocate an array of zeroed types
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @type: the type to be allocated.
+ * @count: the number of elements to be allocated.
+ *
+ * Just like talloc_array, but zeroes the memory.
+ */
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+
+/**
+ * talloc_zero_array - allocate an array of zeroed types
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @type: the type to be allocated.
+ * @count: the number of elements to be allocated.
+ *
+ * Just like talloc_array, but zeroes the memory.
+ */
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+
+/**
+ * talloc_array_ptrtype - allocate an array of memory suitable for this pointer
+ * @ctx: context to be parent of this allocation, or NULL.
+ * @ptr: the pointer whose type we are to allocate
+ * @count: the number of elements for the array
+ *
+ * Like talloc_ptrtype(), except it allocates an array.
+ */
+#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
+
+/**
+ * talloc_realloc - resize a talloc array
+ * @ctx: the parent to assign (if p is NULL)
+ * @p: the memory to reallocate
+ * @type: the type of the object to allocate
+ * @count: the number of objects to reallocate
+ *
+ * The talloc_realloc() macro changes the size of a talloc pointer. The "count"
+ * argument is the number of elements of type "type" that you want the
+ * resulting pointer to hold.
+ *
+ * talloc_realloc() has the following equivalences:
+ *
+ * talloc_realloc(context, NULL, type, 1) ==> talloc(context, type);
+ * talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N);
+ * talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr);
+ *
+ * The "context" argument is only used if "ptr" is NULL, otherwise it is
+ * ignored.
+ *
+ * talloc_realloc() returns the new pointer, or NULL on failure. The call will
+ * fail either due to a lack of memory, or because the pointer has more than
+ * one parent (see talloc_reference()).
+ */
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+
+/**
+ * talloc_realloc_size - resize talloc memory
+ * @ctx: the parent to assign (if p is NULL)
+ * @ptr: the memory to reallocate
+ * @size: the new size of memory.
+ *
+ * The talloc_realloc_size() function is useful when the type is not known so
+ * the typesafe talloc_realloc() cannot be used.
+ */
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+
+/**
+ * talloc_strdup - duplicate a string
+ * @ctx: the talloc context for the new string
+ * @p: the string to copy
+ *
+ * The talloc_strdup() function is equivalent to:
+ *
+ * ptr = talloc_size(ctx, strlen(p)+1);
+ * if (ptr) memcpy(ptr, p, strlen(p)+1);
+ *
+ * This functions sets the name of the new pointer to the passed string. This
+ * is equivalent to:
+ *
+ * talloc_set_name_const(ptr, ptr)
+ */
+char *talloc_strdup(const void *t, const char *p);
+
+/**
+ * talloc_strndup - duplicate a limited length of a string
+ * @ctx: the talloc context for the new string
+ * @p: the string to copy
+ * @n: the maximum length of the returned string.
+ *
+ * The talloc_strndup() function is the talloc equivalent of the C library
+ * function strndup(): the result will be truncated to @n characters before
+ * the nul terminator.
+ *
+ * This functions sets the name of the new pointer to the passed string. This
+ * is equivalent to:
+ *
+ * talloc_set_name_const(ptr, ptr)
+ */
+char *talloc_strndup(const void *t, const char *p, size_t n);
+
+/**
+ * talloc_memdup - duplicate some talloc memory
+ *
+ * The talloc_memdup() function is equivalent to:
+ *
+ * ptr = talloc_size(ctx, size);
+ * if (ptr) memcpy(ptr, p, size);
+ */
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+
+/**
+ * talloc_asprintf - sprintf into a talloc buffer.
+ * @t: The context to allocate the buffer from
+ * @fmt: printf-style format for the buffer.
+ *
+ * The talloc_asprintf() function is the talloc equivalent of the C library
+ * function asprintf().
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * talloc_set_name_const(ptr, ptr)
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * talloc_append_string - concatenate onto a tallocated string
+ * @orig: the tallocated string to append to
+ * @append: the string to add, or NULL to add nothing.
+ *
+ * The talloc_append_string() function appends the given formatted string to
+ * the given string.
+ *
+ * This function sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * talloc_set_name_const(ptr, ptr)
+ */
+char *talloc_append_string(char *orig, const char *append);
+
+/**
+ * talloc_asprintf_append - sprintf onto the end of a talloc buffer.
+ * @s: The tallocated string buffer
+ * @fmt: printf-style format to append to the buffer.
+ *
+ * The talloc_asprintf_append() function appends the given formatted string to
+ * the given string.
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ * talloc_set_name_const(ptr, ptr)
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * talloc_vasprintf - vsprintf into a talloc buffer.
+ * @t: The context to allocate the buffer from
+ * @fmt: printf-style format for the buffer
+ * @ap: va_list arguments
+ *
+ * The talloc_vasprintf() function is the talloc equivalent of the C library
+ * function vasprintf()
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * talloc_set_name_const(ptr, ptr)
+ */
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * talloc_vasprintf_append - sprintf onto the end of a talloc buffer.
+ * @t: The context to allocate the buffer from
+ * @fmt: printf-style format for the buffer
+ * @ap: va_list arguments
+ *
+ * The talloc_vasprintf_append() function is equivalent to
+ * talloc_asprintf_append(), except it takes a va_list.
+ */
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * talloc_set_type - force the name of a pointer to a particular type
+ * @ptr: the talloc pointer
+ * @type: the type whose name to set the ptr name to.
+ *
+ * This macro allows you to force the name of a pointer to be a particular
+ * type. This can be used in conjunction with talloc_get_type() to do type
+ * checking on void* pointers.
+ *
+ * It is equivalent to this:
+ * talloc_set_name_const(ptr, #type)
+ */
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+
+/**
+ * talloc_get_type - convert a talloced pointer with typechecking
+ * @ptr: the talloc pointer
+ * @type: the type which we expect the talloced pointer to be.
+ *
+ * This macro allows you to do type checking on talloc pointers. It is
+ * particularly useful for void* private pointers. It is equivalent to this:
+ *
+ * (type *)talloc_check_name(ptr, #type)
+ */
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+
+/**
+ * talloc_find_parent_byname - find a talloc parent by type
+ * @ptr: the talloc pointer
+ * @type: the type we're looking for
+ *
+ * Find a parent memory context of the current context that has the given
+ * name. This can be very useful in complex programs where it may be difficult
+ * to pass all information down to the level you need, but you know the
+ * structure you want is a parent of another context.
+ */
+#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
+
+/**
+ * talloc_increase_ref_count - hold a reference to a talloc pointer
+ * @ptr: the talloc pointer
+ *
+ * The talloc_increase_ref_count(ptr) function is exactly equivalent to:
+ *
+ * talloc_reference(NULL, ptr);
+ *
+ * You can use either syntax, depending on which you think is clearer in your
+ * code.
+ *
+ * It returns 0 on success and -1 on failure.
+ */
+int talloc_increase_ref_count(const void *ptr);
+
+/**
+ * talloc_set_name - set the name for a talloc pointer
+ * @ptr: the talloc pointer
+ * @fmt: the printf-style format string for the name
+ *
+ * Each talloc pointer has a "name". The name is used principally for debugging
+ * purposes, although it is also possible to set and get the name on a pointer
+ * in as a way of "marking" pointers in your code.
+ *
+ * The main use for names on pointer is for "talloc reports". See
+ * talloc_report() and talloc_report_full() for details. Also see
+ * talloc_enable_leak_report() and talloc_enable_leak_report_full().
+ *
+ * The talloc_set_name() function allocates memory as a child of the
+ * pointer. It is logically equivalent to:
+ * talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+ *
+ * Note that multiple calls to talloc_set_name() will allocate more memory
+ * without releasing the name. All of the memory is released when the ptr is
+ * freed using talloc_free().
+ */
+const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * talloc_set_name_const - set a talloc pointer name to a string constant
+ * @ptr: the talloc pointer to name
+ * @name: the strucng constant.
+ *
+ * The function talloc_set_name_const() is just like talloc_set_name(), but it
+ * takes a string constant, and is much faster. It is extensively used by the
+ * "auto naming" macros, such as talloc().
+ *
+ * This function does not allocate any memory. It just copies the supplied
+ * pointer into the internal representation of the talloc ptr. This means you
+ * must not pass a name pointer to memory that will disappear before the ptr is
+ * freed with talloc_free().
+ */
+void talloc_set_name_const(const void *ptr, const char *name);
+
+/**
+ * talloc_named - create a specifically-named talloc pointer
+ * @context: the parent context for the allocation
+ * @size: the size to allocate
+ * @fmt: the printf-style format for the name
+ *
+ * The talloc_named() function creates a named talloc pointer. It is equivalent
+ * to:
+ *
+ * ptr = talloc_size(context, size);
+ * talloc_set_name(ptr, fmt, ....);
+ */
+void *talloc_named(const void *context, size_t size,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+/**
+ * talloc_named_const - create a specifically-named talloc pointer
+ * @context: the parent context for the allocation
+ * @size: the size to allocate
+ * @name: the string constant to use as the name
+ *
+ * This is equivalent to:
+ *
+ * ptr = talloc_size(context, size);
+ * talloc_set_name_const(ptr, name);
+ */
+void *talloc_named_const(const void *context, size_t size, const char *name);
+
+/**
+ * talloc_get_name - get the name of a talloc pointer
+ * @ptr: the talloc pointer
+ *
+ * This returns the current name for the given talloc pointer. See
+ * talloc_set_name() for details.
+ */
+const char *talloc_get_name(const void *ptr);
+
+/**
+ * talloc_check_name - check if a pointer has the specified name
+ * @ptr: the talloc pointer
+ * @name: the name to compare with the pointer's name
+ *
+ * This function checks if a pointer has the specified name. If it does then
+ * the pointer is returned. It it doesn't then NULL is returned.
+ */
+void *talloc_check_name(const void *ptr, const char *name);
+
+/**
+ * talloc_init - create a top-level context of particular name
+ * @fmt: the printf-style format of the name
+ *
+ * This function creates a zero length named talloc context as a top level
+ * context. It is equivalent to:
+ *
+ * talloc_named(NULL, 0, fmt, ...);
+ */
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+
+/**
+ * talloc_total_size - get the bytes used by the pointer and its children
+ * @ptr: the talloc pointer
+ *
+ * The talloc_total_size() function returns the total size in bytes used by
+ * this pointer and all child pointers. Mostly useful for debugging.
+ *
+ * Passing NULL is allowed, but it will only give a meaningful result if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has been
+ * called.
+ */
+size_t talloc_total_size(const void *ptr);
+
+/**
+ * talloc_total_blocks - get the number of allocations for the pointer
+ * @ptr: the talloc pointer
+ *
+ * The talloc_total_blocks() function returns the total allocations used by
+ * this pointer and all child pointers. Mostly useful for debugging. For
+ * example, a pointer with no children will return "1".
+ *
+ * Passing NULL is allowed, but it will only give a meaningful result if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has been
+ * called.
+ */
+size_t talloc_total_blocks(const void *ptr);
+
+/**
+ * talloc_report_depth_cb - walk the entire talloc tree under a talloc pointer
+ * @ptr: the talloc pointer to recurse under
+ * @depth: the current depth of traversal
+ * @max_depth: maximum depth to traverse, or -1 for no maximum
+ * @callback: the function to call on each pointer
+ * @private_data: pointer to hand to @callback.
+ *
+ * This provides a more flexible reports than talloc_report(). It will
+ * recursively call the callback for the entire tree of memory referenced by
+ * the pointer. References in the tree are passed with is_ref = 1 and the
+ * pointer that is referenced.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed for the
+ * top level memory context, but only if talloc_enable_leak_report() or
+ * talloc_enable_leak_report_full() has been called.
+ *
+ * The recursion is stopped when depth >= max_depth. max_depth = -1 means only
+ * stop at leaf nodes.
+ */
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data);
+
+/**
+ * talloc_report_depth_file - report talloc usage to a maximum depth
+ * @ptr: the talloc pointer to recurse under
+ * @depth: the current depth of traversal
+ * @max_depth: maximum depth to traverse, or -1 for no maximum
+ * @f: the file to report to
+ *
+ * This provides a more flexible reports than talloc_report(). It will let you
+ * specify the depth and max_depth.
+ */
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+
+/**
+ * talloc_enable_null_tracking - enable tracking of top-level tallocs
+ *
+ * This enables tracking of the NULL memory context without enabling leak
+ * reporting on exit. Useful for when you want to do your own leak reporting
+ * call via talloc_report_null_full();
+ */
+void talloc_enable_null_tracking(void);
+
+/**
+ * talloc_disable_null_tracking - enable tracking of top-level tallocs
+ *
+ * This disables tracking of the NULL memory context.
+ */
+void talloc_disable_null_tracking(void);
+
+/**
+ * talloc_enable_leak_report - call talloc_report on program exit
+ *
+ * This enables calling of talloc_report(NULL, stderr) when the program
+ * exits. In Samba4 this is enabled by using the --leak-report command line
+ * option.
+ *
+ * For it to be useful, this function must be called before any other talloc
+ * function as it establishes a "null context" that acts as the top of the
+ * tree. If you don't call this function first then passing NULL to
+ * talloc_report() or talloc_report_full() won't give you the full tree
+ * printout.
+ *
+ * Here is a typical talloc report:
+ *
+ * talloc report on 'null_context' (total 267 bytes in 15 blocks)
+ * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ * iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+ * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ * iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+ * iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+ * iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+ */
+void talloc_enable_leak_report(void);
+
+/**
+ * talloc_enable_leak_report - call talloc_report_full on program exit
+ *
+ * This enables calling of talloc_report_full(NULL, stderr) when the program
+ * exits. In Samba4 this is enabled by using the --leak-report-full command
+ * line option.
+ *
+ * For it to be useful, this function must be called before any other talloc
+ * function as it establishes a "null context" that acts as the top of the
+ * tree. If you don't call this function first then passing NULL to
+ * talloc_report() or talloc_report_full() won't give you the full tree
+ * printout.
+ *
+ * Here is a typical full report:
+ *
+ * full talloc report on 'root' (total 18 bytes in 8 blocks)
+ * p1 contains 18 bytes in 7 blocks (ref 0)
+ * r1 contains 13 bytes in 2 blocks (ref 0)
+ * reference to: p2
+ * p2 contains 1 bytes in 1 blocks (ref 1)
+ * x3 contains 1 bytes in 1 blocks (ref 0)
+ * x2 contains 1 bytes in 1 blocks (ref 0)
+ * x1 contains 1 bytes in 1 blocks (ref 0)
+ */
+void talloc_enable_leak_report_full(void);
+
+/**
+ * talloc_autofree_context - a context which will be freed at exit
+ *
+ * This is a handy utility function that returns a talloc context which will be
+ * automatically freed on program exit. This can be used to reduce the noise in
+ * memory leak reports.
+ */
+void *talloc_autofree_context(void);
+
+/**
+ * talloc_get_size - get the size of an allocation
+ * @ctx: the talloc pointer whose allocation to measure.
+ *
+ * This function lets you know the amount of memory alloced so far by this
+ * context. It does NOT account for subcontext memory. This can be used to
+ * calculate the size of an array.
+ */
+size_t talloc_get_size(const void *ctx);
+
+/**
+ * talloc_find_parent_byname - find a parent of this context with this name
+ * @ctx: the context whose ancestors to search
+ * @name: the name to look for
+ *
+ * Find a parent memory context of @ctx that has the given name. This can be
+ * very useful in complex programs where it may be difficult to pass all
+ * information down to the level you need, but you know the structure you want
+ * is a parent of another context.
+ */
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+
+/* The following definitions come from talloc.c */
+void *_talloc(const void *context, size_t size);
+void _talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+size_t talloc_reference_count(const void *ptr);
+void *_talloc_reference(const void *context, const void *ptr);
+
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+void *talloc_parent(const void *ptr);
+const char *talloc_parent_name(const void *ptr);
+void *_talloc_steal(const void *new_ctx, const void *ptr);
+void *_talloc_move(const void *new_ctx, const void *pptr);
+void *_talloc_zero(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+void talloc_show_parents(const void *context, FILE *file);
+int talloc_is_parent(const void *context, const void *ptr);
+
+#endif /* CCAN_TALLOC_H */
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of talloc routines.
+
+ Copyright (C) Andrew Tridgell 2004
+ Converted to ccan tests by Rusty Russell 2008
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "talloc/talloc.c"
+#include <stdbool.h>
+#include "tap/tap.h"
+
+#define torture_assert(test, expr, str) \
+ ok(expr, "failure: %s [\n%s: Expression %s failed: %s\n]\n", \
+ test, __location__, #expr, str)
+
+#define torture_assert_str_equal(test, arg1, arg2, desc) \
+ ok(strcmp(arg1, arg2) == 0, \
+ "failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
+ test, __location__, arg1, arg2, desc)
+
+#define CHECK_SIZE(test, ptr, tsize) \
+ ok(talloc_total_size(ptr) == (tsize), \
+ "failed: %s [\nwrong '%s' tree size: got %u expected %u\n]\n", \
+ test, #ptr, \
+ (unsigned)talloc_total_size(ptr), \
+ (unsigned)tsize)
+
+#define CHECK_BLOCKS(test, ptr, tblocks) \
+ ok(talloc_total_blocks(ptr) == (tblocks), \
+ "failed: %s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
+ test, #ptr, \
+ (unsigned)talloc_total_blocks(ptr), \
+ (unsigned)tblocks)
+
+#define CHECK_PARENT(test, ptr, parent) \
+ ok(talloc_parent(ptr) == (parent), \
+ "failed: %s [\n'%s' has wrong parent: got %p expected %p\n]\n", \
+ test, #ptr, \
+ talloc_parent(ptr), \
+ (parent))
+
+/*
+ test references
+*/
+static bool test_ref1(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ p2 = talloc_named_const(p1, 1, "p2");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 2, "x2");
+ talloc_named_const(p1, 3, "x3");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+
+ CHECK_BLOCKS("ref1", p1, 5);
+ CHECK_BLOCKS("ref1", p2, 1);
+ CHECK_BLOCKS("ref1", r1, 2);
+
+ talloc_free(p2);
+
+ CHECK_BLOCKS("ref1", p1, 5);
+ CHECK_BLOCKS("ref1", p2, 1);
+ CHECK_BLOCKS("ref1", r1, 1);
+
+ talloc_free(p1);
+
+ CHECK_BLOCKS("ref1", r1, 1);
+
+ talloc_free(r1);
+
+ if (talloc_reference(root, NULL)) {
+ return false;
+ }
+
+ CHECK_BLOCKS("ref1", root, 1);
+
+ CHECK_SIZE("ref1", root, 0);
+
+ talloc_free(root);
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref2(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+
+ CHECK_BLOCKS("ref2", p1, 5);
+ CHECK_BLOCKS("ref2", p2, 1);
+ CHECK_BLOCKS("ref2", r1, 2);
+
+ talloc_free(ref);
+
+ CHECK_BLOCKS("ref2", p1, 5);
+ CHECK_BLOCKS("ref2", p2, 1);
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ talloc_free(p2);
+
+ CHECK_BLOCKS("ref2", p1, 4);
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ talloc_free(p1);
+
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ talloc_free(r1);
+
+ CHECK_SIZE("ref2", root, 0);
+
+ talloc_free(root);
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref3(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ p2 = talloc_named_const(root, 1, "p2");
+ r1 = talloc_named_const(p1, 1, "r1");
+ ref = talloc_reference(p2, r1);
+
+ CHECK_BLOCKS("ref3", p1, 2);
+ CHECK_BLOCKS("ref3", p2, 2);
+ CHECK_BLOCKS("ref3", r1, 1);
+
+ talloc_free(p1);
+
+ CHECK_BLOCKS("ref3", p2, 2);
+ CHECK_BLOCKS("ref3", r1, 1);
+
+ talloc_free(p2);
+
+ CHECK_SIZE("ref3", root, 0);
+
+ talloc_free(root);
+
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref4(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+
+ CHECK_BLOCKS("ref4", p1, 5);
+ CHECK_BLOCKS("ref4", p2, 1);
+ CHECK_BLOCKS("ref4", r1, 2);
+
+ talloc_free(r1);
+
+ CHECK_BLOCKS("ref4", p1, 5);
+ CHECK_BLOCKS("ref4", p2, 1);
+
+ talloc_free(p2);
+
+ CHECK_BLOCKS("ref4", p1, 4);
+
+ talloc_free(p1);
+
+ CHECK_SIZE("ref4", root, 0);
+
+ talloc_free(root);
+
+ return true;
+}
+
+
+/*
+ test references
+*/
+static bool test_unlink1(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(p1, 1, "r1");
+ ref = talloc_reference(r1, p2);
+
+ CHECK_BLOCKS("unlink", p1, 7);
+ CHECK_BLOCKS("unlink", p2, 1);
+ CHECK_BLOCKS("unlink", r1, 2);
+
+ talloc_unlink(r1, p2);
+
+ CHECK_BLOCKS("unlink", p1, 6);
+ CHECK_BLOCKS("unlink", p2, 1);
+ CHECK_BLOCKS("unlink", r1, 1);
+
+ talloc_free(p1);
+
+ CHECK_SIZE("unlink", root, 0);
+
+ talloc_free(root);
+
+ return true;
+}
+
+static int fail_destructor(void *ptr)
+{
+ return -1;
+}
+
+/*
+ miscellaneous tests to try to get a higher test coverage percentage
+*/
+static bool test_misc(void)
+{
+ void *root, *p1;
+ char *p2;
+ double *d;
+ const char *name;
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_size(root, 0x7fffffff);
+ torture_assert("misc", !p1, "failed: large talloc allowed\n");
+
+ p1 = talloc_strdup(root, "foo");
+ talloc_increase_ref_count(p1);
+ talloc_increase_ref_count(p1);
+ talloc_increase_ref_count(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ p2 = talloc_strdup(p1, "foo");
+ torture_assert("misc", talloc_unlink(root, p2) == -1,
+ "failed: talloc_unlink() of non-reference context should return -1\n");
+ torture_assert("misc", talloc_unlink(p1, p2) == 0,
+ "failed: talloc_unlink() of parent should succeed\n");
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+
+ name = talloc_set_name(p1, "my name is %s", "foo");
+ torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
+ "failed: wrong name after talloc_set_name(my name is foo)");
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+
+ talloc_set_name_const(p1, NULL);
+ torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
+ "failed: wrong name after talloc_set_name(NULL)");
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+
+ torture_assert("misc", talloc_free(NULL) == -1,
+ "talloc_free(NULL) should give -1\n");
+
+ talloc_set_destructor(p1, fail_destructor);
+ torture_assert("misc", talloc_free(p1) == -1,
+ "Failed destructor should cause talloc_free to fail\n");
+ talloc_set_destructor(p1, NULL);
+
+
+ p2 = (char *)talloc_zero_size(p1, 20);
+ torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
+ talloc_free(p2);
+
+ torture_assert("misc", talloc_strdup(root, NULL) == NULL,
+ "failed: strdup on NULL should give NULL\n");
+
+ p2 = talloc_strndup(p1, "foo", 2);
+ torture_assert("misc", strcmp("fo", p2) == 0,
+ "strndup doesn't work\n");
+ p2 = talloc_asprintf_append(p2, "o%c", 'd');
+ torture_assert("misc", strcmp("food", p2) == 0,
+ "talloc_asprintf_append doesn't work\n");
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 3);
+
+ p2 = talloc_asprintf_append(NULL, "hello %s", "world");
+ torture_assert("misc", strcmp("hello world", p2) == 0,
+ "talloc_asprintf_append doesn't work\n");
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 3);
+ talloc_free(p2);
+
+ d = talloc_array(p1, double, 0x20000000);
+ torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+ d = talloc_realloc(p1, d, double, 0x20000000);
+ torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", root, 1);
+
+ p1 = talloc_named(root, 100, "%d bytes", 100);
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+ talloc_unlink(root, p1);
+
+ p1 = talloc_init("%d bytes", 200);
+ p2 = talloc_asprintf(p1, "my test '%s'", "string");
+ torture_assert_str_equal("misc", p2, "my test 'string'",
+ "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
+ CHECK_BLOCKS("misc", p1, 3);
+ CHECK_SIZE("misc", p2, 17);
+ CHECK_BLOCKS("misc", root, 1);
+ talloc_unlink(NULL, p1);
+
+ p1 = talloc_named_const(root, 10, "p1");
+ p2 = (char *)talloc_named_const(root, 20, "p2");
+ (void)talloc_reference(p1, p2);
+ talloc_unlink(root, p2);
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+ talloc_unlink(p1, p2);
+ talloc_unlink(root, p1);
+
+ p1 = talloc_named_const(root, 10, "p1");
+ p2 = (char *)talloc_named_const(root, 20, "p2");
+ (void)talloc_reference(NULL, p2);
+ talloc_unlink(root, p2);
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p2);
+ talloc_unlink(root, p1);
+
+ /* Test that talloc_unlink is a no-op */
+
+ torture_assert("misc", talloc_unlink(root, NULL) == -1,
+ "failed: talloc_unlink(root, NULL) == -1\n");
+
+ CHECK_SIZE("misc", root, 0);
+
+ talloc_free(root);
+
+ CHECK_SIZE("misc", NULL, 0);
+
+ talloc_enable_leak_report();
+ talloc_enable_leak_report_full();
+
+ return true;
+}
+
+
+/*
+ test realloc
+*/
+static bool test_realloc(void)
+{
+ void *root, *p1, *p2;
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_size(root, 10);
+ CHECK_SIZE("realloc", p1, 10);
+
+ p1 = talloc_realloc_size(NULL, p1, 20);
+ CHECK_SIZE("realloc", p1, 20);
+
+ talloc_new(p1);
+
+ p2 = talloc_realloc_size(p1, NULL, 30);
+
+ talloc_new(p1);
+
+ p2 = talloc_realloc_size(p1, p2, 40);
+
+ CHECK_SIZE("realloc", p2, 40);
+ CHECK_SIZE("realloc", root, 60);
+ CHECK_BLOCKS("realloc", p1, 4);
+
+ p1 = talloc_realloc_size(NULL, p1, 20);
+ CHECK_SIZE("realloc", p1, 60);
+
+ talloc_increase_ref_count(p2);
+ torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
+ "failed: talloc_realloc() on a referenced pointer should fail\n");
+ CHECK_BLOCKS("realloc", p1, 4);
+
+ talloc_realloc_size(NULL, p2, 0);
+ talloc_realloc_size(NULL, p2, 0);
+ CHECK_BLOCKS("realloc", p1, 3);
+
+ torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
+ "failed: oversize talloc should fail\n");
+
+ talloc_realloc_size(NULL, p1, 0);
+
+ CHECK_BLOCKS("realloc", root, 1);
+ CHECK_SIZE("realloc", root, 0);
+
+ talloc_free(root);
+
+ return true;
+}
+
+/*
+ test realloc with a child
+*/
+static bool test_realloc_child(void)
+{
+ void *root;
+ struct el2 {
+ const char *name;
+ } *el2;
+ struct el1 {
+ int count;
+ struct el2 **list, **list2, **list3;
+ } *el1;
+
+ root = talloc_new(NULL);
+
+ el1 = talloc(root, struct el1);
+ el1->list = talloc(el1, struct el2 *);
+ el1->list[0] = talloc(el1->list, struct el2);
+ el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
+
+ el1->list2 = talloc(el1, struct el2 *);
+ el1->list2[0] = talloc(el1->list2, struct el2);
+ el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
+
+ el1->list3 = talloc(el1, struct el2 *);
+ el1->list3[0] = talloc(el1->list3, struct el2);
+ el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
+
+ el2 = talloc(el1->list, struct el2);
+ el2 = talloc(el1->list2, struct el2);
+ el2 = talloc(el1->list3, struct el2);
+
+ el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+ el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
+ el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
+
+ talloc_free(root);
+
+ return true;
+}
+
+/*
+ test type checking
+*/
+static bool test_type(void)
+{
+ void *root;
+ struct el1 {
+ int count;
+ };
+ struct el2 {
+ int count;
+ };
+ struct el1 *el1;
+
+ root = talloc_new(NULL);
+
+ el1 = talloc(root, struct el1);
+
+ el1->count = 1;
+
+ torture_assert("type", talloc_get_type(el1, struct el1) == el1,
+ "type check failed on el1\n");
+ torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
+ "type check failed on el1 with el2\n");
+ talloc_set_type(el1, struct el2);
+ torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
+ "type set failed on el1 with el2\n");
+
+ talloc_free(root);
+
+ return true;
+}
+
+/*
+ test steal
+*/
+static bool test_steal(void)
+{
+ void *root, *p1, *p2;
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_array(root, char, 10);
+ CHECK_SIZE("steal", p1, 10);
+
+ p2 = talloc_realloc(root, NULL, char, 20);
+ CHECK_SIZE("steal", p1, 10);
+ CHECK_SIZE("steal", root, 30);
+
+ torture_assert("steal", talloc_steal(p1, NULL) == NULL,
+ "failed: stealing NULL should give NULL\n");
+
+ torture_assert("steal", talloc_steal(p1, p1) == p1,
+ "failed: stealing to ourselves is a nop\n");
+ CHECK_BLOCKS("steal", root, 3);
+ CHECK_SIZE("steal", root, 30);
+
+ talloc_steal(NULL, p1);
+ talloc_steal(NULL, p2);
+ CHECK_BLOCKS("steal", root, 1);
+ CHECK_SIZE("steal", root, 0);
+
+ talloc_free(p1);
+ talloc_steal(root, p2);
+ CHECK_BLOCKS("steal", root, 2);
+ CHECK_SIZE("steal", root, 20);
+
+ talloc_free(p2);
+
+ CHECK_BLOCKS("steal", root, 1);
+ CHECK_SIZE("steal", root, 0);
+
+ talloc_free(root);
+
+ p1 = talloc_size(NULL, 3);
+ CHECK_SIZE("steal", NULL, 3);
+ talloc_free(p1);
+
+ return true;
+}
+
+/*
+ test move
+*/
+static bool test_move(void)
+{
+ void *root;
+ struct t_move {
+ char *p;
+ int *x;
+ } *t1, *t2;
+
+ root = talloc_new(NULL);
+
+ t1 = talloc(root, struct t_move);
+ t2 = talloc(root, struct t_move);
+ t1->p = talloc_strdup(t1, "foo");
+ t1->x = talloc(t1, int);
+ *t1->x = 42;
+
+ t2->p = talloc_move(t2, &t1->p);
+ t2->x = talloc_move(t2, &t1->x);
+ torture_assert("move", t1->p == NULL && t1->x == NULL &&
+ strcmp(t2->p, "foo") == 0 && *t2->x == 42,
+ "talloc move failed");
+
+ talloc_free(root);
+
+ return true;
+}
+
+/*
+ test talloc_realloc_fn
+*/
+static bool test_realloc_fn(void)
+{
+ void *root, *p1;
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_realloc_fn(root, NULL, 10);
+ CHECK_BLOCKS("realloc_fn", root, 2);
+ CHECK_SIZE("realloc_fn", root, 10);
+ p1 = talloc_realloc_fn(root, p1, 20);
+ CHECK_BLOCKS("realloc_fn", root, 2);
+ CHECK_SIZE("realloc_fn", root, 20);
+ p1 = talloc_realloc_fn(root, p1, 0);
+ CHECK_BLOCKS("realloc_fn", root, 1);
+ CHECK_SIZE("realloc_fn", root, 0);
+
+ talloc_free(root);
+
+ return true;
+}
+
+
+static bool test_unref_reparent(void)
+{
+ void *root, *p1, *p2, *c1;
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "orig parent");
+ p2 = talloc_named_const(root, 1, "parent by reference");
+
+ c1 = talloc_named_const(p1, 1, "child");
+ talloc_reference(p2, c1);
+
+ CHECK_PARENT("unref_reparent", c1, p1);
+
+ talloc_free(p1);
+
+ CHECK_PARENT("unref_reparent", c1, p2);
+
+ talloc_unlink(p2, c1);
+
+ CHECK_SIZE("unref_reparent", root, 1);
+
+ talloc_free(p2);
+ talloc_free(root);
+
+ return true;
+}
+
+static bool test_lifeless(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent, *child;
+ void *child_owner = talloc_new(NULL);
+
+ parent = talloc_strdup(top, "parent");
+ child = talloc_strdup(parent, "child");
+ (void)talloc_reference(child, parent);
+ (void)talloc_reference(child_owner, child);
+ talloc_unlink(top, parent);
+ talloc_free(child);
+ talloc_free(top);
+ talloc_free(child_owner);
+ talloc_free(child);
+
+ return true;
+}
+
+static int loop_destructor_count;
+
+static int test_loop_destructor(char *ptr)
+{
+ loop_destructor_count++;
+ return 0;
+}
+
+static bool test_loop(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent;
+ struct req1 {
+ char *req2, *req3;
+ } *req1;
+
+ parent = talloc_strdup(top, "parent");
+ req1 = talloc(parent, struct req1);
+ req1->req2 = talloc_strdup(req1, "req2");
+ talloc_set_destructor(req1->req2, test_loop_destructor);
+ req1->req3 = talloc_strdup(req1, "req3");
+ (void)talloc_reference(req1->req3, req1);
+ talloc_free(parent);
+ talloc_free(top);
+
+ torture_assert("loop", loop_destructor_count == 1,
+ "FAILED TO FIRE LOOP DESTRUCTOR\n");
+ loop_destructor_count = 0;
+
+ return true;
+}
+
+static int fail_destructor_str(char *ptr)
+{
+ return -1;
+}
+
+static bool test_free_parent_deny_child(void)
+{
+ void *top = talloc_new(NULL);
+ char *level1;
+ char *level2;
+ char *level3;
+
+ level1 = talloc_strdup(top, "level1");
+ level2 = talloc_strdup(level1, "level2");
+ level3 = talloc_strdup(level2, "level3");
+
+ talloc_set_destructor(level3, fail_destructor_str);
+ talloc_free(level1);
+ talloc_set_destructor(level3, NULL);
+
+ CHECK_PARENT("free_parent_deny_child", level3, top);
+
+ talloc_free(top);
+
+ return true;
+}
+
+static bool test_talloc_ptrtype(void)
+{
+ void *top = talloc_new(NULL);
+ struct struct1 {
+ int foo;
+ int bar;
+ } *s1, *s2, **s3, ***s4;
+ const char *location1;
+ const char *location2;
+ const char *location3;
+ const char *location4;
+
+ s1 = talloc_ptrtype(top, s1);location1 = __location__;
+
+ ok1(talloc_get_size(s1) == sizeof(struct struct1));
+
+ ok1(strcmp(location1, talloc_get_name(s1)) == 0);
+
+ s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
+
+ ok1(talloc_get_size(s2) == (sizeof(struct struct1) * 10));
+
+ ok1(strcmp(location2, talloc_get_name(s2)) == 0);
+
+ s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
+
+ ok1(talloc_get_size(s3) == (sizeof(struct struct1 *) * 10));
+
+ torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
+ "talloc_array_ptrtype() sets the wrong name");
+
+ s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
+
+ ok1(talloc_get_size(s4) == (sizeof(struct struct1 **) * 10));
+
+ torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
+ "talloc_array_ptrtype() sets the wrong name");
+
+ talloc_free(top);
+
+ return true;
+}
+
+static int _test_talloc_free_in_destructor(void **ptr)
+{
+ talloc_free(*ptr);
+ return 0;
+}
+
+static bool test_talloc_free_in_destructor(void)
+{
+ void *level0;
+ void *level1;
+ void *level2;
+ void *level3;
+ void *level4;
+ void **level5;
+
+ level0 = talloc_new(NULL);
+ level1 = talloc_new(level0);
+ level2 = talloc_new(level1);
+ level3 = talloc_new(level2);
+ level4 = talloc_new(level3);
+ level5 = talloc(level4, void *);
+
+ *level5 = level3;
+ (void)talloc_reference(level0, level3);
+ (void)talloc_reference(level3, level3);
+ (void)talloc_reference(level5, level3);
+
+ talloc_set_destructor(level5, _test_talloc_free_in_destructor);
+
+ talloc_free(level1);
+
+ talloc_free(level0);
+
+ return true;
+}
+
+static bool test_autofree(void)
+{
+ /* autofree test would kill smbtorture */
+ void *p;
+ p = talloc_autofree_context();
+ talloc_free(p);
+
+ p = talloc_autofree_context();
+ talloc_free(p);
+
+ return true;
+}
+
+struct torture_context;
+static bool torture_local_talloc(struct torture_context *tctx)
+{
+ bool ret = true;
+
+ setlinebuf(stdout);
+
+ talloc_disable_null_tracking();
+ talloc_enable_null_tracking();
+
+ ret &= test_ref1();
+ ret &= test_ref2();
+ ret &= test_ref3();
+ ret &= test_ref4();
+ ret &= test_unlink1();
+ ret &= test_misc();
+ ret &= test_realloc();
+ ret &= test_realloc_child();
+ ret &= test_steal();
+ ret &= test_move();
+ ret &= test_unref_reparent();
+ ret &= test_realloc_fn();
+ ret &= test_type();
+ ret &= test_lifeless();
+ ret &= test_loop();
+ ret &= test_free_parent_deny_child();
+ ret &= test_talloc_ptrtype();
+ ret &= test_talloc_free_in_destructor();
+ ret &= test_autofree();
+
+ return ret;
+}
+
+int main(void)
+{
+ plan_tests(134);
+
+ torture_local_talloc(NULL);
+ return exit_status();
+}
+
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * tap - Test Anything Protocol
+ *
+ * The tap package produces simple-to-parse mainly-human-readable test
+ * output to assist in the writing of test cases. It is based on the
+ * (now-defunct) libtap, which is based on Perl's CPAN TAP module. Its
+ * output can be parsed by a harness such as CPAN's Prove.
+ *
+ * CCAN testcases are expected to output the TAP format, usually using
+ * this package.
+ *
+ * For more information about TAP, see:
+ * http://en.wikipedia.org/wiki/Test_Anything_Protocol
+ *
+ * Based on the original libtap, Copyright (c) 2004 Nik Clayton.
+ *
+ * Example:
+ * #include <string.h>
+ * #include "tap/tap.h"
+ *
+ * // Run some simple (but overly chatty) tests on strcmp().
+ * int main(int argc, char *argv[])
+ * {
+ * const char a[] = "a", another_a[] = "a";
+ * const char b[] = "b";
+ * const char ab[] = "ab";
+ *
+ * plan_tests(4);
+ * diag("Testing different pointers (%p/%p) with same contents",
+ * a, another_a);
+ * ok1(strcmp(a, another_a) == 0);
+ *
+ * diag("'a' comes before 'b'");
+ * ok1(strcmp(a, b) < 0);
+ * ok1(strcmp(b, a) > 0);
+ *
+ * diag("'ab' comes after 'a'");
+ * ok1(strcmp(ab, a) > 0);
+ * return exit_status();
+ * }
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0)
+ return 0;
+
+ return 1;
+}
--- /dev/null
+.Dd December 20, 2004
+.Os
+.Dt TAP 3
+.Sh NAME
+.Nm tap
+.Nd write tests that implement the Test Anything Protocol
+.Sh SYNOPSIS
+.In tap.h
+.Sh DESCRIPTION
+The
+.Nm
+library provides functions for writing test scripts that produce output
+consistent with the Test Anything Protocol. A test harness that parses
+this protocol can run these tests and produce useful reports indicating
+their success or failure.
+.Ss PRINTF STRINGS
+In the descriptions that follow, for any function that takes as the
+last two parameters
+.Dq Fa char * , Fa ...
+it can be assumed that the
+.Fa char *
+is a
+.Fn printf
+-like format string, and the optional arguments are values to be placed
+in that string.
+.Ss TEST PLANS
+.Bl -tag -width indent
+.It Xo
+.Ft void
+.Fn plan_tests "unsigned int"
+.Xc
+.It Xo
+.Ft void
+.Fn plan_no_plan "void"
+.Xc
+.It Xo
+.Ft void
+.Fn plan_skip_all "char *" "..."
+.Xc
+.El
+.Pp
+You must first specify a test plan. This indicates how many tests you
+intend to run, and allows the test harness to notice if any tests were
+missed, or if the test program exited prematurely.
+.Pp
+To do this, use
+.Fn plan_tests .
+The function will cause your program to exit prematurely if you specify
+0 tests.
+.Pp
+In some situations you may not know how many tests you will be running, or
+you are developing your test program, and do not want to update the
+.Fn plan_tests
+parameter every time you make a change. For those situations use
+.Fn plan_no_plan .
+It indicates to the test harness that an indeterminate number
+of tests will be run.
+.Pp
+Both
+.Fn plan_tests
+and
+.Fn plan_no_plan
+will cause your test program to exit prematurely with a diagnostic
+message if they are called more than once.
+.Pp
+If your test program detects at run time that some required functionality
+is missing (for example, it relies on a database connection which is not
+present, or a particular configuration option that has not been included
+in the running kernel) use
+.Fn plan_skip_all ,
+passing as parameters a string to display indicating the reason for skipping
+the tests.
+.Ss SIMPLE TESTS
+.Bl -tag -width indent
+.It Xo
+.Ft unsigned int
+.Fn ok "expression" "char *" "..."
+.Xc
+.It Xo
+.Ft unsigned int
+.Fn ok1 "expression"
+.Xc
+.It Xo
+.Ft unsigned int
+.Fn pass "char *" "..."
+.Xc
+.It Xo
+.Ft unsigned int
+.Fn fail "char *" "..."
+.Xc
+.El
+.Pp
+Tests are implemented as expressions checked by calls to the
+.Fn ok
+and
+.Fn ok1
+macros. In both cases
+.Fa expression
+should evaluate to true if the test succeeded.
+.Pp
+.Fn ok
+allows you to specify a name, or comment, describing the test which will
+be included in the output.
+.Fn ok1
+is for those times when the expression to be tested is self
+explanatory and does not need an associated comment. In those cases
+the test expression becomes the comment.
+.Pp
+These four calls are equivalent:
+.Bd -literal -offset indent
+int i = 5;
+
+ok(i == 5, "i equals 5"); /* Overly verbose */
+ok(i == 5, "i equals %d", i); /* Just to demonstrate printf-like
+ behaviour of the test name */
+ok(i == 5, "i == 5"); /* Needless repetition */
+ok1(i == 5); /* Just right */
+.Ed
+.Pp
+It is good practice to ensure that the test name describes the meaning
+behind the test rather than what you are testing. Viz
+.Bd -literal -offset indent
+ok(db != NULL, "db is not NULL"); /* Not bad, but */
+ok(db != NULL, "Database conn. succeeded"); /* this is better */
+.Ed
+.Pp
+.Fn ok
+and
+.Fn ok1
+return 1 if the expression evaluated to true, and 0 if it evaluated to
+false. This lets you chain calls from
+.Fn ok
+to
+.Fn diag
+to only produce diagnostic output if the test failed. For example, this
+code will include diagnostic information about why the database connection
+failed, but only if the test failed.
+.Bd -literal -offset indent
+if (!ok(db != NULL, "Database conn. succeeded")) {
+ diag("Database error code: %d", dberrno);
+}
+.Ed
+.Pp
+You also have
+.Fn pass
+and
+.Fn fail .
+From the Test::More documentation:
+.Bd -literal -offset indent
+Sometimes you just want to say that the tests have passed.
+Usually the case is you've got some complicated condition
+that is difficult to wedge into an ok(). In this case,
+you can simply use pass() (to declare the test ok) or fail
+(for not ok).
+
+Use these very, very, very sparingly.
+.Ed
+.Pp
+These are synonyms for ok(1, ...) and ok(0, ...).
+.Ss SKIPPING TESTS
+.Bl -tag -width indent
+.It Xo
+.Ft void
+.Fn skip "unsigned int" "char *" "..."
+.Xc
+.It Xo
+.Fn skip_if "expression" "unsigned int" "char *" "..."
+.Xc
+.El
+.Pp
+Sets of tests can be skipped. Ordinarily you would do this because
+the test can't be run in this particular testing environment.
+.Pp
+For example, suppose some tests should be run as root. If the test is
+not being run as root then the tests should be skipped. In this
+implementation, skipped tests are flagged as being ok, with a special
+message indicating that they were skipped. It is your responsibility
+to ensure that the number of tests skipped (the first parameter to
+.Fn skip )
+is correct for the number of tests to skip.
+.Pp
+One way of implementing this is with a
+.Dq do { } while(0);
+loop, or an
+.Dq if( ) { } else { }
+construct, to ensure that there are no additional side effects from the
+skipped tests.
+.Bd -literal -offset indent
+if(getuid() != 0) {
+ skip(1, "because test only works as root");
+} else {
+ ok(do_something_as_root() == 0, "Did something as root");
+}
+.Ed
+.Pp
+A convenient macro is provided to assist with this. The previous example could
+be re-written as follows.
+.Bd -literal -offset indent
+skip_if(getuid() != 0, 1, "because test only works as root") {
+ ok(do_something_as_root() == 0, "Did something as root");
+}
+.Ed
+.Ss MARKING TESTS AS Dq TODO
+.Bl -tag -width indent
+.It Xo
+.Ft void
+.Fn todo_start "char *" "..."
+.Xc
+.It Xo
+.Ft void
+.Fn todo_end "void"
+.Xc
+.El
+.Pp
+Sets of tests can be flagged as being
+.Dq TODO .
+These are tests that you expect to fail, probably because you haven't
+fixed a bug, or finished a new feature yet. These tests will still be
+run, but with additional output that indicates that they are expected
+to fail. Should a test start to succeed unexpectedly, tools like
+.Xr prove 1
+will indicate this, and you can move the test out of the todo
+block. This is much more useful than simply commenting out (or
+.Dq #ifdef 0 ... #endif )
+the tests.
+.Bd -literal -offset indent
+todo_start("dwim() not returning true yet");
+
+ok(dwim(), "Did what the user wanted");
+
+todo_end();
+.Ed
+.Pp
+Should
+.Fn dwim
+ever start succeeding you will know about it as soon as you run the
+tests. Note that
+.Em unlike
+the
+.Fn skip_*
+family, additional code between
+.Fn todo_start
+and
+.Fn todo_end
+.Em is
+executed.
+.Ss SKIP vs. TODO
+From the Test::More documentation;
+.Bd -literal -offset indent
+If it's something the user might not be able to do, use SKIP.
+This includes optional modules that aren't installed, running
+under an OS that doesn't have some feature (like fork() or
+symlinks), or maybe you need an Internet connection and one
+isn't available.
+
+If it's something the programmer hasn't done yet, use TODO.
+This is for any code you haven't written yet, or bugs you have
+yet to fix, but want to put tests in your testing script
+(always a good idea).
+.Ed
+.Ss DIAGNOSTIC OUTPUT
+.Bl -tag -width indent
+.It Xo
+.Fr void
+.Fn diag "char *" "..."
+.Xc
+.El
+.Pp
+If your tests need to produce diagnostic output, use
+.Fn diag .
+It ensures that the output will not be considered by the TAP test harness.
+.Fn diag
+adds the necessary trailing
+.Dq \en
+for you.
+.Bd -literal -offset indent
+diag("Expected return code 0, got return code %d", rcode);
+.Ed
+.Ss EXIT STATUS
+.Bl -tag -width indent
+.It Xo
+.Fr int
+.Fn exit_status void
+.Xc
+.El
+.Pp
+For maximum compatability your test program should return a particular
+exit code. This is calculated by
+.Fn exit_status
+so it is sufficient to always return from
+.Fn main
+with either
+.Dq return exit_status();
+or
+.Dq exit(exit_status());
+as appropriate.
+.Sh EXAMPLES
+The
+.Pa tests
+directory in the source distribution contains numerous tests of
+.Nm
+functionality, written using
+.Nm .
+Examine them for examples of how to construct test suites.
+.Sh COMPATABILITY
+.Nm
+strives to be compatible with the Perl Test::More and Test::Harness
+modules. The test suite verifies that
+.Nm
+is bug-for-bug compatible with their behaviour. This is why some
+functions which would more naturally return nothing return constant
+values.
+.Pp
+If the
+.Lb libpthread
+is found at compile time,
+.Nm
+.Em should
+be thread safe. Indications to the contrary (and test cases that expose
+incorrect behaviour) are very welcome.
+.Sh SEE ALSO
+.Xr Test::More 1 ,
+.Xr Test::Harness 1 ,
+.Xr prove 1
+.Sh STANDARDS
+.Nm
+requires a
+.St -isoC-99
+compiler. Some of the
+.Nm
+functionality is implemented as variadic macros, and that functionality
+was not formally codified until C99. Patches to use
+.Nm
+with earlier compilers that have their own implementation of variadic
+macros will be gratefully received.
+.Sh HISTORY
+.Nm
+was written to help improve the quality and coverage of the FreeBSD
+regression test suite, and released in the hope that others find it
+a useful tool to help improve the quality of their code.
+.Sh AUTHORS
+.An "Nik Clayton" Aq nik@ngo.org.uk ,
+.Aq nik@FreeBSD.org
+.Pp
+.Nm
+would not exist without the efforts of
+.An "Michael G Schwern" Aq schqern@pobox.com ,
+.An "Andy Lester" Aq andy@petdance.com ,
+and the countless others who have worked on the Perl QA programme.
+.Sh BUGS
+Ideally, running the tests would have no side effects on the behaviour
+of the application you are testing. However, it is not always possible
+to avoid them. The following side effects of using
+.Nm
+are known.
+.Bl -bullet -offset indent
+.It
+stdout is set to unbuffered mode after calling any of the
+.Fn plan_*
+functions.
+.El
--- /dev/null
+/*-
+ * Copyright (c) 2004 Nik Clayton
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tap.h"
+
+static int no_plan = 0;
+static int skip_all = 0;
+static int have_plan = 0;
+static unsigned int test_count = 0; /* Number of tests that have been run */
+static unsigned int e_tests = 0; /* Expected number of tests to run */
+static unsigned int failures = 0; /* Number of tests that failed */
+static char *todo_msg = NULL;
+static char *todo_msg_fixed = "libtap malloc issue";
+static int todo = 0;
+static int test_died = 0;
+
+/* Encapsulate the pthread code in a conditional. In the absence of
+ libpthread the code does nothing */
+#ifdef HAVE_LIBPTHREAD
+#include <pthread.h>
+static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
+# define LOCK pthread_mutex_lock(&M)
+# define UNLOCK pthread_mutex_unlock(&M)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+static void
+_expected_tests(unsigned int tests)
+{
+
+ printf("1..%d\n", tests);
+ e_tests = tests;
+}
+
+static void
+diagv(char *fmt, va_list ap)
+{
+ fputs("# ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputs("\n", stderr);
+}
+
+static void
+_diag(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ diagv(fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Generate a test result.
+ *
+ * ok -- boolean, indicates whether or not the test passed.
+ * test_name -- the name of the test, may be NULL
+ * test_comment -- a comment to print afterwards, may be NULL
+ */
+unsigned int
+_gen_result(int ok, const char *func, char *file, unsigned int line,
+ char *test_name, ...)
+{
+ va_list ap;
+ char *local_test_name = NULL;
+ char *c;
+ int name_is_digits;
+
+ LOCK;
+
+ test_count++;
+
+ /* Start by taking the test name and performing any printf()
+ expansions on it */
+ if(test_name != NULL) {
+ va_start(ap, test_name);
+ vasprintf(&local_test_name, test_name, ap);
+ va_end(ap);
+
+ /* Make sure the test name contains more than digits
+ and spaces. Emit an error message and exit if it
+ does */
+ if(local_test_name) {
+ name_is_digits = 1;
+ for(c = local_test_name; *c != '\0'; c++) {
+ if(!isdigit(*c) && !isspace(*c)) {
+ name_is_digits = 0;
+ break;
+ }
+ }
+
+ if(name_is_digits) {
+ _diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name);
+ _diag(" Very confusing.");
+ }
+ }
+ }
+
+ if(!ok) {
+ printf("not ");
+ failures++;
+ }
+
+ printf("ok %d", test_count);
+
+ if(test_name != NULL) {
+ printf(" - ");
+
+ /* Print the test name, escaping any '#' characters it
+ might contain */
+ if(local_test_name != NULL) {
+ flockfile(stdout);
+ for(c = local_test_name; *c != '\0'; c++) {
+ if(*c == '#')
+ fputc('\\', stdout);
+ fputc((int)*c, stdout);
+ }
+ funlockfile(stdout);
+ } else { /* vasprintf() failed, use a fixed message */
+ printf("%s", todo_msg_fixed);
+ }
+ }
+
+ /* If we're in a todo_start() block then flag the test as being
+ TODO. todo_msg should contain the message to print at this
+ point. If it's NULL then asprintf() failed, and we should
+ use the fixed message.
+
+ This is not counted as a failure, so decrement the counter if
+ the test failed. */
+ if(todo) {
+ printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
+ if(!ok)
+ failures--;
+ }
+
+ printf("\n");
+
+ if(!ok)
+ _diag(" Failed %stest (%s:%s() at line %d)",
+ todo ? "(TODO) " : "", file, func, line);
+
+ free(local_test_name);
+
+ UNLOCK;
+
+ /* We only care (when testing) that ok is positive, but here we
+ specifically only want to return 1 or 0 */
+ return ok ? 1 : 0;
+}
+
+/*
+ * Cleanup at the end of the run, produce any final output that might be
+ * required.
+ */
+static void
+_cleanup(void)
+{
+
+ LOCK;
+
+ /* If plan_no_plan() wasn't called, and we don't have a plan,
+ and we're not skipping everything, then something happened
+ before we could produce any output */
+ if(!no_plan && !have_plan && !skip_all) {
+ _diag("Looks like your test died before it could output anything.");
+ UNLOCK;
+ return;
+ }
+
+ if(test_died) {
+ _diag("Looks like your test died just after %d.", test_count);
+ UNLOCK;
+ return;
+ }
+
+
+ /* No plan provided, but now we know how many tests were run, and can
+ print the header at the end */
+ if(!skip_all && (no_plan || !have_plan)) {
+ printf("1..%d\n", test_count);
+ }
+
+ if((have_plan && !no_plan) && e_tests < test_count) {
+ _diag("Looks like you planned %d tests but ran %d extra.",
+ e_tests, test_count - e_tests);
+ UNLOCK;
+ return;
+ }
+
+ if((have_plan || !no_plan) && e_tests > test_count) {
+ _diag("Looks like you planned %d tests but only ran %d.",
+ e_tests, test_count);
+ if(failures) {
+ _diag("Looks like you failed %d tests of %d run.",
+ failures, test_count);
+ }
+ UNLOCK;
+ return;
+ }
+
+ if(failures)
+ _diag("Looks like you failed %d tests of %d.",
+ failures, test_count);
+
+ UNLOCK;
+}
+
+/*
+ * Initialise the TAP library. Will only do so once, however many times it's
+ * called.
+ */
+static void
+_tap_init(void)
+{
+ static int run_once = 0;
+
+ if(!run_once) {
+ atexit(_cleanup);
+
+ /* stdout needs to be unbuffered so that the output appears
+ in the same place relative to stderr output as it does
+ with Test::Harness */
+ setbuf(stdout, 0);
+ run_once = 1;
+ }
+}
+
+/*
+ * Note that there's no plan.
+ */
+void
+plan_no_plan(void)
+{
+
+ LOCK;
+
+ _tap_init();
+
+ if(have_plan != 0) {
+ fprintf(stderr, "You tried to plan twice!\n");
+ test_died = 1;
+ UNLOCK;
+ exit(255);
+ }
+
+ have_plan = 1;
+ no_plan = 1;
+
+ UNLOCK;
+}
+
+/*
+ * Note that the plan is to skip all tests
+ */
+void
+plan_skip_all(char *reason)
+{
+
+ LOCK;
+
+ _tap_init();
+
+ skip_all = 1;
+
+ printf("1..0");
+
+ if(reason != NULL)
+ printf(" # Skip %s", reason);
+
+ printf("\n");
+
+ UNLOCK;
+}
+
+/*
+ * Note the number of tests that will be run.
+ */
+void
+plan_tests(unsigned int tests)
+{
+
+ LOCK;
+
+ _tap_init();
+
+ if(have_plan != 0) {
+ fprintf(stderr, "You tried to plan twice!\n");
+ test_died = 1;
+ UNLOCK;
+ exit(255);
+ }
+
+ if(tests == 0) {
+ fprintf(stderr, "You said to run 0 tests! You've got to run something.\n");
+ test_died = 1;
+ UNLOCK;
+ exit(255);
+ }
+
+ have_plan = 1;
+
+ _expected_tests(tests);
+
+ UNLOCK;
+}
+
+void
+diag(char *fmt, ...)
+{
+ va_list ap;
+
+ LOCK;
+
+ va_start(ap, fmt);
+ diagv(fmt, ap);
+ va_end(ap);
+
+ UNLOCK;
+}
+
+void
+skip(unsigned int n, char *fmt, ...)
+{
+ va_list ap;
+ char *skip_msg;
+
+ LOCK;
+
+ va_start(ap, fmt);
+ vasprintf(&skip_msg, fmt, ap);
+ va_end(ap);
+
+ while(n-- > 0) {
+ test_count++;
+ printf("ok %d # skip %s\n", test_count,
+ skip_msg != NULL ?
+ skip_msg : "libtap():malloc() failed");
+ }
+
+ free(skip_msg);
+
+ UNLOCK;
+}
+
+void
+todo_start(char *fmt, ...)
+{
+ va_list ap;
+
+ LOCK;
+
+ va_start(ap, fmt);
+ vasprintf(&todo_msg, fmt, ap);
+ va_end(ap);
+
+ todo = 1;
+
+ UNLOCK;
+}
+
+void
+todo_end(void)
+{
+
+ LOCK;
+
+ todo = 0;
+ free(todo_msg);
+
+ UNLOCK;
+}
+
+int
+exit_status(void)
+{
+ int r;
+
+ LOCK;
+
+ /* If there's no plan, just return the number of failures */
+ if(no_plan || !have_plan) {
+ UNLOCK;
+ return failures;
+ }
+
+ /* Ran too many tests? Return the number of tests that were run
+ that shouldn't have been */
+ if(e_tests < test_count) {
+ r = test_count - e_tests;
+ UNLOCK;
+ return r;
+ }
+
+ /* Return the number of tests that failed + the number of tests
+ that weren't run */
+ r = failures + e_tests - test_count;
+ UNLOCK;
+
+ return r;
+}
--- /dev/null
+/*-
+ * Copyright (c) 2004 Nik Clayton
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/**
+ * plan_tests - announce the number of tests you plan to run
+ * @tests: the number of tests
+ *
+ * This should be the first call in your test program: it allows tracing
+ * of failures which mean that not all tests are run.
+ *
+ * If you don't know how many tests will actually be run, assume all of them
+ * and use skip() if you don't actually run some tests.
+ *
+ * Example:
+ * plan_tests(13);
+ */
+void plan_tests(unsigned int tests);
+
+#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(__GNUC__)
+# error "Needs gcc or C99 compiler for variadic macros."
+#else
+
+/**
+ * ok1 - Simple conditional test
+ * @e: the expression which we expect to be true.
+ *
+ * This is the simplest kind of test: if the expression is true, the
+ * test passes. The name of the test which is printed will simply be
+ * file name, line number, and the expression itself.
+ *
+ * Example:
+ * ok1(init_subsystem() == 1);
+ */
+# define ok1(e) ((e) ? \
+ _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
+ _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
+
+/**
+ * ok - Conditional test with a name
+ * @e: the expression which we expect to be true.
+ * @...: the printf-style name of the test.
+ *
+ * If the expression is true, the test passes. The name of the test will be
+ * the filename, line number, and the printf-style string. This can be clearer
+ * than simply the expression itself.
+ *
+ * Example:
+ * ok1(init_subsystem() == 1);
+ * ok(init_subsystem() == 0, "Second initialization should fail");
+ */
+# define ok(e, ...) ((e) ? \
+ _gen_result(1, __func__, __FILE__, __LINE__, \
+ __VA_ARGS__) : \
+ _gen_result(0, __func__, __FILE__, __LINE__, \
+ __VA_ARGS__))
+
+/**
+ * pass - Note that a test passed
+ * @...: the printf-style name of the test.
+ *
+ * For complicated code paths, it can be easiest to simply call pass() in one
+ * branch and fail() in another.
+ *
+ * Example:
+ * x = do_something();
+ * if (!checkable(x) || check_value(x))
+ * pass("do_something() returned a valid value");
+ * else
+ * fail("do_something() returned an invalid value");
+ */
+# define pass(...) ok(1, __VA_ARGS__)
+
+/**
+ * fail - Note that a test failed
+ * @...: the printf-style name of the test.
+ *
+ * For complicated code paths, it can be easiest to simply call pass() in one
+ * branch and fail() in another.
+ */
+# define fail(...) ok(0, __VA_ARGS__)
+
+/* I don't find these to be useful. */
+# define skip_if(cond, n, ...) \
+ if (cond) skip((n), __VA_ARGS__); \
+ else
+
+# define skip_start(test, n, ...) \
+ do { \
+ if((test)) { \
+ skip(n, __VA_ARGS__); \
+ continue; \
+ }
+
+# define skip_end } while(0)
+
+#ifndef PRINTF_ATTRIBUTE
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...)
+ PRINTF_ATTRIBUTE(5, 6);
+
+/**
+ * diag - print a diagnostic message (use instead of printf/fprintf)
+ * @fmt: the format of the printf-style message
+ *
+ * diag ensures that the output will not be considered to be a test
+ * result by the TAP test harness. It will append '\n' for you.
+ *
+ * Example:
+ * diag("Now running complex tests");
+ */
+void diag(char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/**
+ * skip - print a diagnostic message (use instead of printf/fprintf)
+ * @n: number of tests you're skipping.
+ * @fmt: the format of the reason you're skipping the tests.
+ *
+ * Sometimes tests cannot be run because the test system lacks some feature:
+ * you should explicitly document that you're skipping tests using skip().
+ *
+ * From the Test::More documentation:
+ * If it's something the user might not be able to do, use SKIP. This
+ * includes optional modules that aren't installed, running under an OS that
+ * doesn't have some feature (like fork() or symlinks), or maybe you need an
+ * Internet connection and one isn't available.
+ *
+ * Example:
+ * #ifdef HAVE_SOME_FEATURE
+ * ok1(test_some_feature());
+ * #else
+ * skip(1, "Don't have SOME_FEATURE");
+ * #endif
+ */
+void skip(unsigned int n, char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+
+/**
+ * todo_start - mark tests that you expect to fail.
+ * @fmt: the reason they currently fail.
+ *
+ * It's extremely useful to write tests before you implement the matching fix
+ * or features: surround these tests by todo_start()/todo_end(). These tests
+ * will still be run, but with additional output that indicates that they are
+ * expected to fail.
+ *
+ * This way, should a test start to succeed unexpectedly, tools like prove(1)
+ * will indicate this and you can move the test out of the todo block. This
+ * is much more useful than simply commenting out (or '#if 0') the tests.
+ *
+ * From the Test::More documentation:
+ * If it's something the programmer hasn't done yet, use TODO. This is for
+ * any code you haven't written yet, or bugs you have yet to fix, but want to
+ * put tests in your testing script (always a good idea).
+ *
+ * Example:
+ * todo_start("dwim() not returning true yet");
+ * ok(dwim(), "Did what the user wanted");
+ * todo_end();
+ */
+void todo_start(char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/**
+ * todo_end - end of tests you expect to fail.
+ *
+ * See todo_start().
+ */
+void todo_end(void);
+
+/**
+ * exit_status - the value that main should return.
+ *
+ * For maximum compatability your test program should return a particular exit
+ * code (ie. 0 if all tests were run, and every test which was expected to
+ * succeed succeeded).
+ *
+ * Example:
+ * exit(exit_status());
+ */
+int exit_status(void);
+
+/**
+ * plan_no_plan - I have no idea how many tests I'm going to run.
+ *
+ * In some situations you may not know how many tests you will be running, or
+ * you are developing your test program, and do not want to update the
+ * plan_tests() call every time you make a change. For those situations use
+ * plan_no_plan() instead of plan_tests(). It indicates to the test harness
+ * that an indeterminate number of tests will be run.
+ *
+ * Remember, if you fail to plan, you plan to fail.
+ *
+ * Example:
+ * plan_no_plan();
+ * while (random() % 2)
+ * ok1(some_test());
+ * exit(exit_status());
+ */
+void plan_no_plan(void);
+
+/**
+ * plan_skip_all - Indicate that you will skip all tests.
+ * @reason: the string indicating why you can't run any tests.
+ *
+ * If your test program detects at run time that some required functionality
+ * is missing (for example, it relies on a database connection which is not
+ * present, or a particular configuration option that has not been included
+ * in the running kernel) use plan_skip_all() instead of plan_tests().
+ *
+ * Example:
+ * if (!have_some_feature) {
+ * plan_skip_all("Need some_feature support");
+ * exit(exit_status());
+ * }
+ * plan_tests(13);
+ */
+void plan_skip_all(char *reason);
+
+#endif /* C99 or gcc */
--- /dev/null
+/* We use the fact that pipes have a buffer greater than the size of
+ * any output, and change stdout and stderr to use that.
+ *
+ * Since we don't use libtap for output, this looks like one big test. */
+#include "tap/tap.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <fnmatch.h>
+
+/* We dup stderr to here. */
+static int stderrfd;
+
+/* Simple replacement for err() */
+static void failmsg(const char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ /* Write into buffer. */
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ write(stderrfd, "# ", 2);
+ write(stderrfd, buf, strlen(buf));
+ write(stderrfd, "\n", 1);
+ _exit(1);
+}
+
+static void expect(int fd, const char *pattern)
+{
+ char buffer[PIPE_BUF+1];
+ int r;
+
+ r = read(fd, buffer, sizeof(buffer)-1);
+ if (r < 0)
+ failmsg("reading from pipe");
+ buffer[r] = '\0';
+
+ if (fnmatch(pattern, buffer, 0) != 0)
+ failmsg("Expected '%s' got '%s'", pattern, buffer);
+}
+
+int main(int argc, char *argv[])
+{
+ int p[2];
+ int stdoutfd;
+
+ printf("1..1\n");
+ fflush(stdout);
+ stderrfd = dup(STDERR_FILENO);
+ if (stderrfd < 0)
+ err(1, "dup of stderr failed");
+
+ stdoutfd = dup(STDOUT_FILENO);
+ if (stdoutfd < 0)
+ err(1, "dup of stdout failed");
+
+ if (pipe(p) != 0)
+ failmsg("pipe failed");
+
+ if (dup2(p[1], STDERR_FILENO) < 0 || dup2(p[1], STDOUT_FILENO) < 0)
+ failmsg("Duplicating file descriptor");
+
+ plan_tests(10);
+ expect(p[0], "1..10\n");
+
+ ok(1, "msg1");
+ expect(p[0], "ok 1 - msg1\n");
+
+ ok(0, "msg2");
+ expect(p[0], "not ok 2 - msg2\n"
+ "# Failed test (*tap/test/run.c:main() at line 77)\n");
+
+ ok1(true);
+ expect(p[0], "ok 3 - true\n");
+
+ ok1(false);
+ expect(p[0], "not ok 4 - false\n"
+ "# Failed test (*tap/test/run.c:main() at line 84)\n");
+
+ pass("passed");
+ expect(p[0], "ok 5 - passed\n");
+
+ fail("failed");
+ expect(p[0], "not ok 6 - failed\n"
+ "# Failed test (*tap/test/run.c:main() at line 91)\n");
+
+ skip(2, "skipping %s", "test");
+ expect(p[0], "ok 7 # skip skipping test\n"
+ "ok 8 # skip skipping test\n");
+
+ todo_start("todo");
+ ok1(false);
+ expect(p[0], "not ok 9 - false # TODO todo\n"
+ "# Failed (TODO) test (*tap/test/run.c:main() at line 100)\n");
+ ok1(true);
+ expect(p[0], "ok 10 - true # TODO todo\n");
+ todo_end();
+
+ if (exit_status() != 3)
+ failmsg("Expected exit status 3, not %i", exit_status());
+
+#if 0
+ /* Manually run the atexit command. */
+ _cleanup();
+ expect(p[0], "# Looks like you failed 2 tests of 9.\n");
+#endif
+
+ write(stdoutfd, "ok 1 - All passed\n", strlen("ok 1 - All passed\n"));
+ _exit(0);
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * typesafe_cb - macros for safe callbacks.
+ *
+ * The basis of the typesafe_cb header is cast_if_type(): a
+ * conditional cast macro. If an expression exactly matches a given
+ * type, it is cast to the target type, otherwise it is left alone.
+ *
+ * This allows us to create functions which take a small number of
+ * specific types, rather than being forced to use a void *. In
+ * particular, it is useful for creating typesafe callbacks as the
+ * helpers typesafe_cb(), typesafe_cb_preargs() and
+ * typesafe_cb_postargs() demonstrate.
+ *
+ * The standard way of passing arguments to callback functions in C is
+ * to use a void pointer, which the callback then casts back to the
+ * expected type. This unfortunately subverts the type checking the
+ * compiler would perform if it were a direct call. Here's an example:
+ *
+ * static void my_callback(void *_obj)
+ * {
+ * struct obj *obj = _obj;
+ * ...
+ * }
+ * ...
+ * register_callback(my_callback, &my_obj);
+ *
+ * If we wanted to use the natural type for my_callback (ie. "void
+ * my_callback(struct obj *obj)"), we could make register_callback()
+ * take a void * as its first argument, but this would subvert all
+ * type checking. We really want register_callback() to accept only
+ * the exactly correct function type to match the argument, or a
+ * function which takes a void *.
+ *
+ * This is where typesafe_cb() comes in: it uses cast_if_type() to
+ * cast the callback function if it matches the argument type:
+ *
+ * void _register_callback(void (*cb)(void *arg), void *arg);
+ * #define register_callback(cb, arg) \
+ * _register_callback(typesafe_cb(void, (cb), (arg)), (arg))
+ *
+ * On compilers which don't support the extensions required
+ * cast_if_type() and friend become an unconditional cast, so your
+ * code will compile but you won't get type checking.
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+#include "typesafe_cb/typesafe_cb.h"
+
+void _set_some_value(void *val);
+
+void _set_some_value(void *val)
+{
+}
+
+#define set_some_value(expr) \
+ _set_some_value(cast_if_type((expr), unsigned long, void *))
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ int x = 0;
+ set_some_value(x);
+#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
+#error "Unfortunately we don't fail if cast_if_type is a noop."
+#endif
+#else
+ void *p = 0;
+ set_some_value(p);
+#endif
+ return 0;
+}
--- /dev/null
+#include "typesafe_cb/typesafe_cb.h"
+#include <stdlib.h>
+
+void _callback(void (*fn)(void *arg), void *arg);
+void _callback(void (*fn)(void *arg), void *arg)
+{
+ fn(arg);
+}
+
+/* Callback is set up to warn if arg isn't a pointer (since it won't
+ * pass cleanly to _callback's second arg. */
+#define callback(fn, arg) \
+ _callback(typesafe_cb(void, (fn), (arg)), (arg))
+
+void my_callback(int something);
+void my_callback(int something)
+{
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ /* This fails due to arg, not due to cast. */
+ callback(my_callback, 100);
+#endif
+ return 0;
+}
--- /dev/null
+#include "typesafe_cb/typesafe_cb.h"
+#include <stdlib.h>
+
+static void _register_callback(void (*cb)(void *arg), void *arg)
+{
+}
+
+#define register_callback(cb, arg) \
+ _register_callback(typesafe_cb(void, (cb), (arg)), (arg))
+
+static void my_callback(char *p)
+{
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ int *p;
+#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
+#error "Unfortunately we don't fail if cast_if_type is a noop."
+#endif
+#else
+ char *p;
+#endif
+ p = NULL;
+
+ /* This should work always. */
+ register_callback(my_callback, "hello world");
+
+ /* This will fail with FAIL defined */
+ register_callback(my_callback, p);
+ return 0;
+}
--- /dev/null
+#include "typesafe_cb/typesafe_cb.h"
+#include <stdlib.h>
+
+static void _register_callback(void (*cb)(void *arg, int x), void *arg)
+{
+}
+#define register_callback(cb, arg) \
+ _register_callback(typesafe_cb_postargs(void, (cb), (arg), int), (arg))
+
+static void my_callback(char *p, int x)
+{
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ int *p;
+#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
+#error "Unfortunately we don't fail if cast_if_type is a noop."
+#endif
+#else
+ char *p;
+#endif
+ p = NULL;
+ register_callback(my_callback, p);
+ return 0;
+}
--- /dev/null
+#include "typesafe_cb/typesafe_cb.h"
+#include <stdlib.h>
+
+static void _register_callback(void (*cb)(int x, void *arg), void *arg)
+{
+}
+
+#define register_callback(cb, arg) \
+ _register_callback(typesafe_cb_preargs(void, (cb), (arg), int), (arg))
+
+static void my_callback(int x, char *p)
+{
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef FAIL
+ int *p;
+#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
+#error "Unfortunately we don't fail if cast_if_type is a noop."
+#endif
+#else
+ char *p;
+#endif
+ p = NULL;
+ register_callback(my_callback, p);
+ return 0;
+}
--- /dev/null
+#include "typesafe_cb/typesafe_cb.h"
+#include <string.h>
+#include "tap/tap.h"
+
+static char dummy = 0;
+
+/* The example usage. */
+static void _set_some_value(void *val)
+{
+ ok1(val == &dummy);
+}
+
+#define set_some_value(expr) \
+ _set_some_value(cast_if_type((expr), unsigned long, void *))
+
+static void _callback_onearg(void (*fn)(void *arg), void *arg)
+{
+ fn(arg);
+}
+
+static void _callback_preargs(void (*fn)(int a, int b, void *arg), void *arg)
+{
+ fn(1, 2, arg);
+}
+
+static void _callback_postargs(void (*fn)(void *arg, int a, int b), void *arg)
+{
+ fn(arg, 1, 2);
+}
+
+#define callback_onearg(cb, arg) \
+ _callback_onearg(typesafe_cb(void, (cb), (arg)), (arg))
+
+#define callback_preargs(cb, arg) \
+ _callback_preargs(typesafe_cb_preargs(void, (cb), (arg), int, int), (arg))
+
+#define callback_postargs(cb, arg) \
+ _callback_postargs(typesafe_cb_postargs(void, (cb), (arg), int, int), (arg))
+
+static void my_callback_onearg(char *p)
+{
+ ok1(strcmp(p, "hello world") == 0);
+}
+
+static void my_callback_onearg_const(const char *p)
+{
+ ok1(strcmp(p, "hello world") == 0);
+}
+
+static void my_callback_onearg_volatile(volatile char *p)
+{
+ ok1(strcmp((char *)p, "hello world") == 0);
+}
+
+static void my_callback_preargs(int a, int b, char *p)
+{
+ ok1(a == 1);
+ ok1(b == 2);
+ ok1(strcmp(p, "hello world") == 0);
+}
+
+static void my_callback_preargs_const(int a, int b, const char *p)
+{
+ ok1(a == 1);
+ ok1(b == 2);
+ ok1(strcmp(p, "hello world") == 0);
+}
+
+static void my_callback_preargs_volatile(int a, int b, volatile char *p)
+{
+ ok1(a == 1);
+ ok1(b == 2);
+ ok1(strcmp((char *)p, "hello world") == 0);
+}
+
+static void my_callback_postargs(char *p, int a, int b)
+{
+ ok1(a == 1);
+ ok1(b == 2);
+ ok1(strcmp(p, "hello world") == 0);
+}
+
+static void my_callback_postargs_const(const char *p, int a, int b)
+{
+ ok1(a == 1);
+ ok1(b == 2);
+ ok1(strcmp(p, "hello world") == 0);
+}
+
+static void my_callback_postargs_volatile(volatile char *p, int a, int b)
+{
+ ok1(a == 1);
+ ok1(b == 2);
+ ok1(strcmp((char *)p, "hello world") == 0);
+}
+
+/* This is simply a compile test; we promised cast_if_type can be in a
+ * static initializer. */
+struct callback_onearg
+{
+ void (*fn)(void *arg);
+ void *arg;
+};
+
+struct callback_onearg cb_onearg
+= { typesafe_cb(void, my_callback_onearg, "hello world"), "hello world" };
+
+struct callback_preargs
+{
+ void (*fn)(int a, int b, void *arg);
+ void *arg;
+};
+
+struct callback_preargs cb_preargs
+= { typesafe_cb_preargs(void, my_callback_preargs, "hi", int, int), "hi" };
+
+struct callback_postargs
+{
+ void (*fn)(void *arg, int a, int b);
+ void *arg;
+};
+
+struct callback_postargs cb_postargs
+= { typesafe_cb_postargs(void, my_callback_postargs, "hi", int, int), "hi" };
+
+int main(int argc, char *argv[])
+{
+ void *p = &dummy;
+ unsigned long l = (unsigned long)p;
+
+ plan_tests(2 + 3 + 9 + 9);
+ set_some_value(p);
+ set_some_value(l);
+
+ callback_onearg(my_callback_onearg, "hello world");
+ callback_onearg(my_callback_onearg_const, "hello world");
+ callback_onearg(my_callback_onearg_volatile, "hello world");
+
+ callback_preargs(my_callback_preargs, "hello world");
+ callback_preargs(my_callback_preargs_const, "hello world");
+ callback_preargs(my_callback_preargs_volatile, "hello world");
+
+ callback_postargs(my_callback_postargs, "hello world");
+ callback_postargs(my_callback_postargs_const, "hello world");
+ callback_postargs(my_callback_postargs_volatile, "hello world");
+
+ return exit_status();
+}
--- /dev/null
+#ifndef CCAN_CAST_IF_TYPE_H
+#define CCAN_CAST_IF_TYPE_H
+#include "config.h"
+
+#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
+/**
+ * cast_if_type - only cast an expression if it is of a given type
+ * @expr: the expression to cast
+ * @oktype: the type we allow
+ * @desttype: the type to cast to
+ *
+ * This macro is used to create functions which allow multiple types.
+ * The result of this macro is used somewhere that a @desttype type is
+ * expected: if @expr was of type @oktype, it will be cast to
+ * @desttype type. As a result, if @expr is any type other than
+ * @oktype or @desttype, a compiler warning will be issued.
+ *
+ * This macro can be used in static initializers.
+ *
+ * This is merely useful for warnings: if the compiler does not
+ * support the primitives required for cast_if_type(), it becomes an
+ * unconditional cast, and the @oktype argument is not used. In
+ * particular, this means that @oktype can be a type which uses
+ * the "typeof": it will not be evaluated if typeof is not supported.
+ *
+ * Example:
+ * // We can take either an unsigned long or a void *.
+ * void _set_some_value(void *val);
+ * #define set_some_value(expr) \
+ * _set_some_value(cast_if_type((expr), unsigned long, void *))
+ */
+#define cast_if_type(expr, oktype, desttype) \
+__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(expr):0), oktype), \
+ (desttype)(expr), (expr))
+#else
+#define cast_if_type(expr, oktype, desttype) ((desttype)(expr))
+#endif
+
+/**
+ * typesafe_cb - cast a callback function if it matches the arg
+ * @rettype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * If a callback function takes a single argument, this macro does
+ * appropriate casts to a function which takes a single void * argument if the
+ * callback provided matches the @arg (or a const or volatile version).
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(void *arg), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb(void, (fn), (arg)), (arg))
+ */
+#define typesafe_cb(rettype, fn, arg) \
+ cast_if_type(cast_if_type(cast_if_type((fn), \
+ rettype (*)(const typeof(arg)), \
+ rettype (*)(void *)), \
+ rettype (*)(volatile typeof(arg)), \
+ rettype (*)(void *)), \
+ rettype (*)(typeof(arg)), \
+ rettype (*)(void *))
+
+/**
+ * typesafe_cb_preargs - cast a callback function if it matches the arg
+ * @rettype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * before the @arg.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(int, void *arg), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
+ * (arg))
+ */
+#define typesafe_cb_preargs(rettype, fn, arg, ...) \
+ cast_if_type(cast_if_type(cast_if_type((fn), \
+ rettype (*)(__VA_ARGS__, \
+ const typeof(arg)), \
+ rettype (*)(__VA_ARGS__, \
+ void *)), \
+ rettype (*)(__VA_ARGS__, \
+ volatile typeof(arg)), \
+ rettype (*)(__VA_ARGS__, void *)), \
+ rettype (*)(__VA_ARGS__, typeof(arg)), \
+ rettype (*)(__VA_ARGS__, void *))
+
+/**
+ * typesafe_cb_postargs - cast a callback function if it matches the arg
+ * @rettype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * after the @arg.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(void *arg, int), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
+ * (arg))
+ */
+#define typesafe_cb_postargs(rettype, fn, arg, ...) \
+ cast_if_type(cast_if_type(cast_if_type((fn), \
+ rettype (*)(const typeof(arg), \
+ __VA_ARGS__), \
+ rettype (*)(void *, \
+ __VA_ARGS__)), \
+ rettype (*)(volatile typeof(arg), \
+ __VA_ARGS__), \
+ rettype (*)(void *, __VA_ARGS__)), \
+ rettype (*)(typeof(arg), __VA_ARGS__), \
+ rettype (*)(void *, __VA_ARGS__))
+
+#endif /* CCAN_CAST_IF_TYPE_H */
+++ /dev/null
-ccan_tools/run_tests: ccan_tools/run_tests.o tap/tap.o talloc/talloc.o
-
-ccan_tools/doc_extract: ccan_tools/doc_extract.c talloc/talloc.o
-
-ccan_tools/namespacize: ccan_tools/namespacize.c talloc/talloc.o
-
-ccan_tools-clean: ccanlint-clean
- rm -f run_tests doc_extract
-
-include ccan_tools/ccanlint/Makefile
+++ /dev/null
-OBJS := ccan_tools/ccanlint/no_info.o \
- ccan_tools/ccanlint/has_main_header.o \
- ccan_tools/ccanlint/has_tests.o \
- ccan_tools/ccanlint/trailing_whitespace.o \
- ccan_tools/ccanlint/idempotent.o \
-
-FUTURE:=ccan_tools/ccanlint/if_have_not_ifdef.o \
- ccan_tools/ccanlint/needs_depends.o \
- ccan_tools/ccanlint/has_info_documentation.o \
- ccan_tools/ccanlint/has_header_documentation.o \
- ccan_tools/ccanlint/has_tests.o \
- ccan_tools/ccanlint/builds_ok.o \
- ccan_tools/ccanlint/builds_ok_all_have_variants.o \
- ccan_tools/ccanlint/run_tests.o \
- ccan_tools/ccanlint/test_coverage.o \
-
-ccan_tools/ccanlint/generated-init-tests: $(OBJS)
- cat $(OBJS:.o=.c) | sed -n 's/^struct ccanlint \([A-Za-z0-9_]*\) = {/{ extern struct ccanlint \1; list_add(\&tests, \&\1.list); }/p' >$@
-
-ccan_tools/ccanlint/ccanlint.o: ccan_tools/ccanlint/generated-init-tests
-
-ccan_tools/ccanlint/ccanlint: \
- $(OBJS) \
- ccan_tools/ccanlint/ccanlint.o \
- ccan_tools/ccanlint/get_file_lines.o \
- ccan_tools/ccanlint/file_analysis.o \
- talloc/talloc.o noerr/noerr.o
-
-ccanlint-clean:
- $(RM) ccan_tools/ccanlint/generated-init-tests
-
+++ /dev/null
-/*
- * ccanlint: assorted checks and advice for a ccan package
- * Copyright (C) 2008 Rusty Russell
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "ccanlint.h"
-#include <unistd.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <err.h>
-#include <ctype.h>
-
-static unsigned int verbose = 0;
-static LIST_HEAD(tests);
-
-static void init_tests(void)
-{
-#include "generated-init-tests"
-}
-
-static void usage(const char *name)
-{
- fprintf(stderr, "Usage: %s [-s] [-v] [-d <dirname>]\n"
- " -v: verbose mode\n"
- " -s: simply give one line per FAIL and total score\n"
- " -d: use this directory instead of the current one\n",
- name);
- exit(1);
-}
-
-static void indent_print(const char *string)
-{
- while (*string) {
- unsigned int line = strcspn(string, "\n");
- printf("\t%.*s", line, string);
- if (string[line] == '\n') {
- printf("\n");
- line++;
- }
- string += line;
- }
-}
-
-bool ask(const char *question)
-{
- char reply[2];
-
- printf("%s ", question);
- fflush(stdout);
-
- return fgets(reply, sizeof(reply), stdin) != NULL
- && toupper(reply[0]) == 'Y';
-}
-
-static bool run_test(const struct ccanlint *i,
- bool summary,
- unsigned int *score,
- unsigned int *total_score,
- struct manifest *m)
-{
- void *result;
- unsigned int this_score;
-
- if (i->total_score)
- *total_score += i->total_score;
-
- result = i->check(m);
- if (!result) {
- if (verbose)
- printf(" %s: OK\n", i->name);
- if (i->total_score)
- *score += i->total_score;
- return true;
- }
-
- if (i->score)
- this_score = i->score(m, result);
- else
- this_score = 0;
-
- *score += this_score;
- if (summary) {
- printf("%s FAILED (%u/%u)\n",
- i->name, this_score, i->total_score);
-
- if (verbose)
- indent_print(i->describe(m, result));
- return false;
- }
-
- printf("%s\n", i->describe(m, result));
-
- if (i->handle)
- i->handle(m, result);
-
- return false;
-}
-
-int main(int argc, char *argv[])
-{
- int c;
- bool summary = false;
- unsigned int score, total_score;
- struct manifest *m;
- const struct ccanlint *i;
-
- /* I'd love to use long options, but that's not standard. */
- /* FIXME: getopt_long ccan package? */
- while ((c = getopt(argc, argv, "sd:v")) != -1) {
- switch (c) {
- case 'd':
- if (chdir(optarg) != 0)
- err(1, "Changing into directory '%s'", optarg);
- break;
- case 's':
- summary = true;
- break;
- case 'v':
- verbose++;
- break;
- default:
- usage(argv[0]);
- }
- }
-
- if (optind < argc)
- usage(argv[0]);
-
- m = get_manifest();
-
- init_tests();
-
- /* If you don't pass the compulsory tests, you don't even get a score */
- if (verbose)
- printf("Compulsory tests:\n");
- list_for_each(&tests, i, list)
- if (!i->total_score && !run_test(i, summary, NULL, NULL, m))
- exit(1);
-
- if (verbose)
- printf("\nNormal tests:\n");
- score = total_score = 0;
- list_for_each(&tests, i, list)
- if (i->total_score)
- run_test(i, summary, &score, &total_score, m);
-
- printf("Total score: %u/%u\n", score, total_score);
-
- return 0;
-}
+++ /dev/null
-#ifndef CCAN_LINT_H
-#define CCAN_LINT_H
-#include <list/list.h>
-#include <stdbool.h>
-
-struct manifest {
- char *basename;
- struct ccan_file *info_file;
-
- struct list_head c_files;
- struct list_head h_files;
-
- struct list_head run_tests;
- struct list_head compile_ok_tests;
- struct list_head compile_fail_tests;
- struct list_head other_test_files;
-
- struct list_head other_files;
-};
-
-struct manifest *get_manifest(void);
-
-struct ccanlint {
- struct list_node list;
-
- /* Unique name of test */
- const char *name;
-
- /* Total score that this test is worth. 0 means compulsory tests. */
- unsigned int total_score;
-
- /* If this returns non-NULL, it means the check failed. */
- void *(*check)(struct manifest *m);
-
- /* The non-NULL return from check is passed to one of these: */
-
- /* So, what did this get out of the total_score? (NULL means 0). */
- unsigned int (*score)(struct manifest *m, void *check_result);
-
- /* Verbose description of what was wrong. */
- const char *(*describe)(struct manifest *m, void *check_result);
-
- /* Can we do something about it? (NULL if not) */
- void (*handle)(struct manifest *m, void *check_result);
-};
-
-/* Ask the user a yes/no question: the answer is NO if there's an error. */
-bool ask(const char *question);
-
-struct ccan_file {
- struct list_node list;
-
- char *name;
-
- unsigned int num_lines;
- char **lines;
-};
-
-/* Use this rather than accessing f->lines directly: loads on demand. */
-char **get_ccan_file_lines(struct ccan_file *f);
-
-/* Call the reporting on every line in the file. sofar contains
- * previous results. */
-char *report_on_lines(struct list_head *files,
- char *(*report)(const char *),
- char *sofar);
-
-/* The critical tests which mean fail if they don't pass. */
-extern struct ccanlint no_info;
-extern struct ccanlint has_main_header;
-
-/* Normal tests. */
-extern struct ccanlint trailing_whitespace;
-
-
-#endif /* CCAN_LINT_H */
+++ /dev/null
-#include "ccanlint.h"
-#include "get_file_lines.h"
-#include <talloc/talloc.h>
-#include <string/string.h>
-#include <noerr/noerr.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <err.h>
-#include <errno.h>
-#include <dirent.h>
-
-char **get_ccan_file_lines(struct ccan_file *f)
-{
- if (!f->lines)
- f->lines = get_file_lines(f, f->name, &f->num_lines);
- return f->lines;
-}
-
-static void add_files(struct manifest *m, const char *dir)
-{
- DIR *d;
- struct dirent *ent;
-
- if (dir[0])
- d = opendir(dir);
- else
- d = opendir(".");
- if (!d)
- err(1, "Opening directory %s", dir[0] ? dir : ".");
-
- while ((ent = readdir(d)) != NULL) {
- struct stat st;
- struct ccan_file *f;
- struct list_head *dest;
- bool is_c_src;
-
- if (ent->d_name[0] == '.')
- continue;
-
- f = talloc(m, struct ccan_file);
- f->lines = NULL;
- f->name = talloc_asprintf(f, "%s%s", dir, ent->d_name);
- if (lstat(f->name, &st) != 0)
- err(1, "lstat %s", f->name);
-
- if (S_ISDIR(st.st_mode)) {
- f->name = talloc_append_string(f->name, "/");
- add_files(m, f->name);
- continue;
- }
- if (!S_ISREG(st.st_mode)) {
- talloc_free(f);
- continue;
- }
-
- if (streq(f->name, "_info.c")) {
- m->info_file = f;
- continue;
- }
-
- is_c_src = strends(f->name, ".c");
- if (!is_c_src && !strends(f->name, ".h"))
- dest = &m->other_files;
- else if (!strchr(f->name, '/')) {
- if (is_c_src)
- dest = &m->c_files;
- else
- dest = &m->h_files;
- } else if (strstarts(f->name, "test/")) {
- if (is_c_src) {
- if (strstarts(f->name, "test/run"))
- dest = &m->run_tests;
- else if (strstarts(f->name, "test/compile_ok"))
- dest = &m->compile_ok_tests;
- else if (strstarts(f->name, "test/compile_fail"))
- dest = &m->compile_fail_tests;
- else
- dest = &m->other_test_files;
- } else
- dest = &m->other_test_files;
- } else
- dest = &m->other_files;
-
- list_add(dest, &f->list);
- }
- closedir(d);
-}
-
-char *report_on_lines(struct list_head *files,
- char *(*report)(const char *),
- char *sofar)
-{
- struct ccan_file *f;
-
- list_for_each(files, f, list) {
- unsigned int i;
- char **lines = get_ccan_file_lines(f);
-
- for (i = 0; i < f->num_lines; i++) {
- char *r = report(lines[i]);
- if (!r)
- continue;
-
- sofar = talloc_asprintf_append(sofar,
- "%s:%u:%s\n",
- f->name, i+1, r);
- talloc_free(r);
- }
- }
- return sofar;
-}
-
-struct manifest *get_manifest(void)
-{
- struct manifest *m = talloc(NULL, struct manifest);
- unsigned int len;
-
- m->info_file = NULL;
- list_head_init(&m->c_files);
- list_head_init(&m->h_files);
- list_head_init(&m->run_tests);
- list_head_init(&m->compile_ok_tests);
- list_head_init(&m->compile_fail_tests);
- list_head_init(&m->other_test_files);
- list_head_init(&m->other_files);
-
- /* *This* is why people hate C. */
- len = 32;
- m->basename = talloc_array(m, char, len);
- while (!getcwd(m->basename, len)) {
- if (errno != ERANGE)
- err(1, "Getting current directory");
- m->basename = talloc_realloc(m, m->basename, char, len *= 2);
- }
-
- len = strlen(m->basename);
- while (len && m->basename[len-1] == '/')
- m->basename[--len] = '\0';
-
- m->basename = strrchr(m->basename, '/');
- if (!m->basename)
- errx(1, "I don't expect to be run from the root directory");
- m->basename++;
-
- add_files(m, "");
- return m;
-}
+++ /dev/null
-#include "get_file_lines.h"
-#include <talloc/talloc.h>
-#include <string/string.h>
-#include <noerr/noerr.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <err.h>
-#include <dirent.h>
-
-static void *grab_fd(const void *ctx, int fd)
-{
- int ret;
- unsigned int max = 16384, size = 0;
- char *buffer;
-
- buffer = talloc_array(ctx, char, max+1);
- while ((ret = read(fd, buffer + size, max - size)) > 0) {
- size += ret;
- if (size == max)
- buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1);
- }
- if (ret < 0) {
- talloc_free(buffer);
- buffer = NULL;
- } else
- buffer[size] = '\0';
-
- return buffer;
-}
-
-/* This version adds one byte (for nul term) */
-static void *grab_file(const void *ctx, const char *filename)
-{
- int fd;
- char *buffer;
-
- if (streq(filename, "-"))
- fd = dup(STDIN_FILENO);
- else
- fd = open(filename, O_RDONLY, 0);
-
- if (fd < 0)
- return NULL;
-
- buffer = grab_fd(ctx, fd);
- close_noerr(fd);
- return buffer;
-}
-
-/* This is a dumb one which copies. We could mangle instead. */
-static char **split(const void *ctx, const char *text, const char *delims,
- unsigned int *nump)
-{
- char **lines = NULL;
- unsigned int max = 64, num = 0;
-
- lines = talloc_array(ctx, char *, max+1);
-
- while (*text != '\0') {
- unsigned int len = strcspn(text, delims);
- lines[num] = talloc_array(lines, char, len + 1);
- memcpy(lines[num], text, len);
- lines[num][len] = '\0';
- text += len;
- text += strspn(text, delims);
- if (++num == max)
- lines = talloc_realloc(ctx, lines, char *, max*=2 + 1);
- }
- lines[num] = NULL;
- if (nump)
- *nump = num;
- return lines;
-}
-
-char **get_file_lines(void *ctx, const char *name, unsigned int *num_lines)
-{
- char *buffer = grab_file(ctx, name);
-
- if (!buffer)
- err(1, "Getting file %s", name);
-
- return split(buffer, buffer, "\n", num_lines);
-}
+++ /dev/null
-#ifndef GET_FILE_LINES_H
-#define GET_FILE_LINES_H
-
-char **get_file_lines(void *ctx, const char *name, unsigned int *num_lines);
-
-#endif /* GET_FILE_LINES_H */
+++ /dev/null
-#include "ccanlint.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <err.h>
-#include <string/string.h>
-#include <talloc/talloc.h>
-#include <noerr/noerr.h>
-
-static void *check_has_main_header(struct manifest *m)
-{
- struct ccan_file *f;
-
- list_for_each(&m->h_files, f, list) {
- if (strstarts(f->name, m->basename)
- && strlen(f->name) == strlen(m->basename) + 2)
- return NULL;
- }
- return m;
-}
-
-static const char *describe_has_main_header(struct manifest *m,
- void *check_result)
-{
- return talloc_asprintf(m,
- "You have no %s/%s.h header file.\n\n"
- "CCAN modules have a name, the same as the directory name. They're\n"
- "expected to have an interface in the header of the same name.\n",
- m->basename, m->basename);
-}
-
-struct ccanlint has_main_header = {
- .name = "No main header file",
- .check = check_has_main_header,
- .describe = describe_has_main_header,
-};
+++ /dev/null
-#include "ccanlint.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <err.h>
-#include <string/string.h>
-#include <talloc/talloc.h>
-#include <noerr/noerr.h>
-
-static char test_is_not_dir[] = "test is not a directory";
-
-static void *check_has_tests(struct manifest *m)
-{
- struct stat st;
-
- if (lstat("test", &st) != 0) {
- if (errno != ENOENT)
- err(1, "statting test/");
- return "You have no test directory";
- }
-
- if (!S_ISDIR(st.st_mode))
- return test_is_not_dir;
-
- if (list_empty(&m->run_tests) && list_empty(&m->compile_ok_tests)) {
- if (list_empty(&m->compile_fail_tests))
- return "You have no tests in the test directory";
- else
- return "You have no positive tests in the test directory";
- }
- return NULL;
-}
-
-static const char *describe_has_tests(struct manifest *m, void *check_result)
-{
- return talloc_asprintf(m, "%s\n\n"
- "CCAN modules have a directory called test/ which contains tests.\n"
- "There are three kinds of tests: run, compile_ok and compile_fail:\n"
- "you can tell which type of test a C file is by its name, eg 'run.c'\n"
- "and 'run-simple.c' are both run tests.\n\n"
- "The simplest kind of test is a run test, which must compile with no\n"
- "warnings, and then run: it is expected to use libtap to report its\n"
- "results in a simple and portable format.\n"
- "compile_ok tests are a subset of run tests: they must compile and\n"
- "link, but aren't run.\n"
- "compile_fail tests are tests which should fail to compile (or emit\n"
- "warnings) or link when FAIL is defined, but should compile and link\n"
- "when it's not defined: this helps ensure unrelated errors don't make\n"
- "compilation fail.\n\n"
- "Note that the tests are not linked against the files in the\n"
- "above: you should directly #include those C files you want. This\n"
- "allows access to static functions and use special effects inside\n"
- "test files\n", (char *)check_result);
-}
-
-static void handle_no_tests(struct manifest *m, void *check_result)
-{
- FILE *run;
- struct ccan_file *i;
-
- if (check_result == test_is_not_dir)
- return;
-
- if (!ask("Should I create a template test/run.c file for you?"))
- return;
-
- if (mkdir("test", 0600) != 0) {
- if (errno != EEXIST)
- err(1, "Creating test/ directory");
- }
-
- run = fopen("test/run.c", "w");
- if (!run)
- err(1, "Trying to create a test/run.c");
-
- fputs("/* Include the main header first, to test it works */\n", run);
- fprintf(run, "#include \"%s/%s.h\"\n", m->basename, m->basename);
- fputs("/* Include the C files directly. */\n", run);
- list_for_each(&m->c_files, i, list)
- fprintf(run, "#include \"%s/%s\"\n", m->basename, i->name);
- fputs("#include \"tap/tap.h\"\n", run);
- fputs("\n", run);
-
- fputs("int main(int argc, char *argv[])\n", run);
- fputs("{\n", run);
- fputs("\t/* This is how many tests you plan to run\n", run);
- fputs("\tplan_tests(3);\n", run);
- fputs("\n", run);
- fputs("\t/* Simple thing we expect to succeed */\n", run);
- fputs("\tok1(some_test())\n", run);
- fputs("\t/* Same, with an explicit description of the test. */\n", run);
- fputs("\tok(some_test(), \"%s with no args should return 1\", \"some_test\")\n", run);
- fputs("\t/* How to print out messages for debugging. */\n", run);
- fputs("\tdiag(\"Address of some_test is %p\", &some_test)\n", run);
- fputs("\t/* Conditional tests must be explicitly skipped. */\n", run);
- fputs("#if HAVE_SOME_FEATURE\n", run);
- fputs("\tok1(test_some_feature())\n", run);
- fputs("#else\n", run);
- fputs("\tskip(1, \"Don\'t have SOME_FEATURE\")\n", run);
- fputs("#endif\n", run);
- fputs("\n", run);
- fputs("\t/* This exits depending on whether all tests passed */\n", run);
- fputs("\return exit_status()\n", run);
-
- fclose(run);
-}
-
-struct ccanlint has_tests = {
- .name = "No tests",
- .check = check_has_tests,
- .describe = describe_has_tests,
- .handle = handle_no_tests,
-};
+++ /dev/null
-#include "ccanlint.h"
-#include <talloc/talloc.h>
-#include <string/string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <err.h>
-#include <string.h>
-
-static const char explain[]
-= "Headers usually start with the C preprocessor lines to prevent multiple\n"
- "inclusions. These look like the following:\n"
- "#ifndef MY_HEADER_H\n"
- "#define MY_HEADER_H\n"
- "...\n"
- "#endif /* MY_HEADER_H */\n";
-
-static char *report_idem(struct ccan_file *f, char *sofar)
-{
- char **lines;
- char *secondline;
-
- lines = get_ccan_file_lines(f);
- if (f->num_lines < 3)
- /* FIXME: We assume small headers probably uninteresting. */
- return NULL;
-
- if (!strstarts(lines[0], "#ifndef "))
- return talloc_asprintf_append(sofar,
- "%s:1:expect first line to be #ifndef.\n", f->name);
-
- secondline = talloc_asprintf(f, "#define %s",
- lines[0] + strlen("#ifndef "));
- if (!streq(lines[1], secondline))
- return talloc_asprintf_append(sofar,
- "%s:2:expect second line to be '%s'.\n",
- f->name, secondline);
-
- return sofar;
-}
-
-static void *check_idempotent(struct manifest *m)
-{
- struct ccan_file *f;
- char *report = NULL;
-
- list_for_each(&m->h_files, f, list)
- report = report_idem(f, report);
-
- return report;
-}
-
-static const char *describe_idempotent(struct manifest *m, void *check_result)
-{
- return talloc_asprintf(check_result,
- "Some headers not idempotent:\n"
- "%s\n%s", (char *)check_result,
- explain);
-}
-
-struct ccanlint idempotent = {
- .name = "Headers are #ifndef/#define idempotent wrapped",
- .total_score = 1,
- .check = check_idempotent,
- .describe = describe_idempotent,
-};
+++ /dev/null
-#include "ccanlint.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <err.h>
-#include <string.h>
-#include <noerr/noerr.h>
-
-static void *check_no_info(struct manifest *m)
-{
- if (m->info_file)
- return NULL;
- return m;
-}
-
-static const char *describe_no_info(struct manifest *m, void *check_result)
-{
- return "You have no _info.c file.\n\n"
- "The file _info.c contains the metadata for a ccan package: things\n"
- "like the dependencies, the documentation for the package as a whole\n"
- "and license information.\n";
-}
-
-static const char template[] =
- "#include <string.h>\n"
- "#include \"config.h\"\n"
- "\n"
- "/**\n"
- " * %s - YOUR-ONE-LINE-DESCRIPTION-HERE\n"
- " *\n"
- " * This code ... YOUR-BRIEF-SUMMARY-HERE\n"
- " *\n"
- " * Example:\n"
- " * FULLY-COMPILABLE-INDENTED-TRIVIAL-BUT-USEFUL-EXAMPLE-HERE\n"
- " */\n"
- "int main(int argc, char *argv[])\n"
- "{\n"
- " /* Expect exactly one argument\n"
- " if (argc != 2)\n"
- " return 1;\n"
- "\n"
- " if (strcmp(argv[1], \"depends\") == 0) {\n"
- " PRINTF-CCAN-PACKAGES-YOU-NEED-ONE-PER-LINE-IF-ANY\n"
- " return 0;\n"
- " }\n"
- "\n"
- " return 1;\n"
- "}\n";
-
-static void create_info_template(struct manifest *m, void *check_result)
-{
- FILE *info;
-
- if (!ask("Should I create a template _info.c file for you?"))
- return;
-
- info = fopen("_info.c", "w");
- if (!info)
- err(1, "Trying to create a template _info.c");
-
- if (fprintf(info, template, m->basename) < 0) {
- unlink_noerr("_info.c");
- err(1, "Writing template into _info.c");
- }
- fclose(info);
-}
-
-struct ccanlint no_info = {
- .name = "No _info.c file",
- .check = check_no_info,
- .describe = describe_no_info,
- .handle = create_info_template,
-};
+++ /dev/null
-/* Trailing whitespace test. Almost embarrassing, but trivial. */
-#include "ccanlint.h"
-#include <talloc/talloc.h>
-#include <string/string.h>
-
-static char *report_on_trailing_whitespace(const char *line)
-{
- if (!strends(line, " ") && !strends(line, "\t"))
- return NULL;
-
- if (strlen(line) > 20)
- return talloc_asprintf(line, "...'%s'",
- line + strlen(line) - 20);
- return talloc_asprintf(line, "'%s'", line);
-}
-
-static void *check_trailing_whitespace(struct manifest *m)
-{
- char *report;
-
- report = report_on_lines(&m->c_files, report_on_trailing_whitespace,
- NULL);
- report = report_on_lines(&m->h_files, report_on_trailing_whitespace,
- report);
-
- return report;
-}
-
-static const char *describe_trailing_whitespace(struct manifest *m,
- void *check_result)
-{
- return talloc_asprintf(check_result,
- "Some source files have trailing whitespace:\n"
- "%s", (char *)check_result);
-}
-
-struct ccanlint trailing_whitespace = {
- .name = "Lines with unnecessary trailing whitespace",
- .total_score = 1,
- .check = check_trailing_whitespace,
- .describe = describe_trailing_whitespace,
-};
+++ /dev/null
-/* This merely extracts, doesn't do XML or anything. */
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include "talloc/talloc.h"
-
-/* Is A == B ? */
-#define streq(a,b) (strcmp((a),(b)) == 0)
-
-/* Does A start with B ? */
-#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0)
-
-/* This version adds one byte (for nul term) */
-static void *grab_file(void *ctx, const char *filename)
-{
- unsigned int max = 16384, size = 0;
- int ret, fd;
- char *buffer;
-
- if (streq(filename, "-"))
- fd = dup(STDIN_FILENO);
- else
- fd = open(filename, O_RDONLY, 0);
-
- if (fd < 0)
- return NULL;
-
- buffer = talloc_array(ctx, char, max+1);
- while ((ret = read(fd, buffer + size, max - size)) > 0) {
- size += ret;
- if (size == max)
- buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1);
- }
- if (ret < 0) {
- talloc_free(buffer);
- buffer = NULL;
- } else
- buffer[size] = '\0';
- close(fd);
- return buffer;
-}
-
-/* This is a dumb one which copies. We could mangle instead. */
-static char **split(const char *text)
-{
- char **lines = NULL;
- unsigned int max = 64, num = 0;
-
- lines = talloc_array(text, char *, max+1);
-
- while (*text != '\0') {
- unsigned int len = strcspn(text, "\n");
- lines[num] = talloc_array(lines, char, len + 1);
- memcpy(lines[num], text, len);
- lines[num][len] = '\0';
- text += len + 1;
- if (++num == max)
- lines = talloc_realloc(text, lines, char *, max*=2 + 1);
- }
- lines[num] = NULL;
- return lines;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i, j;
-
- for (i = 1; i < argc; i++) {
- char *file;
- char **lines;
- bool printing = false, printed = false;
-
- file = grab_file(NULL, argv[i]);
- if (!file)
- err(1, "Reading file %s", argv[i]);
- lines = split(file);
-
- for (j = 0; lines[j]; j++) {
- if (streq(lines[j], "/**")) {
- printing = true;
- if (printed++)
- puts("\n");
- } else if (streq(lines[j], " */"))
- printing = false;
- else if (printing) {
- if (strstarts(lines[j], " * "))
- puts(lines[j] + 3);
- else if (strstarts(lines[j], " *"))
- puts(lines[j] + 2);
- else
- errx(1, "Malformed line %s:%u",
- argv[i], j);
- }
- }
- talloc_free(file);
- }
- return 0;
-}
-
-
-
+++ /dev/null
-/* Code to move a ccan module into the ccan_ namespace. */
-#include <err.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include "talloc/talloc.h"
-
-#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I. -Iccan_tools/libtap/src/"
-
-#define IDENT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
- "abcdefghijklmnopqrstuvwxyz" \
- "01234567889_"
-
-static bool verbose = false;
-static int indent = 0;
-#define verbose(args...) \
- do { if (verbose) { \
- unsigned int _i; \
- for (_i = 0; _i < indent; _i++) printf(" "); \
- printf(args); \
- } \
- } while(0)
-#define verbose_indent() (indent += 2)
-#define verbose_unindent() (indent -= 2)
-
-#define streq(a,b) (strcmp((a),(b)) == 0)
-
-#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
-
-static inline bool strends(const char *str, const char *postfix)
-{
- if (strlen(str) < strlen(postfix))
- return false;
-
- return streq(str + strlen(str) - strlen(postfix), postfix);
-}
-
-static int close_no_errno(int fd)
-{
- int ret = 0, serrno = errno;
- if (close(fd) < 0)
- ret = errno;
- errno = serrno;
- return ret;
-}
-
-static int unlink_no_errno(const char *filename)
-{
- int ret = 0, serrno = errno;
- if (unlink(filename) < 0)
- ret = errno;
- errno = serrno;
- return ret;
-}
-
-static void *grab_fd(const void *ctx, int fd)
-{
- int ret;
- unsigned int max = 16384, size = 0;
- char *buffer;
-
- buffer = talloc_array(ctx, char, max+1);
- while ((ret = read(fd, buffer + size, max - size)) > 0) {
- size += ret;
- if (size == max)
- buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1);
- }
- if (ret < 0) {
- talloc_free(buffer);
- buffer = NULL;
- } else
- buffer[size] = '\0';
-
- return buffer;
-}
-
-/* This version adds one byte (for nul term) */
-static void *grab_file(const void *ctx, const char *filename)
-{
- int fd;
- char *buffer;
-
- if (streq(filename, "-"))
- fd = dup(STDIN_FILENO);
- else
- fd = open(filename, O_RDONLY, 0);
-
- if (fd < 0)
- return NULL;
-
- buffer = grab_fd(ctx, fd);
- close_no_errno(fd);
- return buffer;
-}
-
-/* This is a dumb one which copies. We could mangle instead. */
-static char **split(const void *ctx, const char *text, const char *delims,
- unsigned int *nump)
-{
- char **lines = NULL;
- unsigned int max = 64, num = 0;
-
- lines = talloc_array(ctx, char *, max+1);
-
- while (*text != '\0') {
- unsigned int len = strcspn(text, delims);
- lines[num] = talloc_array(lines, char, len + 1);
- memcpy(lines[num], text, len);
- lines[num][len] = '\0';
- text += len;
- text += strspn(text, delims);
- if (++num == max)
- lines = talloc_realloc(ctx, lines, char *, max*=2 + 1);
- }
- lines[num] = NULL;
- if (nump)
- *nump = num;
- return lines;
-}
-
-static char **get_dir(const char *dir)
-{
- DIR *d;
- struct dirent *ent;
- char **names = NULL;
- unsigned int size = 0;
-
- d = opendir(dir);
- if (!d)
- return NULL;
-
- while ((ent = readdir(d)) != NULL) {
- names = talloc_realloc(dir, names, char *, size + 2);
- names[size++]
- = talloc_asprintf(names, "%s/%s", dir, ent->d_name);
- }
- names[size++] = NULL;
- closedir(d);
- return names;
-}
-
-static char ** __attribute__((format(printf, 2, 3)))
-lines_from_cmd(const void *ctx, char *format, ...)
-{
- va_list ap;
- char *cmd, *buffer;
- FILE *p;
-
- va_start(ap, format);
- cmd = talloc_vasprintf(ctx, format, ap);
- va_end(ap);
-
- p = popen(cmd, "r");
- if (!p)
- err(1, "Executing '%s'", cmd);
-
- buffer = grab_fd(ctx, fileno(p));
- if (!buffer)
- err(1, "Reading from '%s'", cmd);
- pclose(p);
-
- return split(ctx, buffer, "\n", NULL);
-}
-
-struct replace
-{
- struct replace *next;
- char *string;
-};
-
-static void __attribute__((noreturn)) usage(void)
-{
- errx(1, "Usage:\n"
- "namespacize [--verbose] <dir>\n"
- "namespacize [--verbose] --adjust <dir>...\n"
- "The first form converts dir/ to insert 'ccan_' prefixes, and\n"
- "then adjusts any other ccan directories at the same level which\n"
- "are effected.\n"
- "--adjust does an adjustment for each directory, in case a\n"
- "dependency has been namespacized\n");
-}
-
-static void add_replace(struct replace **repl, const char *str)
-{
- struct replace *new, *i;
-
- /* Avoid duplicates. */
- for (i = *repl; i; i = i->next)
- if (streq(i->string, str))
- return;
-
- new = talloc(*repl, struct replace);
- new->next = *repl;
- new->string = talloc_strdup(new, str);
- *repl = new;
-}
-
-static void add_replace_tok(struct replace **repl, const char *s)
-{
- struct replace *new;
- unsigned int len = strspn(s, IDENT_CHARS);
-
- new = talloc(*repl, struct replace);
- new->next = *repl;
- new->string = talloc_strndup(new, s, len);
- *repl = new;
-}
-
-static char *basename(const void *ctx, const char *dir)
-{
- char *p = strrchr(dir, '/');
-
- if (!p)
- return (char *)dir;
- return talloc_strdup(ctx, p+1);
-}
-
-static void look_for_macros(char *contents, struct replace **repl)
-{
- char *p;
- enum { LINESTART, HASH, DEFINE, NONE } state = LINESTART;
-
- /* Look for lines of form #define X */
- for (p = contents; *p; p++) {
- if (*p == '\n')
- state = LINESTART;
- else if (!isspace(*p)) {
- if (state == LINESTART && *p == '#')
- state = HASH;
- else if (state==HASH && !strncmp(p, "define", 6)) {
- state = DEFINE;
- p += 5;
- } else if (state == DEFINE) {
- unsigned int len;
-
- len = strspn(p, IDENT_CHARS);
- if (len) {
- char *s;
- s = talloc_strndup(contents, p, len);
- /* Don't wrap idempotent wrappers */
- if (!strstarts(s, "CCAN_")) {
- verbose("Found %s\n", s);
- add_replace(repl, s);
- }
- }
- state = NONE;
- } else
- state = NONE;
- }
- }
-}
-
-/* Blank out preprocessor lines, and eliminate \ */
-static void preprocess(char *p)
-{
- char *s;
-
- /* We assume backslashes are only used for macros. */
- while ((s = strstr(p, "\\\n")) != NULL)
- s[0] = s[1] = ' ';
-
- /* Now eliminate # lines. */
- if (p[0] == '#') {
- unsigned int i;
- for (i = 0; p[i] != '\n'; i++)
- p[i] = ' ';
- }
- while ((s = strstr(p, "\n#")) != NULL) {
- unsigned int i;
- for (i = 1; s[i] != '\n'; i++)
- s[i] = ' ';
- }
-}
-
-static char *get_statement(const void *ctx, char **p)
-{
- unsigned brackets = 0;
- bool seen_brackets = false;
- char *answer = talloc_strdup(ctx, "");
-
- for (;;) {
- if ((*p)[0] == '/' && (*p)[1] == '/')
- *p += strcspn(*p, "\n");
- else if ((*p)[0] == '/' && (*p)[1] == '*')
- *p = strstr(*p, "*/") + 1;
- else {
- char c = **p;
- if (c == ';' && !brackets) {
- (*p)++;
- return answer;
- }
- /* Compress whitespace into a single ' ' */
- if (isspace(c)) {
- c = ' ';
- while (isspace((*p)[1]))
- (*p)++;
- } else if (c == '{' || c == '(' || c == '[') {
- if (c == '(')
- seen_brackets = true;
- brackets++;
- } else if (c == '}' || c == ')' || c == ']')
- brackets--;
-
- if (answer[0] != '\0' || c != ' ') {
- answer = talloc_realloc(NULL, answer, char,
- strlen(answer) + 2);
- answer[strlen(answer)+1] = '\0';
- answer[strlen(answer)] = c;
- }
- if (c == '}' && seen_brackets && brackets == 0) {
- (*p)++;
- return answer;
- }
- }
- (*p)++;
- if (**p == '\0')
- return NULL;
- }
-}
-
-/* This hack should handle well-formatted code. */
-static void look_for_definitions(char *contents, struct replace **repl)
-{
- char *stmt, *p = contents;
-
- preprocess(contents);
-
- while ((stmt = get_statement(contents, &p)) != NULL) {
- int i, len;
-
- /* Definition of struct/union? */
- if ((strncmp(stmt, "struct", 5) == 0
- || strncmp(stmt, "union", 5) == 0)
- && strchr(stmt, '{') && stmt[7] != '{')
- add_replace_tok(repl, stmt+7);
-
- /* Definition of var or typedef? */
- for (i = strlen(stmt)-1; i >= 0; i--)
- if (strspn(stmt+i, IDENT_CHARS) == 0)
- break;
-
- if (i != strlen(stmt)-1) {
- add_replace_tok(repl, stmt+i+1);
- continue;
- }
-
- /* function or array declaration? */
- len = strspn(stmt, IDENT_CHARS "* ");
- if (len > 0 && (stmt[len] == '(' || stmt[len] == '[')) {
- if (strspn(stmt + len + 1, IDENT_CHARS) != 0) {
- for (i = len-1; i >= 0; i--)
- if (strspn(stmt+i, IDENT_CHARS) == 0)
- break;
- if (i != len-1) {
- add_replace_tok(repl, stmt+i+1);
- continue;
- }
- } else {
- /* Pointer to function? */
- len++;
- len += strspn(stmt + len, " *");
- i = strspn(stmt + len, IDENT_CHARS);
- if (i > 0 && stmt[len + i] == ')')
- add_replace_tok(repl, stmt+len);
- }
- }
- }
-}
-
-/* FIXME: Only does main header, should chase local includes. */
-static void analyze_headers(const char *dir, struct replace **repl)
-{
- char *hdr, *contents;
-
- /* Get hold of header, assume that's it. */
- hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir));
- contents = grab_file(dir, hdr);
- if (!contents)
- err(1, "Reading %s", hdr);
-
- verbose("Looking in %s for macros\n", hdr);
- verbose_indent();
- look_for_macros(contents, repl);
- verbose_unindent();
-
- verbose("Looking in %s for symbols\n", hdr);
- verbose_indent();
- look_for_definitions(contents, repl);
- verbose_unindent();
-}
-
-static void write_replacement_file(const char *dir, struct replace **repl)
-{
- char *replname = talloc_asprintf(dir, "%s/.namespacize", dir);
- int fd;
- struct replace *r;
-
- fd = open(replname, O_WRONLY|O_CREAT|O_EXCL, 0644);
- if (fd < 0) {
- if (errno == EEXIST)
- errx(1, "%s already exists: can't namespacize twice",
- replname);
- err(1, "Opening %s", replname);
- }
-
- for (r = *repl; r; r = r->next) {
- if (write(fd,r->string,strlen(r->string)) != strlen(r->string)
- || write(fd, "\n", 1) != 1) {
- unlink_no_errno(replname);
- if (errno == 0)
- errx(1, "Short write to %s: disk full?",
- replname);
- errx(1, "Writing to %s", replname);
- }
- }
-
- close(fd);
-}
-
-static int unlink_destroy(char *name)
-{
- unlink(name);
- return 0;
-}
-
-static char *find_word(char *f, const char *str)
-{
- char *p = f;
-
- while ((p = strstr(p, str)) != NULL) {
- /* Check it's not in the middle of a word. */
- if (p > f && (isalnum(p[-1]) || p[-1] == '_')) {
- p++;
- continue;
- }
- if (isalnum(p[strlen(str)]) || p[strlen(str)] == '_') {
- p++;
- continue;
- }
- return p;
- }
- return NULL;
-}
-
-/* This is horribly inefficient but simple. */
-static const char *rewrite_file(const char *filename,
- const struct replace *repl)
-{
- char *newname, *file;
- int fd;
-
- verbose("Rewriting %s\n", filename);
- file = grab_file(filename, filename);
- if (!file)
- err(1, "Reading file %s", filename);
-
- for (; repl; repl = repl->next) {
- char *p;
-
- while ((p = find_word(file, repl->string)) != NULL) {
- unsigned int off;
- char *new = talloc_array(file, char, strlen(file)+6);
-
- off = p - file;
- memcpy(new, file, off);
- if (isupper(repl->string[0]))
- memcpy(new + off, "CCAN_", 5);
- else
- memcpy(new + off, "ccan_", 5);
- strcpy(new + off + 5, file + off);
- file = new;
- }
- }
-
- /* If we exit for some reason, we want this erased. */
- newname = talloc_asprintf(talloc_autofree_context(), "%s.tmp",
- filename);
- fd = open(newname, O_WRONLY|O_CREAT|O_EXCL, 0644);
- if (fd < 0)
- err(1, "Creating %s", newname);
-
- talloc_set_destructor(newname, unlink_destroy);
- if (write(fd, file, strlen(file)) != strlen(file)) {
- if (errno == 0)
- errx(1, "Short write to %s: disk full?", newname);
- errx(1, "Writing to %s", newname);
- }
- close(fd);
- return newname;
-}
-
-struct adjusted
-{
- struct adjusted *next;
- const char *file;
- const char *tmpfile;
-};
-
-static void setup_adjust_files(const char *dir,
- const struct replace *repl,
- struct adjusted **adj)
-{
- char **files;
-
- for (files = get_dir(dir); *files; files++) {
- if (strends(*files, "/test"))
- setup_adjust_files(*files, repl, adj);
- else if (strends(*files, ".c") || strends(*files, ".h")) {
- struct adjusted *a = talloc(dir, struct adjusted);
- a->next = *adj;
- a->file = *files;
- a->tmpfile = rewrite_file(a->file, repl);
- *adj = a;
- }
- }
-}
-
-/* This is the "commit" stage, so we hope it won't fail. */
-static void rename_files(const struct adjusted *adj)
-{
- while (adj) {
- if (rename(adj->tmpfile, adj->file) != 0)
- warn("Could not rename over '%s', we're in trouble",
- adj->file);
- adj = adj->next;
- }
-}
-
-static void convert_dir(const char *dir)
-{
- char *name;
- struct replace *replace = NULL;
- struct adjusted *adj = NULL;
-
- /* Remove any ugly trailing slashes. */
- name = talloc_strdup(NULL, dir);
- while (strends(name, "/"))
- name[strlen(name)-1] = '\0';
-
- analyze_headers(name, &replace);
- write_replacement_file(name, &replace);
- setup_adjust_files(name, replace, &adj);
- rename_files(adj);
- talloc_free(name);
- talloc_free(replace);
-}
-
-static struct replace *read_replacement_file(const char *depdir)
-{
- struct replace *repl = NULL;
- char *replname = talloc_asprintf(depdir, "%s/.namespacize", depdir);
- char *file, **line;
-
- file = grab_file(replname, replname);
- if (!file) {
- if (errno != ENOENT)
- err(1, "Opening %s", replname);
- return NULL;
- }
-
- for (line = split(file, file, "\n", NULL); *line; line++)
- add_replace(&repl, *line);
- return repl;
-}
-
-static char *build_info(const void *ctx, const char *dir)
-{
- char *file, *cfile, *cmd;
-
- cfile = talloc_asprintf(ctx, "%s/%s", dir, "_info.c");
- file = talloc_asprintf(cfile, "%s/%s", dir, "_info");
- cmd = talloc_asprintf(file, "gcc " CFLAGS " -o %s %s", file, cfile);
- if (system(cmd) != 0)
- errx(1, "Failed to compile %s", file);
-
- return file;
-}
-
-static char **get_deps(const void *ctx, const char *dir)
-{
- char **deps, *cmd;
-
- cmd = talloc_asprintf(ctx, "%s depends", build_info(ctx, dir));
- deps = lines_from_cmd(cmd, cmd);
- if (!deps)
- err(1, "Could not run '%s'", cmd);
- return deps;
-}
-
-static char *parent_dir(const void *ctx, const char *dir)
-{
- char *parent, *slash;
-
- parent = talloc_strdup(ctx, dir);
- slash = strrchr(parent, '/');
- if (slash)
- *slash = '\0';
- else
- parent = talloc_strdup(ctx, ".");
- return parent;
-}
-
-static void adjust_dir(const char *dir)
-{
- char *parent = parent_dir(NULL, dir);
- char **deps;
-
- verbose("Adjusting %s\n", dir);
- verbose_indent();
- for (deps = get_deps(parent, dir); *deps; deps++) {
- char *depdir;
- struct adjusted *adj = NULL;
- struct replace *repl;
-
- depdir = talloc_asprintf(parent, "%s/%s", parent, *deps);
- repl = read_replacement_file(depdir);
- if (repl) {
- verbose("%s has been namespacized\n", depdir);
- setup_adjust_files(parent, repl, &adj);
- rename_files(adj);
- } else
- verbose("%s has not been namespacized\n", depdir);
- talloc_free(depdir);
- }
- verbose_unindent();
-}
-
-static void adjust_dependents(const char *dir)
-{
- char *parent = parent_dir(NULL, dir);
- char *base = basename(parent, dir);
- char **file;
-
- verbose("Looking for dependents in %s\n", parent);
- verbose_indent();
- for (file = get_dir(parent); *file; file++) {
- char *infoc, **deps;
- bool isdep = false;
-
- if (basename(*file, *file)[0] == '.')
- continue;
-
- infoc = talloc_asprintf(*file, "%s/_info.c", *file);
- if (access(infoc, R_OK) != 0)
- continue;
-
- for (deps = get_deps(*file, *file); *deps; deps++) {
- if (streq(*deps, base))
- isdep = true;
- }
- if (isdep)
- adjust_dir(*file);
- else
- verbose("%s is not dependent\n", *file);
- }
- verbose_unindent();
-}
-
-int main(int argc, char *argv[])
-{
- if (argv[1] && streq(argv[1], "--verbose")) {
- verbose = true;
- argv++;
- argc--;
- }
-
- if (argc == 2) {
- verbose("Namespacizing %s\n", argv[1]);
- verbose_indent();
- convert_dir(argv[1]);
- adjust_dependents(argv[1]);
- verbose_unindent();
- return 0;
- }
-
- if (argc > 2 && streq(argv[1], "--adjust")) {
- unsigned int i;
-
- for (i = 2; i < argc; i++)
- adjust_dir(argv[i]);
- return 0;
- }
- usage();
-}
+++ /dev/null
-#include <err.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <assert.h>
-#include <unistd.h>
-#include "tap/tap.h"
-#include "talloc/talloc.h"
-#include "../string/string.h"
-
-#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I."
-
-/* FIXME: Use build bug later. */
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-static struct test *tests = NULL;
-static struct obj *objs = NULL;
-static int verbose;
-
-struct test_type
-{
- const char *name;
- void (*testfn)(struct test_type *t, const char *name);
-};
-
-struct test
-{
- struct test *next;
- struct test_type *type;
- char *name;
-};
-
-struct obj
-{
- struct obj *next;
- char *name;
-};
-
-static char *output_name(const char *name)
-{
- char *ret;
-
- assert(strends(name, ".c"));
-
- ret = talloc_strdup(name, name);
- ret[strlen(ret) - 2] = '\0';
- return ret;
-}
-
-static char *obj_list(void)
-{
- char *list = talloc_strdup(objs, "");
- struct obj *i;
-
- for (i = objs; i; i = i->next)
- list = talloc_asprintf_append(list, "%s ", i->name);
-
- /* FIXME */
- list = talloc_asprintf_append(list, "tap/tap.o");
- return list;
-}
-
-static void compile_objs(void)
-{
- struct obj *i;
-
- for (i = objs; i; i = i->next) {
- char *cmd = talloc_asprintf(i, "gcc " CFLAGS " -o %s.o -c %s%s",
- output_name(i->name), i->name,
- verbose ? "" : "> /dev/null 2>&1");
- ok(system(cmd) == 0, "%s", cmd);
- }
-}
-
-static void cleanup_objs(void)
-{
- struct obj *i;
-
- for (i = objs; i; i = i->next)
- unlink(talloc_asprintf(i, "%s.o", output_name(i->name)));
-}
-
-static void add_test(const char *testdir, const char *name, struct test_type *t)
-{
- struct test *test = talloc(testdir, struct test);
-
- test->next = tests;
- test->type = t;
- test->name = talloc_asprintf(test, "%s/%s", testdir, name);
- tests = test;
-}
-
-static void add_obj(const char *testdir, const char *name)
-{
- struct obj *obj = talloc(testdir, struct obj);
-
- obj->next = objs;
- obj->name = talloc_asprintf(obj, "%s/%s", testdir, name);
- objs = obj;
-}
-
-static int build(const char *name, int fail)
-{
- const char *cmd;
- int ret;
-
- cmd = talloc_asprintf(name, "gcc " CFLAGS " %s -o %s %s %s%s",
- fail ? "-DFAIL" : "",
- output_name(name), name, obj_list(),
- verbose ? "" : "> /dev/null 2>&1");
-
- if (verbose)
- fprintf(stderr, "Running %s\n", cmd);
-
- ret = system(cmd);
- if (ret == -1)
- diag("cmd '%s' failed to execute", cmd);
-
- return ret;
-}
-
-static void compile_ok(struct test_type *t, const char *name)
-{
- ok(build(name, 0) == 0, "%s %s", t->name, name);
-}
-
-static void compile_fail(struct test_type *t, const char *name)
-{
- if (build(name, 0) != 0)
- fail("non-FAIL build %s", name);
- else
- ok(build(name, 1) > 0, "%s %s", t->name, name);
-}
-
-static void run(const char *name)
-{
- if (system(output_name(name)) == -1)
- fail("running %s had error %m", name);
-}
-
-static void cleanup(const char *name)
-{
- unlink(output_name(name));
-}
-
-static struct test_type test_types[] = {
- { "compile_ok", compile_ok },
- { "compile_fail", compile_fail },
- { "run", compile_ok },
-};
-
-int main(int argc, char *argv[])
-{
- DIR *dir;
- struct dirent *d;
- char *testdir;
- struct test *test;
- unsigned int num_tests = 0, num_objs = 0;
-
- if (argc > 1 && streq(argv[1], "--verbose")) {
- verbose = 1;
- argc--;
- argv++;
- }
-
- if (argc != 2)
- errx(1, "Usage: run_tests [--verbose] <dir>");
-
- testdir = talloc_asprintf(NULL, "%s/test", argv[1]);
- dir = opendir(testdir);
- if (!dir)
- err(1, "Opening '%s'", testdir);
-
- while ((d = readdir(dir)) != NULL) {
- unsigned int i;
- if (d->d_name[0] == '.' || !strends(d->d_name, ".c"))
- continue;
-
- for (i = 0; i < ARRAY_SIZE(test_types); i++) {
- if (strstarts(d->d_name, test_types[i].name)) {
- add_test(testdir, d->d_name, &test_types[i]);
- num_tests++;
- break;
- }
- }
- if (i == ARRAY_SIZE(test_types)) {
- add_obj(testdir, d->d_name);
- num_objs++;
- }
- }
-
- plan_tests(num_tests + num_objs);
- /* First all the extra object compilations. */
- compile_objs();
-
- /* Do all the test compilations. */
- for (test = tests; test; test = test->next)
- test->type->testfn(test->type, test->name);
-
- cleanup_objs();
-
- /* Now run all the ones which wanted to run. */
- for (test = tests; test; test = test->next) {
- if (streq(test->type->name, "run"))
- run(test->name);
- cleanup(test->name);
- }
-
- exit(exit_status());
-}
+++ /dev/null
-#! /bin/sh
-
-# First, test normal config.
-if ! make -s; then
- echo Normal config failed.
- exit 1
-fi
-
-# Now, remove one HAVE_ at a time.
-cp config.h original-config.h
-trap "mv original-config.h config.h && rm -f .newconfig" EXIT
-
-while grep -q '1$' config.h; do
- tr '\012' @ < config.h | sed 's/1@/0@/' | tr @ '\012' > .newconfig
- diff -u config.h .newconfig
- mv .newconfig config.h
- if ! make -s; then
- echo Failed config:
- cat config.h
- exit 1
- fi
-done
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * check_type - routines for compile time type checking
- *
- * C has fairly weak typing: ints get automatically converted to longs, signed
- * to unsigned, etc. There are some cases where this is best avoided, and
- * these macros provide methods for evoking warnings (or build errors) when
- * a precise type isn't used.
- *
- * On compilers which don't support typeof() these routines are less effective,
- * since they have to use sizeof() which can only distiguish between types of
- * different size.
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
-#if !HAVE_TYPEOF
- printf("build_assert\n");
-#endif
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-#ifndef CCAN_CHECK_TYPE_H
-#define CCAN_CHECK_TYPE_H
-#include "config.h"
-
-/**
- * check_type - issue a warning or build failure if type is not correct.
- * @expr: the expression whose type we should check (not evaluated).
- * @type: the exact type we expect the expression to be.
- *
- * This macro is usually used within other macros to try to ensure that a macro
- * argument is of the expected type. No type promotion of the expression is
- * done: an unsigned int is not the same as an int!
- *
- * check_type() always evaluates to 1.
- *
- * If your compiler does not support typeof, then the best we can do is fail
- * to compile if the sizes of the types are unequal (a less complete check).
- *
- * Example:
- * // They should always pass a 64-bit value to _set_some_value!
- * #define set_some_value(expr) \
- * _set_some_value((check_type((expr), uint64_t), (expr)))
- */
-
-/**
- * check_types_match - issue a warning or build failure if types are not same.
- * @expr1: the first expression (not evaluated).
- * @expr2: the second expression (not evaluated).
- *
- * This macro is usually used within other macros to try to ensure that
- * arguments are of identical types. No type promotion of the expressions is
- * done: an unsigned int is not the same as an int!
- *
- * check_types_match() always evaluates to 1.
- *
- * If your compiler does not support typeof, then the best we can do is fail
- * to compile if the sizes of the types are unequal (a less complete check).
- *
- * Example:
- * // Do subtraction to get to enclosing type, but make sure that
- * // pointer is of correct type for that member.
- * #define container_of(mbr_ptr, encl_type, mbr) \
- * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
- * ((encl_type *) \
- * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
- */
-#if HAVE_TYPEOF
-#define check_type(expr, type) \
- ((typeof(expr) *)0 != (type *)0)
-
-#define check_types_match(expr1, expr2) \
- ((typeof(expr1) *)0 != (typeof(expr2) *)0)
-#else
-#include "build_assert/build_assert.h"
-/* Without typeof, we can only test the sizes. */
-#define check_type(expr, type) \
- EXPR_BUILD_ASSERT(sizeof(expr) == sizeof(type))
-
-#define check_types_match(expr1, expr2) \
- EXPR_BUILD_ASSERT(sizeof(expr1) == sizeof(expr2))
-#endif /* HAVE_TYPEOF */
-
-#endif /* CCAN_CHECK_TYPE_H */
+++ /dev/null
-#include "check_type/check_type.h"
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- check_type(argc, char);
-#endif
- return 0;
-}
+++ /dev/null
-#include "check_type/check_type.h"
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
-#if HAVE_TYPEOF
- check_type(argc, unsigned int);
-#else
- /* This doesn't work without typeof, so just fail */
-#error "Fail without typeof"
-#endif
-#endif
- return 0;
-}
+++ /dev/null
-#include "check_type/check_type.h"
-
-int main(int argc, char *argv[])
-{
- unsigned char x = argc;
-#ifdef FAIL
- check_types_match(argc, x);
-#endif
- return x;
-}
+++ /dev/null
-#include "check_type/check_type.h"
-#include "tap/tap.h"
-
-int main(int argc, char *argv[])
-{
- int x = 0, y = 0;
-
- plan_tests(9);
-
- ok1(check_type(argc, int) == 0);
- ok1(check_type(&argc, int *) == 0);
- ok1(check_types_match(argc, argc) == 0);
- ok1(check_types_match(argc, x) == 0);
- ok1(check_types_match(&argc, &x) == 0);
-
- ok1(check_type(x++, int) == 0);
- ok(x == 0, "check_type does not evaluate expression");
- ok1(check_types_match(x++, y++) == 0);
- ok(x == 0 && y == 0, "check_types_match does not evaluate expressions");
-
- return exit_status();
-}
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * container_of - routine for upcasting
- *
- * It is often convenient to create code where the caller registers a pointer
- * to a generic structure and a callback. The callback might know that the
- * pointer points to within a larger structure, and container_of gives a
- * convenient and fairly type-safe way of returning to the enclosing structure.
- *
- * This idiom is an alternative to providing a void * pointer for every
- * callback.
- *
- * Example:
- * struct info
- * {
- * int my_stuff;
- * struct timer timer;
- * };
- *
- * static void my_timer_callback(struct timer *timer)
- * {
- * struct info *info = container_of(timer, struct info, timer);
- * printf("my_stuff is %u\n", info->my_stuff);
- * }
- *
- * int main()
- * {
- * struct info info = { .my_stuff = 1 };
- *
- * register_timer(&info.timer);
- * ...
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
- printf("check_type\n");
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-#ifndef CCAN_CONTAINER_OF_H
-#define CCAN_CONTAINER_OF_H
-#include <stddef.h>
-
-#include "config.h"
-#include "check_type/check_type.h"
-
-/**
- * container_of - get pointer to enclosing structure
- * @member_ptr: pointer to the structure member
- * @containing_type: the type this member is within
- * @member: the name of this member within the structure.
- *
- * Given a pointer to a member of a structure, this macro does pointer
- * subtraction to return the pointer to the enclosing type.
- *
- * Example:
- * struct info
- * {
- * int some_other_field;
- * struct foo my_foo;
- * };
- *
- * struct info *foo_to_info(struct foo *foop)
- * {
- * return container_of(foo, struct info, my_foo);
- * }
- */
-#define container_of(member_ptr, containing_type, member) \
- ((containing_type *) \
- ((char *)(member_ptr) - offsetof(containing_type, member)) \
- - check_types_match(*(member_ptr), ((containing_type *)0)->member))
-
-
-/**
- * container_of_var - get pointer to enclosing structure using a variable
- * @member_ptr: pointer to the structure member
- * @var: a pointer to a structure of same type as this member is within
- * @member: the name of this member within the structure.
- *
- * Given a pointer to a member of a structure, this macro does pointer
- * subtraction to return the pointer to the enclosing type.
- *
- * Example:
- * struct info
- * {
- * int some_other_field;
- * struct foo my_foo;
- * };
- *
- * struct info *foo_to_info(struct foo *foop)
- * {
- * struct info *i = container_of_var(foo, i, my_foo);
- * return i;
- * }
- */
-#ifdef HAVE_TYPEOF
-#define container_of_var(member_ptr, var, member) \
- container_of(member_ptr, typeof(*var), member)
-#else
-#define container_of_var(member_ptr, var, member) \
- ((void *)((char *)(member_ptr) - offsetof(containing_type, member)))
-#endif
-
-#endif /* CCAN_CONTAINER_OF_H */
+++ /dev/null
-#include "container_of/container_of.h"
-#include <stdlib.h>
-
-struct foo {
- int a;
- char b;
-};
-
-int main(int argc, char *argv[])
-{
- struct foo foo = { .a = 1, .b = 2 };
- int *intp = &foo.a;
- char *p;
-
-#ifdef FAIL
- /* p is a char *, but this gives a struct foo * */
- p = container_of(intp, struct foo, a);
-#else
- p = (char *)intp;
-#endif
- return p == NULL;
-}
+++ /dev/null
-#include "container_of/container_of.h"
-#include <stdlib.h>
-
-struct foo {
- int a;
- char b;
-};
-
-int main(int argc, char *argv[])
-{
- struct foo foo = { .a = 1, .b = 2 }, *foop;
- int *intp = &foo.a;
-
-#ifdef FAIL
- /* b is a char, but intp is an int * */
- foop = container_of(intp, struct foo, b);
-#else
- foop = NULL;
-#endif
- return intp == NULL;
-}
+++ /dev/null
-#include "container_of/container_of.h"
-#include <stdlib.h>
-
-struct foo {
- int a;
- char b;
-};
-
-int main(int argc, char *argv[])
-{
- struct foo foo = { .a = 1, .b = 2 }, *foop;
- int *intp = &foo.a;
-
-#ifdef FAIL
- /* b is a char, but intp is an int * */
- foop = container_of_var(intp, foop, b);
-#else
- foop = NULL;
-#endif
- return intp == NULL;
-}
+++ /dev/null
-#include "container_of/container_of.h"
-#include "tap/tap.h"
-
-struct foo {
- int a;
- char b;
-};
-
-int main(int argc, char *argv[])
-{
- struct foo foo = { .a = 1, .b = 2 };
- int *intp = &foo.a;
- char *charp = &foo.b;
-
- plan_tests(4);
- ok1(container_of(intp, struct foo, a) == &foo);
- ok1(container_of(charp, struct foo, b) == &foo);
- ok1(container_of_var(intp, &foo, a) == &foo);
- ok1(container_of_var(charp, &foo, b) == &foo);
- return exit_status();
-}
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * list - double linked list routines
- *
- * The list header contains routines for manipulating double linked lists.
- * It defines two types: struct list_head used for anchoring lists, and
- * struct list_node which is usually embedded in the structure which is placed
- * in the list.
- *
- * Example:
- * #include <err.h>
- * #include "list/list.h"
- *
- * struct parent {
- * const char *name;
- * struct list_head children;
- * unsigned int num_children;
- * };
- *
- * struct child {
- * const char *name;
- * struct list_node list;
- * };
- *
- * int main(int argc, char *argv[])
- * {
- * struct parent p;
- * struct child *c;
- * unsigned int i;
- *
- * if (argc < 2)
- * errx(1, "Usage: %s parent children...", argv[0]);
- *
- * p.name = argv[1];
- * for (i = 2; i < argc, i++) {
- * c = malloc(sizeof(*c));
- * c->name = argv[i];
- * list_add(&p.children, &c->list);
- * p.num_children++;
- * }
- *
- * printf("%s has %u children:", p.name, p.num_children);
- * list_for_each(&p.children, c, list)
- * printf("%s ", c->name);
- * printf("\n");
- * return 0;
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
- printf("container_of\n");
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include "list/list.h"
-
-struct list_head *list_check(struct list_head *h, const char *abortstr)
-{
- struct list_node *n, *p;
- int count = 0;
-
- if (h->n.next == &h->n) {
- if (h->n.prev != &h->n) {
- if (!abortstr)
- return NULL;
- fprintf(stderr, "%s: prev corrupt in empty %p\n",
- abortstr, h);
- abort();
- }
- return h;
- }
-
- for (p = &h->n, n = h->n.next; n != &h->n; p = n, n = n->next) {
- count++;
- if (n->prev != p) {
- if (!abortstr)
- return NULL;
- fprintf(stderr,
- "%s: prev corrupt in node %p (%u) of %p\n",
- abortstr, n, count, h);
- abort();
- }
- }
- return h;
-}
+++ /dev/null
-#ifndef CCAN_LIST_H
-#define CCAN_LIST_H
-#include <stdbool.h>
-#include "container_of/container_of.h"
-
-/**
- * struct list_node - an entry in a doubly-linked list
- * @next: next entry (self if empty)
- * @prev: previous entry (self if empty)
- *
- * This is used as an entry in a linked list.
- * Example:
- * struct child {
- * const char *name;
- * // Linked list of all us children.
- * struct list_node list;
- * };
- */
-struct list_node
-{
- struct list_node *next, *prev;
-};
-
-/**
- * struct list_head - the head of a doubly-linked list
- * @h: the list_head (containing next and prev pointers)
- *
- * This is used as the head of a linked list.
- * Example:
- * struct parent {
- * const char *name;
- * struct list_head children;
- * unsigned int num_children;
- * };
- */
-struct list_head
-{
- struct list_node n;
-};
-
-/**
- * list_check - check a list for consistency
- * @h: the list_head
- * @abortstr: the location to print on aborting, or NULL.
- *
- * Because list_nodes have redundant information, consistency checking between
- * the back and forward links can be done. This is useful as a debugging check.
- * If @abortstr is non-NULL, that will be printed in a diagnostic if the list
- * is inconsistent, and the function will abort.
- *
- * Returns the list head if the list is consistent, NULL if not (it
- * can never return NULL if @abortstr is set).
- *
- * Example:
- * static void dump_parent(struct parent *p)
- * {
- * struct child *c;
- *
- * printf("%s (%u children):\n", p->name, parent->num_children);
- * list_check(&p->children, "bad child list");
- * list_for_each(&p->children, c, list)
- * printf(" -> %s\n", c->name);
- * }
- */
-struct list_head *list_check(struct list_head *h, const char *abortstr);
-
-#ifdef CCAN_LIST_DEBUG
-#define debug_list(h) list_check((h), __func__)
-#else
-#define debug_list(h) (h)
-#endif
-
-/**
- * list_head_init - initialize a list_head
- * @h: the list_head to set to the empty list
- *
- * Example:
- * list_head_init(&parent->children);
- * parent->num_children = 0;
- */
-static inline void list_head_init(struct list_head *h)
-{
- h->n.next = h->n.prev = &h->n;
-}
-
-/**
- * LIST_HEAD - define and initalized empty list_head
- * @name: the name of the list.
- *
- * The LIST_HEAD macro defines a list_head and initializes it to an empty
- * list. It can be prepended by "static" to define a static list_head.
- *
- * Example:
- * // Header:
- * extern struct list_head my_list;
- *
- * // C file:
- * LIST_HEAD(my_list);
- */
-#define LIST_HEAD(name) \
- struct list_head name = { { &name.n, &name.n } }
-
-/**
- * list_add - add an entry at the start of a linked list.
- * @h: the list_head to add the node to
- * @n: the list_node to add to the list.
- *
- * The list_node does not need to be initialized; it will be overwritten.
- * Example:
- * list_add(&parent->children, &child->list);
- * parent->num_children++;
- */
-static inline void list_add(struct list_head *h, struct list_node *n)
-{
- n->next = h->n.next;
- n->prev = &h->n;
- h->n.next->prev = n;
- h->n.next = n;
- (void)debug_list(h);
-}
-
-/**
- * list_add_tail - add an entry at the end of a linked list.
- * @h: the list_head to add the node to
- * @n: the list_node to add to the list.
- *
- * The list_node does not need to be initialized; it will be overwritten.
- * Example:
- * list_add_tail(&parent->children, &child->list);
- * parent->num_children++;
- */
-static inline void list_add_tail(struct list_head *h, struct list_node *n)
-{
- n->next = &h->n;
- n->prev = h->n.prev;
- h->n.prev->next = n;
- h->n.prev = n;
- (void)debug_list(h);
-}
-
-/**
- * list_del - delete an entry from a linked list.
- * @n: the list_node to delete from the list.
- *
- * Example:
- * list_del(&child->list);
- * parent->num_children--;
- */
-static inline void list_del(struct list_node *n)
-{
- n->next->prev = n->prev;
- n->prev->next = n->next;
- (void)debug_list(n->next);
-#ifdef CCAN_LIST_DEBUG
- /* Catch use-after-del. */
- n->next = n->prev = NULL;
-#endif
-}
-
-/**
- * list_empty - is a list empty?
- * @h: the list_head
- *
- * If the list is empty, returns true.
- *
- * Example:
- * assert(list_empty(&parent->children) == (parent->num_children == 0));
- */
-static inline bool list_empty(struct list_head *h)
-{
- (void)debug_list(h);
- return h->n.next == &h->n;
-}
-
-/**
- * list_entry - convert a list_node back into the structure containing it.
- * @n: the list_node
- * @type: the type of the entry
- * @member: the list_node member of the type
- *
- * Example:
- * struct child *c;
- * // First list entry is children.next; convert back to child.
- * c = list_entry(parent->children.next, struct child, list);
- */
-#define list_entry(n, type, member) container_of(n, type, member)
-
-/**
- * list_top - get the first entry in a list
- * @h: the list_head
- * @type: the type of the entry
- * @member: the list_node member of the type
- *
- * If the list is empty, returns NULL.
- *
- * Example:
- * struct child *first;
- * first = list_top(&parent->children, struct child, list);
- */
-#define list_top(h, type, member) \
- list_entry(_list_top(h), type, member)
-
-static inline struct list_node *_list_top(struct list_head *h)
-{
- (void)debug_list(h);
- if (list_empty(h))
- return NULL;
- return h->n.next;
-}
-
-/**
- * list_for_each - iterate through a list.
- * @h: the list_head
- * @i: the structure containing the list_node
- * @member: the list_node member of the structure
- *
- * This is a convenient wrapper to iterate @i over the entire list. It's
- * a for loop, so you can break and continue as normal.
- *
- * Example:
- * struct child *c;
- * list_for_each(&parent->children, c, list)
- * printf("Name: %s\n", c->name);
- */
-#define list_for_each(h, i, member) \
- for (i = container_of_var(debug_list(h)->n.next, i, member); \
- &i->member != &(h)->n; \
- i = container_of_var(i->member.next, i, member))
-
-/**
- * list_for_each_safe - iterate through a list, maybe during deletion
- * @h: the list_head
- * @i: the structure containing the list_node
- * @nxt: the structure containing the list_node
- * @member: the list_node member of the structure
- *
- * This is a convenient wrapper to iterate @i over the entire list. It's
- * a for loop, so you can break and continue as normal. The extra variable
- * @nxt is used to hold the next element, so you can delete @i from the list.
- *
- * Example:
- * struct child *c, *n;
- * list_for_each_safe(&parent->children, c, n, list) {
- * list_del(&c->list);
- * parent->num_children--;
- * }
- */
-#define list_for_each_safe(h, i, nxt, member) \
- for (i = container_of_var(debug_list(h)->n.next, i, member), \
- nxt = container_of_var(i->member.next, i, member); \
- &i->member != &(h)->n; \
- i = nxt, nxt = container_of_var(i->member.next, i, member))
-#endif /* CCAN_LIST_H */
+++ /dev/null
-#include "list/list.h"
-#include "tap/tap.h"
-#include "list/list.c"
-
-struct parent {
- const char *name;
- struct list_head children;
- unsigned int num_children;
-};
-
-struct child {
- const char *name;
- struct list_node list;
-};
-
-static LIST_HEAD(static_list);
-
-int main(int argc, char *argv[])
-{
- struct parent parent;
- struct child c1, c2, c3, *c, *n;
- unsigned int i;
-
- plan_tests(41);
- /* Test LIST_HEAD, list_empty and check_list */
- ok1(list_empty(&static_list));
- ok1(list_check(&static_list, NULL));
-
- parent.num_children = 0;
- list_head_init(&parent.children);
- /* Test list_head_init */
- ok1(list_empty(&parent.children));
- ok1(list_check(&parent.children, NULL));
-
- c2.name = "c2";
- list_add(&parent.children, &c2.list);
- /* Test list_add and !list_empty. */
- ok1(!list_empty(&parent.children));
- ok1(c2.list.next == &parent.children.n);
- ok1(c2.list.prev == &parent.children.n);
- ok1(parent.children.n.next == &c2.list);
- ok1(parent.children.n.prev == &c2.list);
- /* Test list_check */
- ok1(list_check(&parent.children, NULL));
-
- c1.name = "c1";
- list_add(&parent.children, &c1.list);
- /* Test list_add and !list_empty. */
- ok1(!list_empty(&parent.children));
- ok1(c2.list.next == &parent.children.n);
- ok1(c2.list.prev == &c1.list);
- ok1(parent.children.n.next == &c1.list);
- ok1(parent.children.n.prev == &c2.list);
- ok1(c1.list.next == &c2.list);
- ok1(c1.list.prev == &parent.children.n);
- /* Test list_check */
- ok1(list_check(&parent.children, NULL));
-
- c3.name = "c3";
- list_add_tail(&parent.children, &c3.list);
- /* Test list_add_tail and !list_empty. */
- ok1(!list_empty(&parent.children));
- ok1(parent.children.n.next == &c1.list);
- ok1(parent.children.n.prev == &c3.list);
- ok1(c1.list.next == &c2.list);
- ok1(c1.list.prev == &parent.children.n);
- ok1(c2.list.next == &c3.list);
- ok1(c2.list.prev == &c1.list);
- ok1(c3.list.next == &parent.children.n);
- ok1(c3.list.prev == &c2.list);
- /* Test list_check */
- ok1(list_check(&parent.children, NULL));
-
- /* Test list_top */
- ok1(list_top(&parent.children, struct child, list) == &c1);
-
- /* Test list_for_each. */
- i = 0;
- list_for_each(&parent.children, c, list) {
- switch (i++) {
- case 0:
- ok1(c == &c1);
- break;
- case 1:
- ok1(c == &c2);
- break;
- case 2:
- ok1(c == &c3);
- break;
- }
- if (i > 2)
- break;
- }
- ok1(i == 3);
-
- /* Test list_for_each_safe and list_del. */
- i = 0;
- list_for_each_safe(&parent.children, c, n, list) {
- switch (i++) {
- case 0:
- ok1(c == &c1);
- break;
- case 1:
- ok1(c == &c2);
- break;
- case 2:
- ok1(c == &c3);
- break;
- }
- list_del(&c->list);
- ok1(list_check(&parent.children, NULL));
- if (i > 2)
- break;
- }
- ok1(i == 3);
- ok1(list_empty(&parent.children));
- return exit_status();
-}
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * noerr - routines for cleaning up without blatting errno
- *
- * It is a good idea to follow the standard C convention of setting errno in
- * your own helper functions. Unfortunately, care must be taken in the error
- * paths as most standard functions can (and do) overwrite errno, even if they
- * succeed.
- *
- * Example:
- * #include <sys/types.h>
- * #include <sys/stat.h>
- * #include <fcntl.h>
- *
- * bool write_string_to_file(const char *file, const char *string)
- * {
- * int ret, fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0600);
- * if (fd < 0)
- * return false;
- * ret = write(fd, string, strlen(string));
- * if (ret < 0) {
- * // Preserve errno from write above.
- * close_noerr(fd);
- * unlink_noerr(file);
- * return false;
- * }
- * if (close(fd) != 0) {
- * // Again, preserve errno.
- * unlink_noerr(file);
- * return false;
- * }
- * // A short write means out of space.
- * if (ret < strlen(string)) {
- * unlink(file);
- * errno = ENOSPC;
- * return false;
- * }
- * return true;
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0)
- /* Nothing. */
- return 0;
-
- return 1;
-}
+++ /dev/null
-#include "noerr.h"
-#include <unistd.h>
-#include <errno.h>
-
-int close_noerr(int fd)
-{
- int saved_errno = errno, ret;
-
- if (close(fd) != 0)
- ret = errno;
- else
- ret = 0;
-
- errno = saved_errno;
- return ret;
-}
-
-int unlink_noerr(const char *pathname)
-{
- int saved_errno = errno, ret;
-
- if (unlink(pathname) != 0)
- ret = errno;
- else
- ret = 0;
-
- errno = saved_errno;
- return ret;
-}
+++ /dev/null
-#ifndef NOERR_H
-#define NOERR_H
-
-/**
- * close_noerr - close without stomping errno.
- * @fd: the file descriptor to close.
- *
- * errno is saved and restored across the call to close: if an error occurs,
- * the resulting (non-zero) errno is returned.
- */
-int close_noerr(int fd);
-
-/**
- * unlink_noerr - unlink a file without stomping errno.
- * @pathname: the path to unlink.
- *
- * errno is saved and restored across the call to unlink: if an error occurs,
- * the resulting (non-zero) errno is returned.
- */
-int unlink_noerr(const char *pathname);
-
-#endif /* NOERR_H */
+++ /dev/null
-#include "noerr/noerr.h"
-#include "tap/tap.h"
-#include "noerr/noerr.c"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <assert.h>
-
-int main(int argc, char *argv[])
-{
- /* tempnam(3) is generally a bad idea, but OK here. */
- char *name = tempnam(NULL, "noerr");
- int fd;
-
- plan_tests(12);
- /* Should fail to unlink. */
- ok1(unlink(name) != 0);
- ok1(errno == ENOENT);
-
- /* This one should not set errno. */
- errno = 100;
- ok1(unlink_noerr(name) == ENOENT);
- ok1(errno == 100);
-
- /* Should fail to close. */
- ok1(close(-1) != 0);
- ok1(errno == EBADF);
-
- /* This one should not set errno. */
- errno = 100;
- ok1(close_noerr(-1) == EBADF);
- ok1(errno == 100);
-
- /* Test successful close/unlink doesn't hit errno either. */
- fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600);
- assert(fd >= 0);
-
- errno = 100;
- ok1(close_noerr(fd) == 0);
- ok1(errno == 100);
-
- errno = 100;
- ok1(unlink_noerr(name) == 0);
- ok1(errno == 100);
-
- return exit_status();
-}
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * string - string helper routines
- *
- * This is a grab bag of modules for string comparisons, designed to enhance
- * the standard string.h.
- *
- * Example:
- * #include "ccan/string.h"
- *
- * int main(int argc, char *argv[])
- * {
- * if (argv[1] && streq(argv[1], "--verbose"))
- * printf("verbose set\n");
- * if (argv[1] && strstarts(argv[1], "--"))
- * printf("Some option set\n");
- * if (argv[1] && strends(argv[1], "cow-powers"))
- * printf("Magic option set\n");
- * return 0;
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0)
- /* Nothing. */
- return 0;
-
- return 1;
-}
+++ /dev/null
-#ifndef CCAN_STRING_H
-#define CCAN_STRING_H
-#include <string.h>
-#include <stdbool.h>
-
-/**
- * streq - Are two strings equal?
- * @a: first string
- * @b: first string
- *
- * This macro is arguably more readable than "!strcmp(a, b)".
- *
- * Example:
- * if (streq(str, ""))
- * printf("String is empty!\n");
- */
-#define streq(a,b) (strcmp((a),(b)) == 0)
-
-/**
- * strstarts - Does this string start with this prefix?
- * @str: string to test
- * @prefix: prefix to look for at start of str
- *
- * Example:
- * if (strstarts(str, "foo"))
- * printf("String %s begins with 'foo'!\n", str);
- */
-#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
-
-/**
- * strends - Does this string end with this postfix?
- * @str: string to test
- * @postfix: postfix to look for at end of str
- *
- * Example:
- * if (strends(str, "foo"))
- * printf("String %s end with 'foo'!\n", str);
- */
-static inline bool strends(const char *str, const char *postfix)
-{
- if (strlen(str) < strlen(postfix))
- return false;
-
- return streq(str + strlen(str) - strlen(postfix), postfix);
-}
-#endif /* CCAN_STRING_H */
+++ /dev/null
-#include <stdlib.h>
-#include <stdio.h>
-#include "string/string.h"
-#include "tap/tap.h"
-
-/* FIXME: ccanize */
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
-
-static char *substrings[] = { "far", "bar", "baz", "b", "ba", "z", "ar" };
-
-static char *strdup_rev(const char *s)
-{
- char *ret = strdup(s);
- unsigned int i;
-
- for (i = 0; i < strlen(s); i++)
- ret[i] = s[strlen(s) - i - 1];
- return ret;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i, j, n;
- char *strings[ARRAY_SIZE(substrings) * ARRAY_SIZE(substrings)];
-
- n = 0;
- for (i = 0; i < ARRAY_SIZE(substrings); i++) {
- for (j = 0; j < ARRAY_SIZE(substrings); j++) {
- strings[n] = malloc(strlen(substrings[i])
- + strlen(substrings[j]) + 1);
- sprintf(strings[n++], "%s%s",
- substrings[i], substrings[j]);
- }
- }
-
- plan_tests(n * n * 5);
- for (i = 0; i < n; i++) {
- for (j = 0; j < n; j++) {
- unsigned int k, identical = 0;
- char *reva, *revb;
-
- /* Find first difference. */
- for (k = 0; strings[i][k]==strings[j][k]; k++) {
- if (k == strlen(strings[i])) {
- identical = 1;
- break;
- }
- }
-
- if (identical)
- ok1(streq(strings[i], strings[j]));
- else
- ok1(!streq(strings[i], strings[j]));
-
- /* Postfix test should be equivalent to prefix
- * test on reversed string. */
- reva = strdup_rev(strings[i]);
- revb = strdup_rev(strings[j]);
-
- if (!strings[i][k]) {
- ok1(strstarts(strings[j], strings[i]));
- ok1(strends(revb, reva));
- } else {
- ok1(!strstarts(strings[j], strings[i]));
- ok1(!strends(revb, reva));
- }
- if (!strings[j][k]) {
- ok1(strstarts(strings[i], strings[j]));
- ok1(strends(reva, revb));
- } else {
- ok1(!strstarts(strings[i], strings[j]));
- ok1(!strends(reva, revb));
- }
- }
- }
- return exit_status();
-}
+++ /dev/null
-- Remove talloc.h cruft
-- Restore errno around (successful) talloc_free.
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * talloc - tree allocator routines
- *
- * Talloc is a hierarchical memory pool system with destructors: you keep your
- * objects in heirarchies reflecting their lifetime. Every pointer returned
- * from talloc() is itself a valid talloc context, from which other talloc()s
- * can be attached. This means you can do this:
- *
- * struct foo *X = talloc(mem_ctx, struct foo);
- * X->name = talloc_strdup(X, "foo");
- *
- * and the pointer X->name would be a "child" of the talloc context "X" which
- * is itself a child of mem_ctx. So if you do talloc_free(mem_ctx) then it is
- * all destroyed, whereas if you do talloc_free(X) then just X and X->name are
- * destroyed, and if you do talloc_free(X->name) then just the name element of
- * X is destroyed.
- *
- * If you think about this, then what this effectively gives you is an n-ary
- * tree, where you can free any part of the tree with talloc_free().
- *
- * Talloc has been measured with a time overhead of around 4% over glibc
- * malloc, and 48/80 bytes per allocation (32/64 bit).
- *
- * This version is based on svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc revision 23158.
- *
- * Example:
- * #include <stdio.h>
- * #include <stdarg.h>
- * #include <err.h>
- * #include "talloc/talloc.h"
- *
- * // A structure containing a popened comman.
- * struct command
- * {
- * FILE *f;
- * const char *command;
- * };
- *
- * // When struct command is freed, we also want to pclose pipe.
- * static int close_cmd(struct command *cmd)
- * {
- * pclose(cmd->f);
- * // 0 means "we succeeded, continue freeing"
- * return 0;
- * }
- *
- * // This function opens a writable pipe to the given command.
- * struct command *open_output_cmd(const void *ctx, char *fmt, ...)
- * {
- * va_list ap;
- * struct command *cmd = talloc(ctx, struct command);
- *
- * if (!cmd)
- * return NULL;
- *
- * va_start(ap, fmt);
- * cmd->command = talloc_vasprintf(cmd, fmt, ap);
- * va_end(ap);
- * if (!cmd->command) {
- * talloc_free(cmd);
- * return NULL;
- * }
- *
- * cmd->f = popen(cmd->command, "w");
- * if (!cmd->f) {
- * talloc_free(cmd);
- * return NULL;
- * }
- * talloc_set_destructor(cmd, close_cmd);
- * return cmd;
- * }
- *
- * int main(int argc, char *argv[])
- * {
- * struct command *cmd;
- *
- * if (argc != 2)
- * errx(1, "Usage: %s <command>\n");
- *
- * cmd = open_output_cmd(NULL, "%s hello", argv[1]);
- * if (!cmd)
- * err(1, "Running '%s hello'", argv[1]);
- * fprintf(cmd->f, "This is a test\n");
- * talloc_free(cmd);
- * return 0;
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
- printf("typesafe_cb\n");
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<refentry>
- <refmeta>
- <refentrytitle>talloc</refentrytitle>
- <manvolnum>3</manvolnum>
- </refmeta>
- <refnamediv>
- <refname>talloc</refname>
-<refpurpose>hierarchical reference counted memory pool system with destructors</refpurpose>
- </refnamediv>
- <refsynopsisdiv>
-<synopsis>#include <talloc/talloc.h></synopsis>
- </refsynopsisdiv>
- <refsect1><title>DESCRIPTION</title>
- <para>
- If you are used to talloc from Samba3 then please read this
- carefully, as talloc has changed a lot.
- </para>
- <para>
- The new talloc is a hierarchical, reference counted memory pool
- system with destructors. Quite a mouthful really, but not too bad
- once you get used to it.
- </para>
- <para>
- Perhaps the biggest change from Samba3 is that there is no
- distinction between a "talloc context" and a "talloc pointer". Any
- pointer returned from talloc() is itself a valid talloc context.
- This means you can do this:
- </para>
- <programlisting>
- struct foo *X = talloc(mem_ctx, struct foo);
- X->name = talloc_strdup(X, "foo");
- </programlisting>
- <para>
- and the pointer <literal role="code">X->name</literal>
- would be a "child" of the talloc context <literal
- role="code">X</literal> which is itself a child of
- <literal role="code">mem_ctx</literal>. So if you do
- <literal role="code">talloc_free(mem_ctx)</literal> then
- it is all destroyed, whereas if you do <literal
- role="code">talloc_free(X)</literal> then just <literal
- role="code">X</literal> and <literal
- role="code">X->name</literal> are destroyed, and if
- you do <literal
- role="code">talloc_free(X->name)</literal> then just
- the name element of <literal role="code">X</literal> is
- destroyed.
- </para>
- <para>
- If you think about this, then what this effectively gives you is an
- n-ary tree, where you can free any part of the tree with
- talloc_free().
- </para>
- <para>
- If you find this confusing, then I suggest you run the <literal
- role="code">testsuite</literal> program to watch talloc
- in action. You may also like to add your own tests to <literal
- role="code">testsuite.c</literal> to clarify how some
- particular situation is handled.
- </para>
- </refsect1>
- <refsect1><title>TALLOC API</title>
- <para>
- The following is a complete guide to the talloc API. Read it all at
- least twice.
- </para>
- <refsect2><title>(type *)talloc(const void *ctx, type);</title>
- <para>
- The talloc() macro is the core of the talloc library. It takes a
- memory <emphasis role="italic">ctx</emphasis> and a <emphasis
- role="italic">type</emphasis>, and returns a pointer to a new
- area of memory of the given <emphasis
- role="italic">type</emphasis>.
- </para>
- <para>
- The returned pointer is itself a talloc context, so you can use
- it as the <emphasis role="italic">ctx</emphasis> argument to more
- calls to talloc() if you wish.
- </para>
- <para>
- The returned pointer is a "child" of the supplied context. This
- means that if you talloc_free() the <emphasis
- role="italic">ctx</emphasis> then the new child disappears as
- well. Alternatively you can free just the child.
- </para>
- <para>
- The <emphasis role="italic">ctx</emphasis> argument to talloc()
- can be NULL, in which case a new top level context is created.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_size(const void *ctx, size_t size);</title>
- <para>
- The function talloc_size() should be used when you don't have a
- convenient type to pass to talloc(). Unlike talloc(), it is not
- type safe (as it returns a void *), so you are on your own for
- type checking.
- </para>
- </refsect2>
- <refsect2><title>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</title>
- <para>
- The talloc_ptrtype() macro should be used when you have a pointer and
- want to allocate memory to point at with this pointer. When compiling
- with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
- and talloc_get_name() will return the current location in the source file.
- and not the type.
- </para>
- </refsect2>
- <refsect2><title>int talloc_free(void *ptr);</title>
- <para>
- The talloc_free() function frees a piece of talloc memory, and
- all its children. You can call talloc_free() on any pointer
- returned by talloc().
- </para>
- <para>
- The return value of talloc_free() indicates success or failure,
- with 0 returned for success and -1 for failure. The only
- possible failure condition is if <emphasis
- role="italic">ptr</emphasis> had a destructor attached to it and
- the destructor returned -1. See <link
- linkend="talloc_set_destructor"><quote>talloc_set_destructor()</quote></link>
- for details on destructors.
- </para>
- <para>
- If this pointer has an additional parent when talloc_free() is
- called then the memory is not actually released, but instead the
- most recently established parent is destroyed. See <link
- linkend="talloc_reference"><quote>talloc_reference()</quote></link>
- for details on establishing additional parents.
- </para>
- <para>
- For more control on which parent is removed, see <link
- linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
- </para>
- <para>
- talloc_free() operates recursively on its children.
- </para>
- </refsect2>
- <refsect2 id="talloc_reference"><title>void *talloc_reference(const void *ctx, const void *ptr);</title>
- <para>
- The talloc_reference() function makes <emphasis
- role="italic">ctx</emphasis> an additional parent of <emphasis
- role="italic">ptr</emphasis>.
- </para>
- <para>
- The return value of talloc_reference() is always the original
- pointer <emphasis role="italic">ptr</emphasis>, unless talloc ran
- out of memory in creating the reference in which case it will
- return NULL (each additional reference consumes around 48 bytes
- of memory on intel x86 platforms).
- </para>
- <para>
- If <emphasis role="italic">ptr</emphasis> is NULL, then the
- function is a no-op, and simply returns NULL.
- </para>
- <para>
- After creating a reference you can free it in one of the
- following ways:
- </para>
- <para>
- <itemizedlist>
- <listitem>
- <para>
- you can talloc_free() any parent of the original pointer.
- That will reduce the number of parents of this pointer by 1,
- and will cause this pointer to be freed if it runs out of
- parents.
- </para>
- </listitem>
- <listitem>
- <para>
- you can talloc_free() the pointer itself. That will destroy
- the most recently established parent to the pointer and leave
- the pointer as a child of its current parent.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- For more control on which parent to remove, see <link
- linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
- </para>
- </refsect2>
- <refsect2 id="talloc_unlink"><title>int talloc_unlink(const void *ctx, const void *ptr);</title>
- <para>
- The talloc_unlink() function removes a specific parent from
- <emphasis role="italic">ptr</emphasis>. The <emphasis
- role="italic">ctx</emphasis> passed must either be a context used
- in talloc_reference() with this pointer, or must be a direct
- parent of ptr.
- </para>
- <para>
- Note that if the parent has already been removed using
- talloc_free() then this function will fail and will return -1.
- Likewise, if <emphasis role="italic">ptr</emphasis> is NULL, then
- the function will make no modifications and return -1.
- </para>
- <para>
- Usually you can just use talloc_free() instead of
- talloc_unlink(), but sometimes it is useful to have the
- additional control on which parent is removed.
- </para>
- </refsect2>
- <refsect2 id="talloc_set_destructor"><title>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</title>
- <para>
- The function talloc_set_destructor() sets the <emphasis
- role="italic">destructor</emphasis> for the pointer <emphasis
- role="italic">ptr</emphasis>. A <emphasis
- role="italic">destructor</emphasis> is a function that is called
- when the memory used by a pointer is about to be released. The
- destructor receives <emphasis role="italic">ptr</emphasis> as an
- argument, and should return 0 for success and -1 for failure.
- </para>
- <para>
- The <emphasis role="italic">destructor</emphasis> can do anything
- it wants to, including freeing other pieces of memory. A common
- use for destructors is to clean up operating system resources
- (such as open file descriptors) contained in the structure the
- destructor is placed on.
- </para>
- <para>
- You can only place one destructor on a pointer. If you need more
- than one destructor then you can create a zero-length child of
- the pointer and place an additional destructor on that.
- </para>
- <para>
- To remove a destructor call talloc_set_destructor() with NULL for
- the destructor.
- </para>
- <para>
- If your destructor attempts to talloc_free() the pointer that it
- is the destructor for then talloc_free() will return -1 and the
- free will be ignored. This would be a pointless operation
- anyway, as the destructor is only called when the memory is just
- about to go away.
- </para>
- </refsect2>
- <refsect2><title>int talloc_increase_ref_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- The talloc_increase_ref_count(<emphasis
- role="italic">ptr</emphasis>) function is exactly equivalent to:
- </para>
- <programlisting>talloc_reference(NULL, ptr);</programlisting>
- <para>
- You can use either syntax, depending on which you think is
- clearer in your code.
- </para>
- <para>
- It returns 0 on success and -1 on failure.
- </para>
- </refsect2>
- <refsect2><title>size_t talloc_reference_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- Return the number of references to the pointer.
- </para>
- </refsect2>
- <refsect2 id="talloc_set_name"><title>void talloc_set_name(const void *ptr, const char *fmt, ...);</title>
- <para>
- Each talloc pointer has a "name". The name is used principally
- for debugging purposes, although it is also possible to set and
- get the name on a pointer in as a way of "marking" pointers in
- your code.
- </para>
- <para>
- The main use for names on pointer is for "talloc reports". See
- <link
- linkend="talloc_report"><quote>talloc_report_depth_cb()</quote></link>,
- <link
- linkend="talloc_report"><quote>talloc_report_depth_file()</quote></link>,
- <link
- linkend="talloc_report"><quote>talloc_report()</quote></link>
- <link
- linkend="talloc_report"><quote>talloc_report()</quote></link>
- and <link
- linkend="talloc_report_full"><quote>talloc_report_full()</quote></link>
- for details. Also see <link
- linkend="talloc_enable_leak_report"><quote>talloc_enable_leak_report()</quote></link>
- and <link
- linkend="talloc_enable_leak_report_full"><quote>talloc_enable_leak_report_full()</quote></link>.
- </para>
- <para>
- The talloc_set_name() function allocates memory as a child of the
- pointer. It is logically equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</programlisting>
- <para>
- Note that multiple calls to talloc_set_name() will allocate more
- memory without releasing the name. All of the memory is released
- when the ptr is freed using talloc_free().
- </para>
- </refsect2>
- <refsect2><title>void talloc_set_name_const(const void *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
- <para>
- The function talloc_set_name_const() is just like
- talloc_set_name(), but it takes a string constant, and is much
- faster. It is extensively used by the "auto naming" macros, such
- as talloc_p().
- </para>
- <para>
- This function does not allocate any memory. It just copies the
- supplied pointer into the internal representation of the talloc
- ptr. This means you must not pass a <emphasis
- role="italic">name</emphasis> pointer to memory that will
- disappear before <emphasis role="italic">ptr</emphasis> is freed
- with talloc_free().
- </para>
- </refsect2>
- <refsect2><title>void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
- <para>
- The talloc_named() function creates a named talloc pointer. It
- is equivalent to:
- </para>
- <programlisting>ptr = talloc_size(ctx, size);
-talloc_set_name(ptr, fmt, ....);</programlisting>
- </refsect2>
- <refsect2><title>void *talloc_named_const(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
- <para>
- This is equivalent to:
- </para>
- <programlisting>ptr = talloc_size(ctx, size);
-talloc_set_name_const(ptr, name);</programlisting>
- </refsect2>
- <refsect2><title>const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- This returns the current name for the given talloc pointer,
- <emphasis role="italic">ptr</emphasis>. See <link
- linkend="talloc_set_name"><quote>talloc_set_name()</quote></link>
- for details.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
- <para>
- This function creates a zero length named talloc context as a top
- level context. It is equivalent to:
- </para>
- <programlisting>talloc_named(NULL, 0, fmt, ...);</programlisting>
- </refsect2>
- <refsect2><title>void *talloc_new(void *<emphasis role="italic">ctx</emphasis>);</title>
- <para>
- This is a utility macro that creates a new memory context hanging
- off an exiting context, automatically naming it "talloc_new:
- __location__" where __location__ is the source line it is called
- from. It is particularly useful for creating a new temporary
- working context.
- </para>
- </refsect2>
- <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_realloc(const void *<emphasis role="italic">ctx</emphasis>, void *<emphasis role="italic">ptr</emphasis>, <emphasis role="italic">type</emphasis>, <emphasis role="italic">count</emphasis>);</title>
- <para>
- The talloc_realloc() macro changes the size of a talloc pointer.
- It has the following equivalences:
- </para>
- <programlisting>talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
-talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr);</programlisting>
- <para>
- The <emphasis role="italic">ctx</emphasis> argument is only used
- if <emphasis role="italic">ptr</emphasis> is not NULL, otherwise
- it is ignored.
- </para>
- <para>
- talloc_realloc() returns the new pointer, or NULL on failure.
- The call will fail either due to a lack of memory, or because the
- pointer has more than one parent (see <link
- linkend="talloc_reference"><quote>talloc_reference()</quote></link>).
- </para>
- </refsect2>
- <refsect2><title>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</title>
- <para>
- the talloc_realloc_size() function is useful when the type is not
- known so the type-safe talloc_realloc() cannot be used.
- </para>
- </refsect2>
- <refsect2><title>TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- The talloc_steal() function changes the parent context of a
- talloc pointer. It is typically used when the context that the
- pointer is currently a child of is going to be freed and you wish
- to keep the memory for a longer time.
- </para>
- <para>
- The talloc_steal() function returns the pointer that you pass it.
- It does not have any failure modes.
- </para>
- <para>
- NOTE: It is possible to produce loops in the parent/child
- relationship if you are not careful with talloc_steal(). No
- guarantees are provided as to your sanity or the safety of your
- data if you do this.
- </para>
- </refsect2>
- <refsect2><title>TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- The talloc_move() function is a wrapper around
- talloc_steal() which zeros the source pointer after the
- move. This avoids a potential source of bugs where a
- programmer leaves a pointer in two structures, and uses the
- pointer from the old structure after it has been moved to a
- new one.
- </para>
- </refsect2>
- <refsect2><title>size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- The talloc_total_size() function returns the total size in bytes
- used by this pointer and all child pointers. Mostly useful for
- debugging.
- </para>
- <para>
- Passing NULL is allowed, but it will only give a meaningful
- result if talloc_enable_leak_report() or
- talloc_enable_leak_report_full() has been called.
- </para>
- </refsect2>
- <refsect2><title>size_t talloc_total_blocks(const void *<emphasis role="italic">ptr</emphasis>);</title>
- <para>
- The talloc_total_blocks() function returns the total memory block
- count used by this pointer and all child pointers. Mostly useful
- for debugging.
- </para>
- <para>
- Passing NULL is allowed, but it will only give a meaningful
- result if talloc_enable_leak_report() or
- talloc_enable_leak_report_full() has been called.
- </para>
- </refsect2>
- <refsect2 id="talloc_report"><title>void talloc_report(const void *ptr, FILE *f);</title>
- <para>
- The talloc_report() function prints a summary report of all
- memory used by <emphasis role="italic">ptr</emphasis>. One line
- of report is printed for each immediate child of ptr, showing the
- total memory and number of blocks used by that child.
- </para>
- <para>
- You can pass NULL for the pointer, in which case a report is
- printed for the top level memory context, but only if
- talloc_enable_leak_report() or talloc_enable_leak_report_full()
- has been called.
- </para>
- </refsect2>
- <refsect2 id="talloc_report_full"><title>void talloc_report_full(const void *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>);</title>
- <para>
- This provides a more detailed report than talloc_report(). It
- will recursively print the entire tree of memory referenced by
- the pointer. References in the tree are shown by giving the name
- of the pointer that is referenced.
- </para>
- <para>
- You can pass NULL for the pointer, in which case a report is
- printed for the top level memory context, but only if
- talloc_enable_leak_report() or talloc_enable_leak_report_full()
- has been called.
- </para>
- </refsect2>
- <refsect2 id="talloc_report_depth_cb">
- <funcsynopsis><funcprototype>
- <funcdef>void <function>talloc_report_depth_cb</function></funcdef>
- <paramdef><parameter>const void *ptr</parameter></paramdef>
- <paramdef><parameter>int depth</parameter></paramdef>
- <paramdef><parameter>int max_depth</parameter></paramdef>
- <paramdef><parameter>void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</parameter></paramdef>
- <paramdef><parameter>void *priv</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <para>
- This provides a more flexible reports than talloc_report(). It
- will recursively call the callback for the entire tree of memory
- referenced by the pointer. References in the tree are passed with
- <emphasis role="italic">is_ref = 1</emphasis> and the pointer that is referenced.
- </para>
- <para>
- You can pass NULL for the pointer, in which case a report is
- printed for the top level memory context, but only if
- talloc_enable_leak_report() or talloc_enable_leak_report_full()
- has been called.
- </para>
- <para>
- The recursion is stopped when depth >= max_depth.
- max_depth = -1 means only stop at leaf nodes.
- </para>
- </refsect2>
- <refsect2 id="talloc_report_depth_file">
- <funcsynopsis><funcprototype>
- <funcdef>void <function>talloc_report_depth_file</function></funcdef>
- <paramdef><parameter>const void *ptr</parameter></paramdef>
- <paramdef><parameter>int depth</parameter></paramdef>
- <paramdef><parameter>int max_depth</parameter></paramdef>
- <paramdef><parameter>FILE *f</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <para>
- This provides a more flexible reports than talloc_report(). It
- will let you specify the depth and max_depth.
- </para>
- </refsect2>
- <refsect2 id="talloc_enable_leak_report"><title>void talloc_enable_leak_report(void);</title>
- <para>
- This enables calling of talloc_report(NULL, stderr) when the
- program exits. In Samba4 this is enabled by using the
- --leak-report command line option.
- </para>
- <para>
- For it to be useful, this function must be called before any
- other talloc function as it establishes a "null context" that
- acts as the top of the tree. If you don't call this function
- first then passing NULL to talloc_report() or
- talloc_report_full() won't give you the full tree printout.
- </para>
- <para>
- Here is a typical talloc report:
- </para>
- <screen format="linespecific">talloc report on 'null_context' (total 267 bytes in 15 blocks)
-libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
-libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
-iconv(UTF8,CP850) contains 42 bytes in 2 blocks
-libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
-iconv(CP850,UTF8) contains 42 bytes in 2 blocks
-iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
-iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
- </screen>
- </refsect2>
- <refsect2 id="talloc_enable_leak_report_full"><title>void talloc_enable_leak_report_full(void);</title>
- <para>
- This enables calling of talloc_report_full(NULL, stderr) when the
- program exits. In Samba4 this is enabled by using the
- --leak-report-full command line option.
- </para>
- <para>
- For it to be useful, this function must be called before any
- other talloc function as it establishes a "null context" that
- acts as the top of the tree. If you don't call this function
- first then passing NULL to talloc_report() or
- talloc_report_full() won't give you the full tree printout.
- </para>
- <para>
- Here is a typical full report:
- </para>
- <screen format="linespecific">full talloc report on 'root' (total 18 bytes in 8 blocks)
-p1 contains 18 bytes in 7 blocks (ref 0)
- r1 contains 13 bytes in 2 blocks (ref 0)
- reference to: p2
- p2 contains 1 bytes in 1 blocks (ref 1)
- x3 contains 1 bytes in 1 blocks (ref 0)
- x2 contains 1 bytes in 1 blocks (ref 0)
- x1 contains 1 bytes in 1 blocks (ref 0)
- </screen>
- </refsect2>
- <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>);</title>
- <para>
- The talloc_zero() macro is equivalent to:
- </para>
- <programlisting>ptr = talloc(ctx, type);
-if (ptr) memset(ptr, 0, sizeof(type));</programlisting>
- </refsect2>
- <refsect2><title>void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>)</title>
- <para>
- The talloc_zero_size() function is useful when you don't have a
- known type.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, size_t size);</title>
- <para>
- The talloc_memdup() function is equivalent to:
- </para>
- <programlisting>ptr = talloc_size(ctx, size);
-if (ptr) memcpy(ptr, p, size);</programlisting>
- </refsect2>
- <refsect2><title>char *talloc_strdup(const void *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>);</title>
- <para>
- The talloc_strdup() function is equivalent to:
- </para>
- <programlisting>ptr = talloc_size(ctx, strlen(p)+1);
-if (ptr) memcpy(ptr, p, strlen(p)+1);</programlisting>
- <para>
- This function sets the name of the new pointer to the passed
- string. This is equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
- </refsect2>
- <refsect2><title>char *talloc_strndup(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>);</title>
- <para>
- The talloc_strndup() function is the talloc equivalent of the C
- library function strndup(3).
- </para>
- <para>
- This function sets the name of the new pointer to the passed
- string. This is equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
- </refsect2>
- <refsect2><title>char *talloc_append_string(const void *<emphasis role="italic">t</emphasis>, char *<emphasis role="italic">orig</emphasis>, const char *<emphasis role="italic">append</emphasis>);</title>
- <para>
- The talloc_append_string() function appends the given formatted
- string to the given string.
- </para>
- <para>
- This function sets the name of the new pointer to the new
- string. This is equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
- </refsect2>
- <refsect2><title>char *talloc_vasprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>);</title>
- <para>
- The talloc_vasprintf() function is the talloc equivalent of the C
- library function vasprintf(3).
- </para>
- <para>
- This function sets the name of the new pointer to the new
- string. This is equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
- </refsect2>
- <refsect2><title>char *talloc_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
- <para>
- The talloc_asprintf() function is the talloc equivalent of the C
- library function asprintf(3).
- </para>
- <para>
- This function sets the name of the new pointer to the passed
- string. This is equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
- </refsect2>
- <refsect2><title>char *talloc_asprintf_append(char *s, const char *fmt, ...);</title>
- <para>
- The talloc_asprintf_append() function appends the given formatted
- string to the given string.
- </para>
- <para>
- This function sets the name of the new pointer to the new
- string. This is equivalent to:
- </para>
- <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
- </refsect2>
- <refsect2><title>(type *)talloc_array(const void *ctx, type, uint_t count);</title>
- <para>
- The talloc_array() macro is equivalent to:
- </para>
- <programlisting>(type *)talloc_size(ctx, sizeof(type) * count);</programlisting>
- <para>
- except that it provides integer overflow protection for the
- multiply, returning NULL if the multiply overflows.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_array_size(const void *ctx, size_t size, uint_t count);</title>
- <para>
- The talloc_array_size() function is useful when the type is not
- known. It operates in the same way as talloc_array(), but takes a
- size instead of a type.
- </para>
- </refsect2>
- <refsect2><title>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count);</title>
- <para>
- The talloc_ptrtype() macro should be used when you have a pointer to an array
- and want to allocate memory of an array to point at with this pointer. When compiling
- with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
- and talloc_get_name() will return the current location in the source file.
- and not the type.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</title>
- <para>
- This is a non-macro version of talloc_realloc(), which is useful
- as libraries sometimes want a realloc function pointer. A
- realloc(3) implementation encapsulates the functionality of
- malloc(3), free(3) and realloc(3) in one call, which is why it is
- useful to be able to pass around a single function pointer.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_autofree_context(void);</title>
- <para>
- This is a handy utility function that returns a talloc context
- which will be automatically freed on program exit. This can be
- used to reduce the noise in memory leak reports.
- </para>
- </refsect2>
- <refsect2><title>void *talloc_check_name(const void *ptr, const char *name);</title>
- <para>
- This function checks if a pointer has the specified <emphasis
- role="italic">name</emphasis>. If it does then the pointer is
- returned. It it doesn't then NULL is returned.
- </para>
- </refsect2>
- <refsect2><title>(type *)talloc_get_type(const void *ptr, type);</title>
- <para>
- This macro allows you to do type checking on talloc pointers. It
- is particularly useful for void* private pointers. It is
- equivalent to this:
- </para>
- <programlisting>(type *)talloc_check_name(ptr, #type)</programlisting>
- </refsect2>
- <refsect2><title>talloc_set_type(const void *ptr, type);</title>
- <para>
- This macro allows you to force the name of a pointer to be a
- particular <emphasis>type</emphasis>. This can be
- used in conjunction with talloc_get_type() to do type checking on
- void* pointers.
- </para>
- <para>
- It is equivalent to this:
- </para>
- <programlisting>talloc_set_name_const(ptr, #type)</programlisting>
- </refsect2>
- </refsect1>
- <refsect1><title>PERFORMANCE</title>
- <para>
- All the additional features of talloc(3) over malloc(3) do come at a
- price. We have a simple performance test in Samba4 that measures
- talloc() versus malloc() performance, and it seems that talloc() is
- about 10% slower than malloc() on my x86 Debian Linux box. For
- Samba, the great reduction in code complexity that we get by using
- talloc makes this worthwhile, especially as the total overhead of
- talloc/malloc in Samba is already quite small.
- </para>
- </refsect1>
- <refsect1><title>SEE ALSO</title>
- <para>
- malloc(3), strndup(3), vasprintf(3), asprintf(3),
- <ulink url="http://talloc.samba.org/"/>
- </para>
- </refsect1>
- <refsect1><title>COPYRIGHT/LICENSE</title>
- <para>
- Copyright (C) Andrew Tridgell 2004
- </para>
- <para>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at
- your option) any later version.
- </para>
- <para>
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- </para>
- <para>
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- </para>
- </refsect1>
-</refentry>
+++ /dev/null
-/*
- Samba Unix SMB/CIFS implementation.
-
- Samba trivial allocation library - new interface
-
- NOTE: Please read talloc_guide.txt for full documentation
-
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/*
- inspired by http://swapped.cc/halloc/
-*/
-
-#include "talloc.h"
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-
-/* use this to force every realloc to change the pointer, to stress test
- code that might not cope */
-#define ALWAYS_REALLOC 0
-
-
-#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0xe814ec70
-#define TALLOC_FLAG_FREE 0x01
-#define TALLOC_FLAG_LOOP 0x02
-#define TALLOC_MAGIC_REFERENCE ((const char *)1)
-
-/* by default we abort when given a bad pointer (such as when talloc_free() is called
- on a pointer that came from malloc() */
-#ifndef TALLOC_ABORT
-#define TALLOC_ABORT(reason) abort()
-#endif
-
-#ifndef discard_const_p
-#if defined(INTPTR_MIN)
-# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
-#else
-# define discard_const_p(type, ptr) ((type *)(ptr))
-#endif
-#endif
-
-/* these macros gain us a few percent of speed on gcc */
-#if HAVE_BUILTIN_EXPECT
-/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
- as its first argument */
-#define likely(x) __builtin_expect(!!(x), 1)
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#else
-#define likely(x) x
-#define unlikely(x) x
-#endif
-
-/* this null_context is only used if talloc_enable_leak_report() or
- talloc_enable_leak_report_full() is called, otherwise it remains
- NULL
-*/
-static void *null_context;
-static void *autofree_context;
-
-struct talloc_reference_handle {
- struct talloc_reference_handle *next, *prev;
- void *ptr;
-};
-
-typedef int (*talloc_destructor_t)(void *);
-
-struct talloc_chunk {
- struct talloc_chunk *next, *prev;
- struct talloc_chunk *parent, *child;
- struct talloc_reference_handle *refs;
- talloc_destructor_t destructor;
- const char *name;
- size_t size;
- unsigned flags;
-};
-
-/* 16 byte alignment seems to keep everyone happy */
-#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
-#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
-
-/* panic if we get a bad magic value */
-static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
-{
- const char *pp = (const char *)ptr;
- struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
- if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
- if (tc->flags & TALLOC_FLAG_FREE) {
- TALLOC_ABORT("Bad talloc magic value - double free");
- } else {
- TALLOC_ABORT("Bad talloc magic value - unknown value");
- }
- }
- return tc;
-}
-
-/* hook into the front of the list */
-#define _TLIST_ADD(list, p) \
-do { \
- if (!(list)) { \
- (list) = (p); \
- (p)->next = (p)->prev = NULL; \
- } else { \
- (list)->prev = (p); \
- (p)->next = (list); \
- (p)->prev = NULL; \
- (list) = (p); \
- }\
-} while (0)
-
-/* remove an element from a list - element doesn't have to be in list. */
-#define _TLIST_REMOVE(list, p) \
-do { \
- if ((p) == (list)) { \
- (list) = (p)->next; \
- if (list) (list)->prev = NULL; \
- } else { \
- if ((p)->prev) (p)->prev->next = (p)->next; \
- if ((p)->next) (p)->next->prev = (p)->prev; \
- } \
- if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
-} while (0)
-
-
-/*
- return the parent chunk of a pointer
-*/
-static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
- while (tc->prev) tc=tc->prev;
-
- return tc->parent;
-}
-
-void *talloc_parent(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
-}
-
-/*
- find parents name
-*/
-const char *talloc_parent_name(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc? tc->name : NULL;
-}
-
-/*
- Allocate a bit of memory as a child of an existing pointer
-*/
-static inline void *__talloc(const void *context, size_t size)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(context == NULL)) {
- context = null_context;
- }
-
- if (unlikely(size >= MAX_TALLOC_SIZE)) {
- return NULL;
- }
-
- tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
- if (unlikely(tc == NULL)) return NULL;
-
- tc->size = size;
- tc->flags = TALLOC_MAGIC;
- tc->destructor = NULL;
- tc->child = NULL;
- tc->name = NULL;
- tc->refs = NULL;
-
- if (likely(context)) {
- struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
-
- if (parent->child) {
- parent->child->parent = NULL;
- tc->next = parent->child;
- tc->next->prev = tc;
- } else {
- tc->next = NULL;
- }
- tc->parent = parent;
- tc->prev = NULL;
- parent->child = tc;
- } else {
- tc->next = tc->prev = tc->parent = NULL;
- }
-
- return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- setup a destructor to be called on free of a pointer
- the destructor should return 0 on success, or -1 on failure.
- if the destructor fails then the free is failed, and the memory can
- be continued to be used
-*/
-void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->destructor = destructor;
-}
-
-/*
- increase the reference count on a piece of memory.
-*/
-int talloc_increase_ref_count(const void *ptr)
-{
- if (unlikely(!talloc_reference(null_context, ptr))) {
- return -1;
- }
- return 0;
-}
-
-/*
- helper for talloc_reference()
-
- this is referenced by a function pointer and should not be inline
-*/
-static int talloc_reference_destructor(struct talloc_reference_handle *handle)
-{
- struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
- _TLIST_REMOVE(ptr_tc->refs, handle);
- return 0;
-}
-
-/*
- more efficient way to add a name to a pointer - the name must point to a
- true string constant
-*/
-static inline void _talloc_set_name_const(const void *ptr, const char *name)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->name = name;
-}
-
-/*
- internal talloc_named_const()
-*/
-static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
-{
- void *ptr;
-
- ptr = __talloc(context, size);
- if (unlikely(ptr == NULL)) {
- return NULL;
- }
-
- _talloc_set_name_const(ptr, name);
-
- return ptr;
-}
-
-/*
- make a secondary reference to a pointer, hanging off the given context.
- the pointer remains valid until both the original caller and this given
- context are freed.
-
- the major use for this is when two different structures need to reference the
- same underlying data, and you want to be able to free the two instances separately,
- and in either order
-*/
-void *_talloc_reference(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc;
- struct talloc_reference_handle *handle;
- if (unlikely(ptr == NULL)) return NULL;
-
- tc = talloc_chunk_from_ptr(ptr);
- handle = (struct talloc_reference_handle *)_talloc_named_const(context,
- sizeof(struct talloc_reference_handle),
- TALLOC_MAGIC_REFERENCE);
- if (unlikely(handle == NULL)) return NULL;
-
- /* note that we hang the destructor off the handle, not the
- main context as that allows the caller to still setup their
- own destructor on the context if they want to */
- talloc_set_destructor(handle, talloc_reference_destructor);
- handle->ptr = discard_const_p(void, ptr);
- _TLIST_ADD(tc->refs, handle);
- return handle->ptr;
-}
-
-
-/*
- internal talloc_free call
-*/
-static inline int _talloc_free(void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return -1;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (unlikely(tc->refs)) {
- int is_child;
- /* check this is a reference from a child or grantchild
- * back to it's parent or grantparent
- *
- * in that case we need to remove the reference and
- * call another instance of talloc_free() on the current
- * pointer.
- */
- is_child = talloc_is_parent(tc->refs, ptr);
- _talloc_free(tc->refs);
- if (is_child) {
- return _talloc_free(ptr);
- }
- return -1;
- }
-
- if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
- /* we have a free loop - stop looping */
- return 0;
- }
-
- if (unlikely(tc->destructor)) {
- talloc_destructor_t d = tc->destructor;
- if (d == (talloc_destructor_t)-1) {
- return -1;
- }
- tc->destructor = (talloc_destructor_t)-1;
- if (d(ptr) == -1) {
- tc->destructor = d;
- return -1;
- }
- tc->destructor = NULL;
- }
-
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- while (tc->child) {
- /* we need to work out who will own an abandoned child
- if it cannot be freed. In priority order, the first
- choice is owner of any remaining reference to this
- pointer, the second choice is our parent, and the
- final choice is the null context. */
- void *child = TC_PTR_FROM_CHUNK(tc->child);
- const void *new_parent = null_context;
- if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- if (unlikely(_talloc_free(child) == -1)) {
- if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- talloc_steal(new_parent, child);
- }
- }
-
- tc->flags |= TALLOC_FLAG_FREE;
- free(tc);
- return 0;
-}
-
-/*
- move a lump of memory from one talloc context to another return the
- ptr on success, or NULL if it could not be transferred.
- passing NULL as ptr will always return NULL with no side effects.
-*/
-void *_talloc_steal(const void *new_ctx, const void *ptr)
-{
- struct talloc_chunk *tc, *new_tc;
-
- if (unlikely(!ptr)) {
- return NULL;
- }
-
- if (unlikely(new_ctx == NULL)) {
- new_ctx = null_context;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (unlikely(new_ctx == NULL)) {
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->parent = tc->next = tc->prev = NULL;
- return discard_const_p(void, ptr);
- }
-
- new_tc = talloc_chunk_from_ptr(new_ctx);
-
- if (unlikely(tc == new_tc || tc->parent == new_tc)) {
- return discard_const_p(void, ptr);
- }
-
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->parent = new_tc;
- if (new_tc->child) new_tc->child->parent = NULL;
- _TLIST_ADD(new_tc->child, tc);
-
- return discard_const_p(void, ptr);
-}
-
-
-
-/*
- remove a secondary reference to a pointer. This undo's what
- talloc_reference() has done. The context and pointer arguments
- must match those given to a talloc_reference()
-*/
-static inline int talloc_unreference(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- struct talloc_reference_handle *h;
-
- if (unlikely(context == NULL)) {
- context = null_context;
- }
-
- for (h=tc->refs;h;h=h->next) {
- struct talloc_chunk *p = talloc_parent_chunk(h);
- if (p == NULL) {
- if (context == NULL) break;
- } else if (TC_PTR_FROM_CHUNK(p) == context) {
- break;
- }
- }
- if (h == NULL) {
- return -1;
- }
-
- return _talloc_free(h);
-}
-
-/*
- remove a specific parent context from a pointer. This is a more
- controlled varient of talloc_free()
-*/
-int talloc_unlink(const void *context, void *ptr)
-{
- struct talloc_chunk *tc_p, *new_p;
- void *new_parent;
-
- if (ptr == NULL) {
- return -1;
- }
-
- if (context == NULL) {
- context = null_context;
- }
-
- if (talloc_unreference(context, ptr) == 0) {
- return 0;
- }
-
- if (context == NULL) {
- if (talloc_parent_chunk(ptr) != NULL) {
- return -1;
- }
- } else {
- if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
- return -1;
- }
- }
-
- tc_p = talloc_chunk_from_ptr(ptr);
-
- if (tc_p->refs == NULL) {
- return _talloc_free(ptr);
- }
-
- new_p = talloc_parent_chunk(tc_p->refs);
- if (new_p) {
- new_parent = TC_PTR_FROM_CHUNK(new_p);
- } else {
- new_parent = NULL;
- }
-
- if (talloc_unreference(new_parent, ptr) != 0) {
- return -1;
- }
-
- talloc_steal(new_parent, ptr);
-
- return 0;
-}
-
-/*
- add a name to an existing pointer - va_list version
-*/
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->name = talloc_vasprintf(ptr, fmt, ap);
- if (likely(tc->name)) {
- _talloc_set_name_const(tc->name, ".name");
- }
- return tc->name;
-}
-
-/*
- add a name to an existing pointer
-*/
-const char *talloc_set_name(const void *ptr, const char *fmt, ...)
-{
- const char *name;
- va_list ap;
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
- return name;
-}
-
-
-/*
- create a named talloc pointer. Any talloc pointer can be named, and
- talloc_named() operates just like talloc() except that it allows you
- to name the pointer.
-*/
-void *talloc_named(const void *context, size_t size, const char *fmt, ...)
-{
- va_list ap;
- void *ptr;
- const char *name;
-
- ptr = __talloc(context, size);
- if (unlikely(ptr == NULL)) return NULL;
-
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
-
- if (unlikely(name == NULL)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- return ptr;
-}
-
-/*
- return the name of a talloc ptr, or "UNNAMED"
-*/
-const char *talloc_get_name(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
- return ".reference";
- }
- if (likely(tc->name)) {
- return tc->name;
- }
- return "UNNAMED";
-}
-
-
-/*
- check if a pointer has the given name. If it does, return the pointer,
- otherwise return NULL
-*/
-void *talloc_check_name(const void *ptr, const char *name)
-{
- const char *pname;
- if (unlikely(ptr == NULL)) return NULL;
- pname = talloc_get_name(ptr);
- if (likely(pname == name || strcmp(pname, name) == 0)) {
- return discard_const_p(void, ptr);
- }
- return NULL;
-}
-
-
-/*
- this is for compatibility with older versions of talloc
-*/
-void *talloc_init(const char *fmt, ...)
-{
- va_list ap;
- void *ptr;
- const char *name;
-
- /*
- * samba3 expects talloc_report_depth_cb(NULL, ...)
- * reports all talloc'ed memory, so we need to enable
- * null_tracking
- */
- talloc_enable_null_tracking();
-
- ptr = __talloc(NULL, 0);
- if (unlikely(ptr == NULL)) return NULL;
-
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
-
- if (unlikely(name == NULL)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- return ptr;
-}
-
-/*
- this is a replacement for the Samba3 talloc_destroy_pool functionality. It
- should probably not be used in new code. It's in here to keep the talloc
- code consistent across Samba 3 and 4.
-*/
-void talloc_free_children(void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- while (tc->child) {
- /* we need to work out who will own an abandoned child
- if it cannot be freed. In priority order, the first
- choice is owner of any remaining reference to this
- pointer, the second choice is our parent, and the
- final choice is the null context. */
- void *child = TC_PTR_FROM_CHUNK(tc->child);
- const void *new_parent = null_context;
- if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- if (unlikely(_talloc_free(child) == -1)) {
- if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- talloc_steal(new_parent, child);
- }
- }
-}
-
-/*
- Allocate a bit of memory as a child of an existing pointer
-*/
-void *_talloc(const void *context, size_t size)
-{
- return __talloc(context, size);
-}
-
-/*
- externally callable talloc_set_name_const()
-*/
-void talloc_set_name_const(const void *ptr, const char *name)
-{
- _talloc_set_name_const(ptr, name);
-}
-
-/*
- create a named talloc pointer. Any talloc pointer can be named, and
- talloc_named() operates just like talloc() except that it allows you
- to name the pointer.
-*/
-void *talloc_named_const(const void *context, size_t size, const char *name)
-{
- return _talloc_named_const(context, size, name);
-}
-
-/*
- free a talloc pointer. This also frees all child pointers of this
- pointer recursively
-
- return 0 if the memory is actually freed, otherwise -1. The memory
- will not be freed if the ref_count is > 1 or the destructor (if
- any) returns non-zero
-*/
-int talloc_free(void *ptr)
-{
- int saved_errno = errno, ret;
- ret = _talloc_free(ptr);
- if (ret == 0)
- errno = saved_errno;
- return ret;
-}
-
-
-
-/*
- A talloc version of realloc. The context argument is only used if
- ptr is NULL
-*/
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
-{
- struct talloc_chunk *tc;
- void *new_ptr;
-
- /* size zero is equivalent to free() */
- if (unlikely(size == 0)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- if (unlikely(size >= MAX_TALLOC_SIZE)) {
- return NULL;
- }
-
- /* realloc(NULL) is equivalent to malloc() */
- if (ptr == NULL) {
- return _talloc_named_const(context, size, name);
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- /* don't allow realloc on referenced pointers */
- if (unlikely(tc->refs)) {
- return NULL;
- }
-
- /* by resetting magic we catch users of the old memory */
- tc->flags |= TALLOC_FLAG_FREE;
-
-#if ALWAYS_REALLOC
- new_ptr = malloc(size + TC_HDR_SIZE);
- if (new_ptr) {
- memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
- free(tc);
- }
-#else
- new_ptr = realloc(tc, size + TC_HDR_SIZE);
-#endif
- if (unlikely(!new_ptr)) {
- tc->flags &= ~TALLOC_FLAG_FREE;
- return NULL;
- }
-
- tc = (struct talloc_chunk *)new_ptr;
- tc->flags &= ~TALLOC_FLAG_FREE;
- if (tc->parent) {
- tc->parent->child = tc;
- }
- if (tc->child) {
- tc->child->parent = tc;
- }
-
- if (tc->prev) {
- tc->prev->next = tc;
- }
- if (tc->next) {
- tc->next->prev = tc;
- }
-
- tc->size = size;
- _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
-
- return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- a wrapper around talloc_steal() for situations where you are moving a pointer
- between two structures, and want the old pointer to be set to NULL
-*/
-void *_talloc_move(const void *new_ctx, const void *_pptr)
-{
- const void **pptr = discard_const_p(const void *,_pptr);
- void *ret = _talloc_steal(new_ctx, *pptr);
- (*pptr) = NULL;
- return ret;
-}
-
-/*
- return the total size of a talloc pool (subtree)
-*/
-size_t talloc_total_size(const void *ptr)
-{
- size_t total = 0;
- struct talloc_chunk *c, *tc;
-
- if (ptr == NULL) {
- ptr = null_context;
- }
- if (ptr == NULL) {
- return 0;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return 0;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- total = tc->size;
- for (c=tc->child;c;c=c->next) {
- total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
- }
-
- tc->flags &= ~TALLOC_FLAG_LOOP;
-
- return total;
-}
-
-/*
- return the total number of blocks in a talloc pool (subtree)
-*/
-size_t talloc_total_blocks(const void *ptr)
-{
- size_t total = 0;
- struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return 0;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- total++;
- for (c=tc->child;c;c=c->next) {
- total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
- }
-
- tc->flags &= ~TALLOC_FLAG_LOOP;
-
- return total;
-}
-
-/*
- return the number of external references to a pointer
-*/
-size_t talloc_reference_count(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- struct talloc_reference_handle *h;
- size_t ret = 0;
-
- for (h=tc->refs;h;h=h->next) {
- ret++;
- }
- return ret;
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
- void (*callback)(const void *ptr,
- int depth, int max_depth,
- int is_ref,
- void *private_data),
- void *private_data)
-{
- struct talloc_chunk *c, *tc;
-
- if (ptr == NULL) {
- ptr = null_context;
- }
- if (ptr == NULL) return;
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return;
- }
-
- callback(ptr, depth, max_depth, 0, private_data);
-
- if (max_depth >= 0 && depth >= max_depth) {
- return;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
- for (c=tc->child;c;c=c->next) {
- if (c->name == TALLOC_MAGIC_REFERENCE) {
- struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
- callback(h->ptr, depth + 1, max_depth, 1, private_data);
- } else {
- talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
- }
- }
- tc->flags &= ~TALLOC_FLAG_LOOP;
-}
-
-static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
-{
- const char *name = talloc_get_name(ptr);
- FILE *f = (FILE *)_f;
-
- if (is_ref) {
- fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
- return;
- }
-
- if (depth == 0) {
- fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
- (max_depth < 0 ? "full " :""), name,
- (unsigned long)talloc_total_size(ptr),
- (unsigned long)talloc_total_blocks(ptr));
- return;
- }
-
- fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
- depth*4, "",
- name,
- (unsigned long)talloc_total_size(ptr),
- (unsigned long)talloc_total_blocks(ptr),
- (int)talloc_reference_count(ptr), ptr);
-
-#if 0
- fprintf(f, "content: ");
- if (talloc_total_size(ptr)) {
- int tot = talloc_total_size(ptr);
- int i;
-
- for (i = 0; i < tot; i++) {
- if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
- fprintf(f, "%c", ((char *)ptr)[i]);
- } else {
- fprintf(f, "~%02x", ((char *)ptr)[i]);
- }
- }
- }
- fprintf(f, "\n");
-#endif
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
-{
- talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
- fflush(f);
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_full(const void *ptr, FILE *f)
-{
- talloc_report_depth_file(ptr, 0, -1, f);
-}
-
-/*
- report on memory usage by all children of a pointer
-*/
-void talloc_report(const void *ptr, FILE *f)
-{
- talloc_report_depth_file(ptr, 0, 1, f);
-}
-
-/*
- report on any memory hanging off the null context
-*/
-static void talloc_report_null(void)
-{
- if (talloc_total_size(null_context) != 0) {
- talloc_report(null_context, stderr);
- }
-}
-
-/*
- report on any memory hanging off the null context
-*/
-static void talloc_report_null_full(void)
-{
- if (talloc_total_size(null_context) != 0) {
- talloc_report_full(null_context, stderr);
- }
-}
-
-/*
- enable tracking of the NULL context
-*/
-void talloc_enable_null_tracking(void)
-{
- if (null_context == NULL) {
- null_context = _talloc_named_const(NULL, 0, "null_context");
- }
-}
-
-/*
- disable tracking of the NULL context
-*/
-void talloc_disable_null_tracking(void)
-{
- _talloc_free(null_context);
- null_context = NULL;
-}
-
-/*
- enable leak reporting on exit
-*/
-void talloc_enable_leak_report(void)
-{
- talloc_enable_null_tracking();
- atexit(talloc_report_null);
-}
-
-/*
- enable full leak reporting on exit
-*/
-void talloc_enable_leak_report_full(void)
-{
- talloc_enable_null_tracking();
- atexit(talloc_report_null_full);
-}
-
-/*
- talloc and zero memory.
-*/
-void *_talloc_zero(const void *ctx, size_t size, const char *name)
-{
- void *p = _talloc_named_const(ctx, size, name);
-
- if (p) {
- memset(p, '\0', size);
- }
-
- return p;
-}
-
-/*
- memdup with a talloc.
-*/
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
-{
- void *newp = _talloc_named_const(t, size, name);
-
- if (likely(newp)) {
- memcpy(newp, p, size);
- }
-
- return newp;
-}
-
-/*
- strdup with a talloc
-*/
-char *talloc_strdup(const void *t, const char *p)
-{
- char *ret;
- if (!p) {
- return NULL;
- }
- ret = (char *)talloc_memdup(t, p, strlen(p) + 1);
- if (likely(ret)) {
- _talloc_set_name_const(ret, ret);
- }
- return ret;
-}
-
-/*
- append to a talloced string
-*/
-char *talloc_append_string(char *orig, const char *append)
-{
- char *ret;
- size_t olen = strlen(orig);
- size_t alenz;
-
- if (!append)
- return orig;
-
- alenz = strlen(append) + 1;
-
- ret = talloc_realloc(NULL, orig, char, olen + alenz);
- if (!ret)
- return NULL;
-
- /* append the string with the trailing \0 */
- memcpy(&ret[olen], append, alenz);
-
- _talloc_set_name_const(ret, ret);
-
- return ret;
-}
-
-/*
- strndup with a talloc
-*/
-char *talloc_strndup(const void *t, const char *p, size_t n)
-{
- size_t len;
- char *ret;
-
- for (len=0; len<n && p[len]; len++) ;
-
- ret = (char *)__talloc(t, len + 1);
- if (!ret) { return NULL; }
- memcpy(ret, p, len);
- ret[len] = 0;
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
-{
- int len;
- char *ret;
- va_list ap2;
- char c;
-
- /* this call looks strange, but it makes it work on older solaris boxes */
- va_copy(ap2, ap);
- len = vsnprintf(&c, 1, fmt, ap2);
- va_end(ap2);
- if (len < 0) {
- return NULL;
- }
-
- ret = (char *)__talloc(t, len+1);
- if (ret) {
- va_copy(ap2, ap);
- vsnprintf(ret, len+1, fmt, ap2);
- va_end(ap2);
- _talloc_set_name_const(ret, ret);
- }
-
- return ret;
-}
-
-
-/*
- Perform string formatting, and return a pointer to newly allocated
- memory holding the result, inside a memory pool.
- */
-char *talloc_asprintf(const void *t, const char *fmt, ...)
-{
- va_list ap;
- char *ret;
-
- va_start(ap, fmt);
- ret = talloc_vasprintf(t, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved. Good for gradually
- * accumulating output into a string buffer.
- **/
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
-{
- struct talloc_chunk *tc;
- int len, s_len;
- va_list ap2;
- char c;
-
- if (s == NULL) {
- return talloc_vasprintf(NULL, fmt, ap);
- }
-
- tc = talloc_chunk_from_ptr(s);
-
- s_len = tc->size - 1;
-
- va_copy(ap2, ap);
- len = vsnprintf(&c, 1, fmt, ap2);
- va_end(ap2);
-
- if (len <= 0) {
- /* Either the vsnprintf failed or the format resulted in
- * no characters being formatted. In the former case, we
- * ought to return NULL, in the latter we ought to return
- * the original string. Most current callers of this
- * function expect it to never return NULL.
- */
- return s;
- }
-
- s = talloc_realloc(NULL, s, char, s_len + len+1);
- if (!s) return NULL;
-
- va_copy(ap2, ap);
- vsnprintf(s+s_len, len+1, fmt, ap2);
- va_end(ap2);
- _talloc_set_name_const(s, s);
-
- return s;
-}
-
-/*
- Realloc @p s to append the formatted result of @p fmt and return @p
- s, which may have moved. Good for gradually accumulating output
- into a string buffer.
- */
-char *talloc_asprintf_append(char *s, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- s = talloc_vasprintf_append(s, fmt, ap);
- va_end(ap);
- return s;
-}
-
-/*
- alloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- return NULL;
- }
- return _talloc_named_const(ctx, el_size * count, name);
-}
-
-/*
- alloc an zero array, checking for integer overflow in the array size
-*/
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- return NULL;
- }
- return _talloc_zero(ctx, el_size * count, name);
-}
-
-/*
- realloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- return NULL;
- }
- return _talloc_realloc(ctx, ptr, el_size * count, name);
-}
-
-/*
- a function version of talloc_realloc(), so it can be passed as a function pointer
- to libraries that want a realloc function (a realloc function encapsulates
- all the basic capabilities of an allocation library, which is why this is useful)
-*/
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
-{
- return _talloc_realloc(context, ptr, size, NULL);
-}
-
-
-static int talloc_autofree_destructor(void *ptr)
-{
- autofree_context = NULL;
- return 0;
-}
-
-static void talloc_autofree(void)
-{
- _talloc_free(autofree_context);
-}
-
-/*
- return a context which will be auto-freed on exit
- this is useful for reducing the noise in leak reports
-*/
-void *talloc_autofree_context(void)
-{
- if (autofree_context == NULL) {
- autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
- talloc_set_destructor(autofree_context, talloc_autofree_destructor);
- atexit(talloc_autofree);
- }
- return autofree_context;
-}
-
-size_t talloc_get_size(const void *context)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL)
- return 0;
-
- tc = talloc_chunk_from_ptr(context);
-
- return tc->size;
-}
-
-/*
- find a parent of this context that has the given name, if any
-*/
-void *talloc_find_parent_byname(const void *context, const char *name)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(context);
- while (tc) {
- if (tc->name && strcmp(tc->name, name) == 0) {
- return TC_PTR_FROM_CHUNK(tc);
- }
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- return NULL;
-}
-
-/*
- show the parentage of a context
-*/
-void talloc_show_parents(const void *context, FILE *file)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- fprintf(file, "talloc no parents for NULL\n");
- return;
- }
-
- tc = talloc_chunk_from_ptr(context);
- fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
- while (tc) {
- fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- fflush(file);
-}
-
-/*
- return 1 if ptr is a parent of context
-*/
-int talloc_is_parent(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- return 0;
- }
-
- tc = talloc_chunk_from_ptr(context);
- while (tc) {
- if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- return 0;
-}
+++ /dev/null
-#ifndef CCAN_TALLOC_H
-#define CCAN_TALLOC_H
-/*
- Copyright (C) Andrew Tridgell 2004-2005
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include "config.h"
-#include "typesafe_cb/typesafe_cb.h"
-
-/*
- this uses a little trick to allow __LINE__ to be stringified
-*/
-#ifndef __location__
-#define __TALLOC_STRING_LINE1__(s) #s
-#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
-#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
-#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
-#endif
-
-#if HAVE_ATTRIBUTE_PRINTF
-/** Use gcc attribute to check printf fns. a1 is the 1-based index of
- * the parameter containing the format, and a2 the index of the first
- * argument. Note that some gcc 2.x versions don't handle this
- * properly **/
-#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
-#else
-#define PRINTF_ATTRIBUTE(a1, a2)
-#endif
-
-/* try to make talloc_set_destructor() and talloc_steal() type safe,
- if we have a recent gcc */
-#if HAVE_TYPEOF
-#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
-#else
-#define _TALLOC_TYPEOF(ptr) void *
-#endif
-
-#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
-
-/**
- * talloc - allocate dynamic memory for a type
- * @ctx: context to be parent of this allocation, or NULL.
- * @type: the type to be allocated.
- *
- * The talloc() macro is the core of the talloc library. It takes a memory
- * context and a type, and returns a pointer to a new area of memory of the
- * given type.
- *
- * The returned pointer is itself a talloc context, so you can use it as the
- * context argument to more calls to talloc if you wish.
- *
- * The returned pointer is a "child" of @ctx. This means that if you
- * talloc_free() @ctx then the new child disappears as well. Alternatively you
- * can free just the child.
- *
- * @ctx can be NULL, in which case a new top level context is created.
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc(NULL, unsigned int);
- * b = talloc(a, unsigned int);
- *
- * See Also:
- * talloc_zero, talloc_array, talloc_steal, talloc_free.
- */
-#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
-
-/**
- * talloc_free - free talloc'ed memory and its children
- * @ptr: the talloced pointer to free
- *
- * The talloc_free() function frees a piece of talloc memory, and all its
- * children. You can call talloc_free() on any pointer returned by talloc().
- *
- * The return value of talloc_free() indicates success or failure, with 0
- * returned for success and -1 for failure. The only possible failure condition
- * is if the pointer had a destructor attached to it and the destructor
- * returned -1. See talloc_set_destructor() for details on destructors.
- * errno will be preserved unless the talloc_free fails.
- *
- * If this pointer has an additional parent when talloc_free() is called then
- * the memory is not actually released, but instead the most recently
- * established parent is destroyed. See talloc_reference() for details on
- * establishing additional parents.
- *
- * For more control on which parent is removed, see talloc_unlink().
- *
- * talloc_free() operates recursively on its children.
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc(NULL, unsigned int);
- * b = talloc(a, unsigned int);
- * // Frees a and b
- * talloc_free(a);
- *
- * See Also:
- * talloc_set_destructor, talloc_unlink
- */
-int talloc_free(void *ptr);
-
-/**
- * talloc_set_destructor: set a destructor for when this pointer is freed
- * @ptr: the talloc pointer to set the destructor on
- * @destructor: the function to be called
- *
- * The function talloc_set_destructor() sets the "destructor" for the pointer
- * @ptr. A destructor is a function that is called when the memory used by a
- * pointer is about to be released. The destructor receives the pointer as an
- * argument, and should return 0 for success and -1 for failure.
- *
- * The destructor can do anything it wants to, including freeing other pieces
- * of memory. A common use for destructors is to clean up operating system
- * resources (such as open file descriptors) contained in the structure the
- * destructor is placed on.
- *
- * You can only place one destructor on a pointer. If you need more than one
- * destructor then you can create a zero-length child of the pointer and place
- * an additional destructor on that.
- *
- * To remove a destructor call talloc_set_destructor() with NULL for the
- * destructor.
- *
- * If your destructor attempts to talloc_free() the pointer that it is the
- * destructor for then talloc_free() will return -1 and the free will be
- * ignored. This would be a pointless operation anyway, as the destructor is
- * only called when the memory is just about to go away.
- *
- * Example:
- * static int destroy_fd(int *fd)
- * {
- * close(*fd);
- * return 0;
- * }
- *
- * int *open_file(const char *filename)
- * {
- * int *fd = talloc(NULL, int);
- * *fd = open(filename, O_RDONLY);
- * if (*fd < 0) {
- * talloc_free(fd);
- * return NULL;
- * }
- * // Whenever they free this, we close the file.
- * talloc_set_destructor(fd, destroy_fd);
- * return fd;
- * }
- *
- * See Also:
- * talloc, talloc_free
- */
-#define talloc_set_destructor(ptr, function) \
- _talloc_set_destructor((ptr), typesafe_cb(int, (function), (ptr)))
-
-/**
- * talloc_zero - allocate zeroed dynamic memory for a type
- * @ctx: context to be parent of this allocation, or NULL.
- * @type: the type to be allocated.
- *
- * The talloc_zero() macro is equivalent to:
- *
- * ptr = talloc(ctx, type);
- * if (ptr) memset(ptr, 0, sizeof(type));
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc_zero(NULL, unsigned int);
- * b = talloc_zero(a, unsigned int);
- *
- * See Also:
- * talloc, talloc_zero_size, talloc_zero_array
- */
-#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
-
-/**
- * talloc_array - allocate dynamic memory for an array of a given type
- * @ctx: context to be parent of this allocation, or NULL.
- * @type: the type to be allocated.
- * @count: the number of elements to be allocated.
- *
- * The talloc_array() macro is a safe way of allocating an array. It is
- * equivalent to:
- *
- * (type *)talloc_size(ctx, sizeof(type) * count);
- *
- * except that it provides integer overflow protection for the multiply,
- * returning NULL if the multiply overflows.
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc_zero(NULL, unsigned int);
- * b = talloc_array(a, unsigned int, 100);
- *
- * See Also:
- * talloc, talloc_zero_array
- */
-#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
-
-/**
- * talloc_size - allocate a particular size of memory
- * @ctx: context to be parent of this allocation, or NULL.
- * @size: the number of bytes to allocate
- *
- * The function talloc_size() should be used when you don't have a convenient
- * type to pass to talloc(). Unlike talloc(), it is not type safe (as it
- * returns a void *), so you are on your own for type checking.
- *
- * Best to use talloc() or talloc_array() instead.
- *
- * Example:
- * void *mem = talloc_size(NULL, 100);
- *
- * See Also:
- * talloc, talloc_array, talloc_zero_size
- */
-#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
-
-#ifdef HAVE_TYPEOF
-/**
- * talloc_steal - change/set the parent context of a talloc pointer
- * @ctx: the new parent
- * @ptr: the talloc pointer to reparent
- *
- * The talloc_steal() function changes the parent context of a talloc
- * pointer. It is typically used when the context that the pointer is currently
- * a child of is going to be freed and you wish to keep the memory for a longer
- * time.
- *
- * The talloc_steal() function returns the pointer that you pass it. It does
- * not have any failure modes.
- *
- * NOTE: It is possible to produce loops in the parent/child relationship if
- * you are not careful with talloc_steal(). No guarantees are provided as to
- * your sanity or the safety of your data if you do this.
- *
- * talloc_steal (new_ctx, NULL) will return NULL with no sideeffects.
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc(NULL, unsigned int);
- * b = talloc(NULL, unsigned int);
- * // Reparent b to a as if we'd done 'b = talloc(a, unsigned int)'.
- * talloc_steal(a, b);
- *
- * See Also:
- * talloc_reference
- */
-#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) _talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); _talloc_steal_ret; }) /* this extremely strange macro is to avoid some braindamaged warning stupidity in gcc 4.1.x */
-#else
-#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
-#endif /* HAVE_TYPEOF */
-
-/**
- * talloc_report_full - report all the memory used by a pointer and children.
- * @ptr: the context to report on
- * @f: the file to report to
- *
- * Recursively print the entire tree of memory referenced by the
- * pointer. References in the tree are shown by giving the name of the pointer
- * that is referenced.
- *
- * You can pass NULL for the pointer, in which case a report is printed for the
- * top level memory context, but only if talloc_enable_null_tracking() has been
- * called.
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc(NULL, unsigned int);
- * b = talloc(a, unsigned int);
- * fprintf(stderr, "Dumping memory tree for a:\n");
- * talloc_report_full(a, stderr);
- *
- * See Also:
- * talloc_report
- */
-void talloc_report_full(const void *ptr, FILE *f);
-
-/**
- * talloc_reference - add an additional parent to a context
- * @ctx: the additional parent
- * @ptr: the talloc pointer
- *
- * The talloc_reference() function makes @ctx an additional parent of @ptr.
- *
- * The return value of talloc_reference() is always the original pointer @ptr,
- * unless talloc ran out of memory in creating the reference in which case it
- * will return NULL (each additional reference consumes around 48 bytes of
- * memory on intel x86 platforms).
- *
- * If @ptr is NULL, then the function is a no-op, and simply returns NULL.
- *
- * After creating a reference you can free it in one of the following ways:
- *
- * - you can talloc_free() any parent of the original pointer. That will
- * reduce the number of parents of this pointer by 1, and will cause this
- * pointer to be freed if it runs out of parents.
- *
- * - you can talloc_free() the pointer itself. That will destroy the most
- * recently established parent to the pointer and leave the pointer as a
- * child of its current parent.
- *
- * For more control on which parent to remove, see talloc_unlink().
- * Example:
- * unsigned int *a, *b, *c;
- * a = talloc(NULL, unsigned int);
- * b = talloc(NULL, unsigned int);
- * c = talloc(a, unsigned int);
- * // b also serves as a parent of c.
- * talloc_reference(b, c);
- */
-#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
-
-/**
- * talloc_unlink: remove a specific parent from a talloc pointer.
- * @context: the parent to remove
- * @ptr: the talloc pointer
- *
- * The talloc_unlink() function removes a specific parent from @ptr. The
- * context passed must either be a context used in talloc_reference() with this
- * pointer, or must be a direct parent of @ptr.
- *
- * Note that if the parent has already been removed using talloc_free() then
- * this function will fail and will return -1. Likewise, if @ptr is NULL,
- * then the function will make no modifications and return -1.
- *
- * Usually you can just use talloc_free() instead of talloc_unlink(), but
- * sometimes it is useful to have the additional control on which parent is
- * removed.
- * Example:
- * unsigned int *a, *b, *c;
- * a = talloc(NULL, unsigned int);
- * b = talloc(NULL, unsigned int);
- * c = talloc(a, unsigned int);
- * // b also serves as a parent of c.
- * talloc_reference(b, c);
- * talloc_unlink(b, c);
- */
-int talloc_unlink(const void *context, void *ptr);
-
-/**
- * talloc_report - print a summary of memory used by a pointer
- *
- * The talloc_report() function prints a summary report of all memory
- * used by @ptr. One line of report is printed for each immediate child of
- * @ptr, showing the total memory and number of blocks used by that child.
- *
- * You can pass NULL for the pointer, in which case a report is printed for the
- * top level memory context, but only if talloc_enable_null_tracking() has been
- * called.
- *
- * Example:
- * unsigned int *a, *b;
- * a = talloc(NULL, unsigned int);
- * b = talloc(a, unsigned int);
- * fprintf(stderr, "Summary of memory tree for a:\n");
- * talloc_report(a, stderr);
- *
- * See Also:
- * talloc_report_full
- */
-void talloc_report(const void *ptr, FILE *f);
-
-/**
- * talloc_ptrtype - allocate a size of memory suitable for this pointer
- * @ctx: context to be parent of this allocation, or NULL.
- * @ptr: the pointer whose type we are to allocate
- *
- * The talloc_ptrtype() macro should be used when you have a pointer and
- * want to allocate memory to point at with this pointer. When compiling
- * with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
- * and talloc_get_name() will return the current location in the source file.
- * and not the type.
- *
- * Example:
- * unsigned int *a = talloc_ptrtype(NULL, a);
- */
-#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
-
-/**
- * talloc_free_children - free talloc'ed memory's children only
- * @ptr: the talloced pointer whose children we want to free
- *
- * talloc_free_children() walks along the list of all children of a talloc
- * context @ptr and talloc_free()s only the children, not the context itself.
- * Example:
- * unsigned int *a, *b;
- * a = talloc(NULL, unsigned int);
- * b = talloc(a, unsigned int);
- * // Frees b
- * talloc_free_children(a);
- */
-void talloc_free_children(void *ptr);
-
-/**
- * talloc_new - create a new context
- * @ctx: the context to use as a parent.
- *
- * This is a utility macro that creates a new memory context hanging off an
- * exiting context, automatically naming it "talloc_new: __location__" where
- * __location__ is the source line it is called from. It is particularly useful
- * for creating a new temporary working context.
- */
-#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
-
-/**
- * talloc_zero_size - allocate a particular size of zeroed memory
- *
- * The talloc_zero_size() function is useful when you don't have a known type.
- */
-#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
-
-/**
- * talloc_zero_array - allocate an array of zeroed types
- * @ctx: context to be parent of this allocation, or NULL.
- * @type: the type to be allocated.
- * @count: the number of elements to be allocated.
- *
- * Just like talloc_array, but zeroes the memory.
- */
-#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
-
-/**
- * talloc_zero_array - allocate an array of zeroed types
- * @ctx: context to be parent of this allocation, or NULL.
- * @type: the type to be allocated.
- * @count: the number of elements to be allocated.
- *
- * Just like talloc_array, but zeroes the memory.
- */
-#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
-
-/**
- * talloc_array_ptrtype - allocate an array of memory suitable for this pointer
- * @ctx: context to be parent of this allocation, or NULL.
- * @ptr: the pointer whose type we are to allocate
- * @count: the number of elements for the array
- *
- * Like talloc_ptrtype(), except it allocates an array.
- */
-#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
-
-/**
- * talloc_realloc - resize a talloc array
- * @ctx: the parent to assign (if p is NULL)
- * @p: the memory to reallocate
- * @type: the type of the object to allocate
- * @count: the number of objects to reallocate
- *
- * The talloc_realloc() macro changes the size of a talloc pointer. The "count"
- * argument is the number of elements of type "type" that you want the
- * resulting pointer to hold.
- *
- * talloc_realloc() has the following equivalences:
- *
- * talloc_realloc(context, NULL, type, 1) ==> talloc(context, type);
- * talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N);
- * talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr);
- *
- * The "context" argument is only used if "ptr" is NULL, otherwise it is
- * ignored.
- *
- * talloc_realloc() returns the new pointer, or NULL on failure. The call will
- * fail either due to a lack of memory, or because the pointer has more than
- * one parent (see talloc_reference()).
- */
-#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
-
-/**
- * talloc_realloc_size - resize talloc memory
- * @ctx: the parent to assign (if p is NULL)
- * @ptr: the memory to reallocate
- * @size: the new size of memory.
- *
- * The talloc_realloc_size() function is useful when the type is not known so
- * the typesafe talloc_realloc() cannot be used.
- */
-#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
-
-/**
- * talloc_strdup - duplicate a string
- * @ctx: the talloc context for the new string
- * @p: the string to copy
- *
- * The talloc_strdup() function is equivalent to:
- *
- * ptr = talloc_size(ctx, strlen(p)+1);
- * if (ptr) memcpy(ptr, p, strlen(p)+1);
- *
- * This functions sets the name of the new pointer to the passed string. This
- * is equivalent to:
- *
- * talloc_set_name_const(ptr, ptr)
- */
-char *talloc_strdup(const void *t, const char *p);
-
-/**
- * talloc_strndup - duplicate a limited length of a string
- * @ctx: the talloc context for the new string
- * @p: the string to copy
- * @n: the maximum length of the returned string.
- *
- * The talloc_strndup() function is the talloc equivalent of the C library
- * function strndup(): the result will be truncated to @n characters before
- * the nul terminator.
- *
- * This functions sets the name of the new pointer to the passed string. This
- * is equivalent to:
- *
- * talloc_set_name_const(ptr, ptr)
- */
-char *talloc_strndup(const void *t, const char *p, size_t n);
-
-/**
- * talloc_memdup - duplicate some talloc memory
- *
- * The talloc_memdup() function is equivalent to:
- *
- * ptr = talloc_size(ctx, size);
- * if (ptr) memcpy(ptr, p, size);
- */
-#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
-
-/**
- * talloc_asprintf - sprintf into a talloc buffer.
- * @t: The context to allocate the buffer from
- * @fmt: printf-style format for the buffer.
- *
- * The talloc_asprintf() function is the talloc equivalent of the C library
- * function asprintf().
- *
- * This functions sets the name of the new pointer to the new string. This is
- * equivalent to:
- *
- * talloc_set_name_const(ptr, ptr)
- */
-char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-
-/**
- * talloc_append_string - concatenate onto a tallocated string
- * @orig: the tallocated string to append to
- * @append: the string to add, or NULL to add nothing.
- *
- * The talloc_append_string() function appends the given formatted string to
- * the given string.
- *
- * This function sets the name of the new pointer to the new string. This is
- * equivalent to:
- *
- * talloc_set_name_const(ptr, ptr)
- */
-char *talloc_append_string(char *orig, const char *append);
-
-/**
- * talloc_asprintf_append - sprintf onto the end of a talloc buffer.
- * @s: The tallocated string buffer
- * @fmt: printf-style format to append to the buffer.
- *
- * The talloc_asprintf_append() function appends the given formatted string to
- * the given string.
- *
- * This functions sets the name of the new pointer to the new string. This is
- * equivalent to:
- * talloc_set_name_const(ptr, ptr)
- */
-char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-
-/**
- * talloc_vasprintf - vsprintf into a talloc buffer.
- * @t: The context to allocate the buffer from
- * @fmt: printf-style format for the buffer
- * @ap: va_list arguments
- *
- * The talloc_vasprintf() function is the talloc equivalent of the C library
- * function vasprintf()
- *
- * This functions sets the name of the new pointer to the new string. This is
- * equivalent to:
- *
- * talloc_set_name_const(ptr, ptr)
- */
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-/**
- * talloc_vasprintf_append - sprintf onto the end of a talloc buffer.
- * @t: The context to allocate the buffer from
- * @fmt: printf-style format for the buffer
- * @ap: va_list arguments
- *
- * The talloc_vasprintf_append() function is equivalent to
- * talloc_asprintf_append(), except it takes a va_list.
- */
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-/**
- * talloc_set_type - force the name of a pointer to a particular type
- * @ptr: the talloc pointer
- * @type: the type whose name to set the ptr name to.
- *
- * This macro allows you to force the name of a pointer to be a particular
- * type. This can be used in conjunction with talloc_get_type() to do type
- * checking on void* pointers.
- *
- * It is equivalent to this:
- * talloc_set_name_const(ptr, #type)
- */
-#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
-
-/**
- * talloc_get_type - convert a talloced pointer with typechecking
- * @ptr: the talloc pointer
- * @type: the type which we expect the talloced pointer to be.
- *
- * This macro allows you to do type checking on talloc pointers. It is
- * particularly useful for void* private pointers. It is equivalent to this:
- *
- * (type *)talloc_check_name(ptr, #type)
- */
-#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
-
-/**
- * talloc_find_parent_byname - find a talloc parent by type
- * @ptr: the talloc pointer
- * @type: the type we're looking for
- *
- * Find a parent memory context of the current context that has the given
- * name. This can be very useful in complex programs where it may be difficult
- * to pass all information down to the level you need, but you know the
- * structure you want is a parent of another context.
- */
-#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
-
-/**
- * talloc_increase_ref_count - hold a reference to a talloc pointer
- * @ptr: the talloc pointer
- *
- * The talloc_increase_ref_count(ptr) function is exactly equivalent to:
- *
- * talloc_reference(NULL, ptr);
- *
- * You can use either syntax, depending on which you think is clearer in your
- * code.
- *
- * It returns 0 on success and -1 on failure.
- */
-int talloc_increase_ref_count(const void *ptr);
-
-/**
- * talloc_set_name - set the name for a talloc pointer
- * @ptr: the talloc pointer
- * @fmt: the printf-style format string for the name
- *
- * Each talloc pointer has a "name". The name is used principally for debugging
- * purposes, although it is also possible to set and get the name on a pointer
- * in as a way of "marking" pointers in your code.
- *
- * The main use for names on pointer is for "talloc reports". See
- * talloc_report() and talloc_report_full() for details. Also see
- * talloc_enable_leak_report() and talloc_enable_leak_report_full().
- *
- * The talloc_set_name() function allocates memory as a child of the
- * pointer. It is logically equivalent to:
- * talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
- *
- * Note that multiple calls to talloc_set_name() will allocate more memory
- * without releasing the name. All of the memory is released when the ptr is
- * freed using talloc_free().
- */
-const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-
-/**
- * talloc_set_name_const - set a talloc pointer name to a string constant
- * @ptr: the talloc pointer to name
- * @name: the strucng constant.
- *
- * The function talloc_set_name_const() is just like talloc_set_name(), but it
- * takes a string constant, and is much faster. It is extensively used by the
- * "auto naming" macros, such as talloc().
- *
- * This function does not allocate any memory. It just copies the supplied
- * pointer into the internal representation of the talloc ptr. This means you
- * must not pass a name pointer to memory that will disappear before the ptr is
- * freed with talloc_free().
- */
-void talloc_set_name_const(const void *ptr, const char *name);
-
-/**
- * talloc_named - create a specifically-named talloc pointer
- * @context: the parent context for the allocation
- * @size: the size to allocate
- * @fmt: the printf-style format for the name
- *
- * The talloc_named() function creates a named talloc pointer. It is equivalent
- * to:
- *
- * ptr = talloc_size(context, size);
- * talloc_set_name(ptr, fmt, ....);
- */
-void *talloc_named(const void *context, size_t size,
- const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
-
-/**
- * talloc_named_const - create a specifically-named talloc pointer
- * @context: the parent context for the allocation
- * @size: the size to allocate
- * @name: the string constant to use as the name
- *
- * This is equivalent to:
- *
- * ptr = talloc_size(context, size);
- * talloc_set_name_const(ptr, name);
- */
-void *talloc_named_const(const void *context, size_t size, const char *name);
-
-/**
- * talloc_get_name - get the name of a talloc pointer
- * @ptr: the talloc pointer
- *
- * This returns the current name for the given talloc pointer. See
- * talloc_set_name() for details.
- */
-const char *talloc_get_name(const void *ptr);
-
-/**
- * talloc_check_name - check if a pointer has the specified name
- * @ptr: the talloc pointer
- * @name: the name to compare with the pointer's name
- *
- * This function checks if a pointer has the specified name. If it does then
- * the pointer is returned. It it doesn't then NULL is returned.
- */
-void *talloc_check_name(const void *ptr, const char *name);
-
-/**
- * talloc_init - create a top-level context of particular name
- * @fmt: the printf-style format of the name
- *
- * This function creates a zero length named talloc context as a top level
- * context. It is equivalent to:
- *
- * talloc_named(NULL, 0, fmt, ...);
- */
-void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
-
-/**
- * talloc_total_size - get the bytes used by the pointer and its children
- * @ptr: the talloc pointer
- *
- * The talloc_total_size() function returns the total size in bytes used by
- * this pointer and all child pointers. Mostly useful for debugging.
- *
- * Passing NULL is allowed, but it will only give a meaningful result if
- * talloc_enable_leak_report() or talloc_enable_leak_report_full() has been
- * called.
- */
-size_t talloc_total_size(const void *ptr);
-
-/**
- * talloc_total_blocks - get the number of allocations for the pointer
- * @ptr: the talloc pointer
- *
- * The talloc_total_blocks() function returns the total allocations used by
- * this pointer and all child pointers. Mostly useful for debugging. For
- * example, a pointer with no children will return "1".
- *
- * Passing NULL is allowed, but it will only give a meaningful result if
- * talloc_enable_leak_report() or talloc_enable_leak_report_full() has been
- * called.
- */
-size_t talloc_total_blocks(const void *ptr);
-
-/**
- * talloc_report_depth_cb - walk the entire talloc tree under a talloc pointer
- * @ptr: the talloc pointer to recurse under
- * @depth: the current depth of traversal
- * @max_depth: maximum depth to traverse, or -1 for no maximum
- * @callback: the function to call on each pointer
- * @private_data: pointer to hand to @callback.
- *
- * This provides a more flexible reports than talloc_report(). It will
- * recursively call the callback for the entire tree of memory referenced by
- * the pointer. References in the tree are passed with is_ref = 1 and the
- * pointer that is referenced.
- *
- * You can pass NULL for the pointer, in which case a report is printed for the
- * top level memory context, but only if talloc_enable_leak_report() or
- * talloc_enable_leak_report_full() has been called.
- *
- * The recursion is stopped when depth >= max_depth. max_depth = -1 means only
- * stop at leaf nodes.
- */
-void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
- void (*callback)(const void *ptr,
- int depth, int max_depth,
- int is_ref,
- void *private_data),
- void *private_data);
-
-/**
- * talloc_report_depth_file - report talloc usage to a maximum depth
- * @ptr: the talloc pointer to recurse under
- * @depth: the current depth of traversal
- * @max_depth: maximum depth to traverse, or -1 for no maximum
- * @f: the file to report to
- *
- * This provides a more flexible reports than talloc_report(). It will let you
- * specify the depth and max_depth.
- */
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
-
-/**
- * talloc_enable_null_tracking - enable tracking of top-level tallocs
- *
- * This enables tracking of the NULL memory context without enabling leak
- * reporting on exit. Useful for when you want to do your own leak reporting
- * call via talloc_report_null_full();
- */
-void talloc_enable_null_tracking(void);
-
-/**
- * talloc_disable_null_tracking - enable tracking of top-level tallocs
- *
- * This disables tracking of the NULL memory context.
- */
-void talloc_disable_null_tracking(void);
-
-/**
- * talloc_enable_leak_report - call talloc_report on program exit
- *
- * This enables calling of talloc_report(NULL, stderr) when the program
- * exits. In Samba4 this is enabled by using the --leak-report command line
- * option.
- *
- * For it to be useful, this function must be called before any other talloc
- * function as it establishes a "null context" that acts as the top of the
- * tree. If you don't call this function first then passing NULL to
- * talloc_report() or talloc_report_full() won't give you the full tree
- * printout.
- *
- * Here is a typical talloc report:
- *
- * talloc report on 'null_context' (total 267 bytes in 15 blocks)
- * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
- * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
- * iconv(UTF8,CP850) contains 42 bytes in 2 blocks
- * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
- * iconv(CP850,UTF8) contains 42 bytes in 2 blocks
- * iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
- * iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
- */
-void talloc_enable_leak_report(void);
-
-/**
- * talloc_enable_leak_report - call talloc_report_full on program exit
- *
- * This enables calling of talloc_report_full(NULL, stderr) when the program
- * exits. In Samba4 this is enabled by using the --leak-report-full command
- * line option.
- *
- * For it to be useful, this function must be called before any other talloc
- * function as it establishes a "null context" that acts as the top of the
- * tree. If you don't call this function first then passing NULL to
- * talloc_report() or talloc_report_full() won't give you the full tree
- * printout.
- *
- * Here is a typical full report:
- *
- * full talloc report on 'root' (total 18 bytes in 8 blocks)
- * p1 contains 18 bytes in 7 blocks (ref 0)
- * r1 contains 13 bytes in 2 blocks (ref 0)
- * reference to: p2
- * p2 contains 1 bytes in 1 blocks (ref 1)
- * x3 contains 1 bytes in 1 blocks (ref 0)
- * x2 contains 1 bytes in 1 blocks (ref 0)
- * x1 contains 1 bytes in 1 blocks (ref 0)
- */
-void talloc_enable_leak_report_full(void);
-
-/**
- * talloc_autofree_context - a context which will be freed at exit
- *
- * This is a handy utility function that returns a talloc context which will be
- * automatically freed on program exit. This can be used to reduce the noise in
- * memory leak reports.
- */
-void *talloc_autofree_context(void);
-
-/**
- * talloc_get_size - get the size of an allocation
- * @ctx: the talloc pointer whose allocation to measure.
- *
- * This function lets you know the amount of memory alloced so far by this
- * context. It does NOT account for subcontext memory. This can be used to
- * calculate the size of an array.
- */
-size_t talloc_get_size(const void *ctx);
-
-/**
- * talloc_find_parent_byname - find a parent of this context with this name
- * @ctx: the context whose ancestors to search
- * @name: the name to look for
- *
- * Find a parent memory context of @ctx that has the given name. This can be
- * very useful in complex programs where it may be difficult to pass all
- * information down to the level you need, but you know the structure you want
- * is a parent of another context.
- */
-void *talloc_find_parent_byname(const void *ctx, const char *name);
-
-/* The following definitions come from talloc.c */
-void *_talloc(const void *context, size_t size);
-void _talloc_set_destructor(const void *ptr, int (*destructor)(void *));
-size_t talloc_reference_count(const void *ptr);
-void *_talloc_reference(const void *context, const void *ptr);
-
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
-void *talloc_parent(const void *ptr);
-const char *talloc_parent_name(const void *ptr);
-void *_talloc_steal(const void *new_ctx, const void *ptr);
-void *_talloc_move(const void *new_ctx, const void *pptr);
-void *_talloc_zero(const void *ctx, size_t size, const char *name);
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
-void talloc_show_parents(const void *context, FILE *file);
-int talloc_is_parent(const void *context, const void *ptr);
-
-#endif /* CCAN_TALLOC_H */
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
-
- local testing of talloc routines.
-
- Copyright (C) Andrew Tridgell 2004
- Converted to ccan tests by Rusty Russell 2008
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "talloc/talloc.c"
-#include <stdbool.h>
-#include "tap/tap.h"
-
-#define torture_assert(test, expr, str) \
- ok(expr, "failure: %s [\n%s: Expression %s failed: %s\n]\n", \
- test, __location__, #expr, str)
-
-#define torture_assert_str_equal(test, arg1, arg2, desc) \
- ok(strcmp(arg1, arg2) == 0, \
- "failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
- test, __location__, arg1, arg2, desc)
-
-#define CHECK_SIZE(test, ptr, tsize) \
- ok(talloc_total_size(ptr) == (tsize), \
- "failed: %s [\nwrong '%s' tree size: got %u expected %u\n]\n", \
- test, #ptr, \
- (unsigned)talloc_total_size(ptr), \
- (unsigned)tsize)
-
-#define CHECK_BLOCKS(test, ptr, tblocks) \
- ok(talloc_total_blocks(ptr) == (tblocks), \
- "failed: %s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
- test, #ptr, \
- (unsigned)talloc_total_blocks(ptr), \
- (unsigned)tblocks)
-
-#define CHECK_PARENT(test, ptr, parent) \
- ok(talloc_parent(ptr) == (parent), \
- "failed: %s [\n'%s' has wrong parent: got %p expected %p\n]\n", \
- test, #ptr, \
- talloc_parent(ptr), \
- (parent))
-
-/*
- test references
-*/
-static bool test_ref1(void)
-{
- void *root, *p1, *p2, *ref, *r1;
-
- root = talloc_named_const(NULL, 0, "root");
- p1 = talloc_named_const(root, 1, "p1");
- p2 = talloc_named_const(p1, 1, "p2");
- talloc_named_const(p1, 1, "x1");
- talloc_named_const(p1, 2, "x2");
- talloc_named_const(p1, 3, "x3");
-
- r1 = talloc_named_const(root, 1, "r1");
- ref = talloc_reference(r1, p2);
-
- CHECK_BLOCKS("ref1", p1, 5);
- CHECK_BLOCKS("ref1", p2, 1);
- CHECK_BLOCKS("ref1", r1, 2);
-
- talloc_free(p2);
-
- CHECK_BLOCKS("ref1", p1, 5);
- CHECK_BLOCKS("ref1", p2, 1);
- CHECK_BLOCKS("ref1", r1, 1);
-
- talloc_free(p1);
-
- CHECK_BLOCKS("ref1", r1, 1);
-
- talloc_free(r1);
-
- if (talloc_reference(root, NULL)) {
- return false;
- }
-
- CHECK_BLOCKS("ref1", root, 1);
-
- CHECK_SIZE("ref1", root, 0);
-
- talloc_free(root);
- return true;
-}
-
-/*
- test references
-*/
-static bool test_ref2(void)
-{
- void *root, *p1, *p2, *ref, *r1;
-
- root = talloc_named_const(NULL, 0, "root");
- p1 = talloc_named_const(root, 1, "p1");
- talloc_named_const(p1, 1, "x1");
- talloc_named_const(p1, 1, "x2");
- talloc_named_const(p1, 1, "x3");
- p2 = talloc_named_const(p1, 1, "p2");
-
- r1 = talloc_named_const(root, 1, "r1");
- ref = talloc_reference(r1, p2);
-
- CHECK_BLOCKS("ref2", p1, 5);
- CHECK_BLOCKS("ref2", p2, 1);
- CHECK_BLOCKS("ref2", r1, 2);
-
- talloc_free(ref);
-
- CHECK_BLOCKS("ref2", p1, 5);
- CHECK_BLOCKS("ref2", p2, 1);
- CHECK_BLOCKS("ref2", r1, 1);
-
- talloc_free(p2);
-
- CHECK_BLOCKS("ref2", p1, 4);
- CHECK_BLOCKS("ref2", r1, 1);
-
- talloc_free(p1);
-
- CHECK_BLOCKS("ref2", r1, 1);
-
- talloc_free(r1);
-
- CHECK_SIZE("ref2", root, 0);
-
- talloc_free(root);
- return true;
-}
-
-/*
- test references
-*/
-static bool test_ref3(void)
-{
- void *root, *p1, *p2, *ref, *r1;
-
- root = talloc_named_const(NULL, 0, "root");
- p1 = talloc_named_const(root, 1, "p1");
- p2 = talloc_named_const(root, 1, "p2");
- r1 = talloc_named_const(p1, 1, "r1");
- ref = talloc_reference(p2, r1);
-
- CHECK_BLOCKS("ref3", p1, 2);
- CHECK_BLOCKS("ref3", p2, 2);
- CHECK_BLOCKS("ref3", r1, 1);
-
- talloc_free(p1);
-
- CHECK_BLOCKS("ref3", p2, 2);
- CHECK_BLOCKS("ref3", r1, 1);
-
- talloc_free(p2);
-
- CHECK_SIZE("ref3", root, 0);
-
- talloc_free(root);
-
- return true;
-}
-
-/*
- test references
-*/
-static bool test_ref4(void)
-{
- void *root, *p1, *p2, *ref, *r1;
-
- root = talloc_named_const(NULL, 0, "root");
- p1 = talloc_named_const(root, 1, "p1");
- talloc_named_const(p1, 1, "x1");
- talloc_named_const(p1, 1, "x2");
- talloc_named_const(p1, 1, "x3");
- p2 = talloc_named_const(p1, 1, "p2");
-
- r1 = talloc_named_const(root, 1, "r1");
- ref = talloc_reference(r1, p2);
-
- CHECK_BLOCKS("ref4", p1, 5);
- CHECK_BLOCKS("ref4", p2, 1);
- CHECK_BLOCKS("ref4", r1, 2);
-
- talloc_free(r1);
-
- CHECK_BLOCKS("ref4", p1, 5);
- CHECK_BLOCKS("ref4", p2, 1);
-
- talloc_free(p2);
-
- CHECK_BLOCKS("ref4", p1, 4);
-
- talloc_free(p1);
-
- CHECK_SIZE("ref4", root, 0);
-
- talloc_free(root);
-
- return true;
-}
-
-
-/*
- test references
-*/
-static bool test_unlink1(void)
-{
- void *root, *p1, *p2, *ref, *r1;
-
- root = talloc_named_const(NULL, 0, "root");
- p1 = talloc_named_const(root, 1, "p1");
- talloc_named_const(p1, 1, "x1");
- talloc_named_const(p1, 1, "x2");
- talloc_named_const(p1, 1, "x3");
- p2 = talloc_named_const(p1, 1, "p2");
-
- r1 = talloc_named_const(p1, 1, "r1");
- ref = talloc_reference(r1, p2);
-
- CHECK_BLOCKS("unlink", p1, 7);
- CHECK_BLOCKS("unlink", p2, 1);
- CHECK_BLOCKS("unlink", r1, 2);
-
- talloc_unlink(r1, p2);
-
- CHECK_BLOCKS("unlink", p1, 6);
- CHECK_BLOCKS("unlink", p2, 1);
- CHECK_BLOCKS("unlink", r1, 1);
-
- talloc_free(p1);
-
- CHECK_SIZE("unlink", root, 0);
-
- talloc_free(root);
-
- return true;
-}
-
-static int fail_destructor(void *ptr)
-{
- return -1;
-}
-
-/*
- miscellaneous tests to try to get a higher test coverage percentage
-*/
-static bool test_misc(void)
-{
- void *root, *p1;
- char *p2;
- double *d;
- const char *name;
-
- root = talloc_new(NULL);
-
- p1 = talloc_size(root, 0x7fffffff);
- torture_assert("misc", !p1, "failed: large talloc allowed\n");
-
- p1 = talloc_strdup(root, "foo");
- talloc_increase_ref_count(p1);
- talloc_increase_ref_count(p1);
- talloc_increase_ref_count(p1);
- CHECK_BLOCKS("misc", p1, 1);
- CHECK_BLOCKS("misc", root, 2);
- talloc_free(p1);
- CHECK_BLOCKS("misc", p1, 1);
- CHECK_BLOCKS("misc", root, 2);
- talloc_unlink(NULL, p1);
- CHECK_BLOCKS("misc", p1, 1);
- CHECK_BLOCKS("misc", root, 2);
- p2 = talloc_strdup(p1, "foo");
- torture_assert("misc", talloc_unlink(root, p2) == -1,
- "failed: talloc_unlink() of non-reference context should return -1\n");
- torture_assert("misc", talloc_unlink(p1, p2) == 0,
- "failed: talloc_unlink() of parent should succeed\n");
- talloc_free(p1);
- CHECK_BLOCKS("misc", p1, 1);
- CHECK_BLOCKS("misc", root, 2);
-
- name = talloc_set_name(p1, "my name is %s", "foo");
- torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
- "failed: wrong name after talloc_set_name(my name is foo)");
- CHECK_BLOCKS("misc", p1, 2);
- CHECK_BLOCKS("misc", root, 3);
-
- talloc_set_name_const(p1, NULL);
- torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
- "failed: wrong name after talloc_set_name(NULL)");
- CHECK_BLOCKS("misc", p1, 2);
- CHECK_BLOCKS("misc", root, 3);
-
- torture_assert("misc", talloc_free(NULL) == -1,
- "talloc_free(NULL) should give -1\n");
-
- talloc_set_destructor(p1, fail_destructor);
- torture_assert("misc", talloc_free(p1) == -1,
- "Failed destructor should cause talloc_free to fail\n");
- talloc_set_destructor(p1, NULL);
-
-
- p2 = (char *)talloc_zero_size(p1, 20);
- torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
- talloc_free(p2);
-
- torture_assert("misc", talloc_strdup(root, NULL) == NULL,
- "failed: strdup on NULL should give NULL\n");
-
- p2 = talloc_strndup(p1, "foo", 2);
- torture_assert("misc", strcmp("fo", p2) == 0,
- "strndup doesn't work\n");
- p2 = talloc_asprintf_append(p2, "o%c", 'd');
- torture_assert("misc", strcmp("food", p2) == 0,
- "talloc_asprintf_append doesn't work\n");
- CHECK_BLOCKS("misc", p2, 1);
- CHECK_BLOCKS("misc", p1, 3);
-
- p2 = talloc_asprintf_append(NULL, "hello %s", "world");
- torture_assert("misc", strcmp("hello world", p2) == 0,
- "talloc_asprintf_append doesn't work\n");
- CHECK_BLOCKS("misc", p2, 1);
- CHECK_BLOCKS("misc", p1, 3);
- talloc_free(p2);
-
- d = talloc_array(p1, double, 0x20000000);
- torture_assert("misc", !d, "failed: integer overflow not detected\n");
-
- d = talloc_realloc(p1, d, double, 0x20000000);
- torture_assert("misc", !d, "failed: integer overflow not detected\n");
-
- talloc_free(p1);
- CHECK_BLOCKS("misc", root, 1);
-
- p1 = talloc_named(root, 100, "%d bytes", 100);
- CHECK_BLOCKS("misc", p1, 2);
- CHECK_BLOCKS("misc", root, 3);
- talloc_unlink(root, p1);
-
- p1 = talloc_init("%d bytes", 200);
- p2 = talloc_asprintf(p1, "my test '%s'", "string");
- torture_assert_str_equal("misc", p2, "my test 'string'",
- "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
- CHECK_BLOCKS("misc", p1, 3);
- CHECK_SIZE("misc", p2, 17);
- CHECK_BLOCKS("misc", root, 1);
- talloc_unlink(NULL, p1);
-
- p1 = talloc_named_const(root, 10, "p1");
- p2 = (char *)talloc_named_const(root, 20, "p2");
- (void)talloc_reference(p1, p2);
- talloc_unlink(root, p2);
- CHECK_BLOCKS("misc", p2, 1);
- CHECK_BLOCKS("misc", p1, 2);
- CHECK_BLOCKS("misc", root, 3);
- talloc_unlink(p1, p2);
- talloc_unlink(root, p1);
-
- p1 = talloc_named_const(root, 10, "p1");
- p2 = (char *)talloc_named_const(root, 20, "p2");
- (void)talloc_reference(NULL, p2);
- talloc_unlink(root, p2);
- CHECK_BLOCKS("misc", p2, 1);
- CHECK_BLOCKS("misc", p1, 1);
- CHECK_BLOCKS("misc", root, 2);
- talloc_unlink(NULL, p2);
- talloc_unlink(root, p1);
-
- /* Test that talloc_unlink is a no-op */
-
- torture_assert("misc", talloc_unlink(root, NULL) == -1,
- "failed: talloc_unlink(root, NULL) == -1\n");
-
- CHECK_SIZE("misc", root, 0);
-
- talloc_free(root);
-
- CHECK_SIZE("misc", NULL, 0);
-
- talloc_enable_leak_report();
- talloc_enable_leak_report_full();
-
- return true;
-}
-
-
-/*
- test realloc
-*/
-static bool test_realloc(void)
-{
- void *root, *p1, *p2;
-
- root = talloc_new(NULL);
-
- p1 = talloc_size(root, 10);
- CHECK_SIZE("realloc", p1, 10);
-
- p1 = talloc_realloc_size(NULL, p1, 20);
- CHECK_SIZE("realloc", p1, 20);
-
- talloc_new(p1);
-
- p2 = talloc_realloc_size(p1, NULL, 30);
-
- talloc_new(p1);
-
- p2 = talloc_realloc_size(p1, p2, 40);
-
- CHECK_SIZE("realloc", p2, 40);
- CHECK_SIZE("realloc", root, 60);
- CHECK_BLOCKS("realloc", p1, 4);
-
- p1 = talloc_realloc_size(NULL, p1, 20);
- CHECK_SIZE("realloc", p1, 60);
-
- talloc_increase_ref_count(p2);
- torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
- "failed: talloc_realloc() on a referenced pointer should fail\n");
- CHECK_BLOCKS("realloc", p1, 4);
-
- talloc_realloc_size(NULL, p2, 0);
- talloc_realloc_size(NULL, p2, 0);
- CHECK_BLOCKS("realloc", p1, 3);
-
- torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
- "failed: oversize talloc should fail\n");
-
- talloc_realloc_size(NULL, p1, 0);
-
- CHECK_BLOCKS("realloc", root, 1);
- CHECK_SIZE("realloc", root, 0);
-
- talloc_free(root);
-
- return true;
-}
-
-/*
- test realloc with a child
-*/
-static bool test_realloc_child(void)
-{
- void *root;
- struct el2 {
- const char *name;
- } *el2;
- struct el1 {
- int count;
- struct el2 **list, **list2, **list3;
- } *el1;
-
- root = talloc_new(NULL);
-
- el1 = talloc(root, struct el1);
- el1->list = talloc(el1, struct el2 *);
- el1->list[0] = talloc(el1->list, struct el2);
- el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
-
- el1->list2 = talloc(el1, struct el2 *);
- el1->list2[0] = talloc(el1->list2, struct el2);
- el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
-
- el1->list3 = talloc(el1, struct el2 *);
- el1->list3[0] = talloc(el1->list3, struct el2);
- el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
-
- el2 = talloc(el1->list, struct el2);
- el2 = talloc(el1->list2, struct el2);
- el2 = talloc(el1->list3, struct el2);
-
- el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
- el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
- el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
-
- talloc_free(root);
-
- return true;
-}
-
-/*
- test type checking
-*/
-static bool test_type(void)
-{
- void *root;
- struct el1 {
- int count;
- };
- struct el2 {
- int count;
- };
- struct el1 *el1;
-
- root = talloc_new(NULL);
-
- el1 = talloc(root, struct el1);
-
- el1->count = 1;
-
- torture_assert("type", talloc_get_type(el1, struct el1) == el1,
- "type check failed on el1\n");
- torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
- "type check failed on el1 with el2\n");
- talloc_set_type(el1, struct el2);
- torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
- "type set failed on el1 with el2\n");
-
- talloc_free(root);
-
- return true;
-}
-
-/*
- test steal
-*/
-static bool test_steal(void)
-{
- void *root, *p1, *p2;
-
- root = talloc_new(NULL);
-
- p1 = talloc_array(root, char, 10);
- CHECK_SIZE("steal", p1, 10);
-
- p2 = talloc_realloc(root, NULL, char, 20);
- CHECK_SIZE("steal", p1, 10);
- CHECK_SIZE("steal", root, 30);
-
- torture_assert("steal", talloc_steal(p1, NULL) == NULL,
- "failed: stealing NULL should give NULL\n");
-
- torture_assert("steal", talloc_steal(p1, p1) == p1,
- "failed: stealing to ourselves is a nop\n");
- CHECK_BLOCKS("steal", root, 3);
- CHECK_SIZE("steal", root, 30);
-
- talloc_steal(NULL, p1);
- talloc_steal(NULL, p2);
- CHECK_BLOCKS("steal", root, 1);
- CHECK_SIZE("steal", root, 0);
-
- talloc_free(p1);
- talloc_steal(root, p2);
- CHECK_BLOCKS("steal", root, 2);
- CHECK_SIZE("steal", root, 20);
-
- talloc_free(p2);
-
- CHECK_BLOCKS("steal", root, 1);
- CHECK_SIZE("steal", root, 0);
-
- talloc_free(root);
-
- p1 = talloc_size(NULL, 3);
- CHECK_SIZE("steal", NULL, 3);
- talloc_free(p1);
-
- return true;
-}
-
-/*
- test move
-*/
-static bool test_move(void)
-{
- void *root;
- struct t_move {
- char *p;
- int *x;
- } *t1, *t2;
-
- root = talloc_new(NULL);
-
- t1 = talloc(root, struct t_move);
- t2 = talloc(root, struct t_move);
- t1->p = talloc_strdup(t1, "foo");
- t1->x = talloc(t1, int);
- *t1->x = 42;
-
- t2->p = talloc_move(t2, &t1->p);
- t2->x = talloc_move(t2, &t1->x);
- torture_assert("move", t1->p == NULL && t1->x == NULL &&
- strcmp(t2->p, "foo") == 0 && *t2->x == 42,
- "talloc move failed");
-
- talloc_free(root);
-
- return true;
-}
-
-/*
- test talloc_realloc_fn
-*/
-static bool test_realloc_fn(void)
-{
- void *root, *p1;
-
- root = talloc_new(NULL);
-
- p1 = talloc_realloc_fn(root, NULL, 10);
- CHECK_BLOCKS("realloc_fn", root, 2);
- CHECK_SIZE("realloc_fn", root, 10);
- p1 = talloc_realloc_fn(root, p1, 20);
- CHECK_BLOCKS("realloc_fn", root, 2);
- CHECK_SIZE("realloc_fn", root, 20);
- p1 = talloc_realloc_fn(root, p1, 0);
- CHECK_BLOCKS("realloc_fn", root, 1);
- CHECK_SIZE("realloc_fn", root, 0);
-
- talloc_free(root);
-
- return true;
-}
-
-
-static bool test_unref_reparent(void)
-{
- void *root, *p1, *p2, *c1;
-
- root = talloc_named_const(NULL, 0, "root");
- p1 = talloc_named_const(root, 1, "orig parent");
- p2 = talloc_named_const(root, 1, "parent by reference");
-
- c1 = talloc_named_const(p1, 1, "child");
- talloc_reference(p2, c1);
-
- CHECK_PARENT("unref_reparent", c1, p1);
-
- talloc_free(p1);
-
- CHECK_PARENT("unref_reparent", c1, p2);
-
- talloc_unlink(p2, c1);
-
- CHECK_SIZE("unref_reparent", root, 1);
-
- talloc_free(p2);
- talloc_free(root);
-
- return true;
-}
-
-static bool test_lifeless(void)
-{
- void *top = talloc_new(NULL);
- char *parent, *child;
- void *child_owner = talloc_new(NULL);
-
- parent = talloc_strdup(top, "parent");
- child = talloc_strdup(parent, "child");
- (void)talloc_reference(child, parent);
- (void)talloc_reference(child_owner, child);
- talloc_unlink(top, parent);
- talloc_free(child);
- talloc_free(top);
- talloc_free(child_owner);
- talloc_free(child);
-
- return true;
-}
-
-static int loop_destructor_count;
-
-static int test_loop_destructor(char *ptr)
-{
- loop_destructor_count++;
- return 0;
-}
-
-static bool test_loop(void)
-{
- void *top = talloc_new(NULL);
- char *parent;
- struct req1 {
- char *req2, *req3;
- } *req1;
-
- parent = talloc_strdup(top, "parent");
- req1 = talloc(parent, struct req1);
- req1->req2 = talloc_strdup(req1, "req2");
- talloc_set_destructor(req1->req2, test_loop_destructor);
- req1->req3 = talloc_strdup(req1, "req3");
- (void)talloc_reference(req1->req3, req1);
- talloc_free(parent);
- talloc_free(top);
-
- torture_assert("loop", loop_destructor_count == 1,
- "FAILED TO FIRE LOOP DESTRUCTOR\n");
- loop_destructor_count = 0;
-
- return true;
-}
-
-static int fail_destructor_str(char *ptr)
-{
- return -1;
-}
-
-static bool test_free_parent_deny_child(void)
-{
- void *top = talloc_new(NULL);
- char *level1;
- char *level2;
- char *level3;
-
- level1 = talloc_strdup(top, "level1");
- level2 = talloc_strdup(level1, "level2");
- level3 = talloc_strdup(level2, "level3");
-
- talloc_set_destructor(level3, fail_destructor_str);
- talloc_free(level1);
- talloc_set_destructor(level3, NULL);
-
- CHECK_PARENT("free_parent_deny_child", level3, top);
-
- talloc_free(top);
-
- return true;
-}
-
-static bool test_talloc_ptrtype(void)
-{
- void *top = talloc_new(NULL);
- struct struct1 {
- int foo;
- int bar;
- } *s1, *s2, **s3, ***s4;
- const char *location1;
- const char *location2;
- const char *location3;
- const char *location4;
-
- s1 = talloc_ptrtype(top, s1);location1 = __location__;
-
- ok1(talloc_get_size(s1) == sizeof(struct struct1));
-
- ok1(strcmp(location1, talloc_get_name(s1)) == 0);
-
- s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
-
- ok1(talloc_get_size(s2) == (sizeof(struct struct1) * 10));
-
- ok1(strcmp(location2, talloc_get_name(s2)) == 0);
-
- s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
-
- ok1(talloc_get_size(s3) == (sizeof(struct struct1 *) * 10));
-
- torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
- "talloc_array_ptrtype() sets the wrong name");
-
- s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
-
- ok1(talloc_get_size(s4) == (sizeof(struct struct1 **) * 10));
-
- torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
- "talloc_array_ptrtype() sets the wrong name");
-
- talloc_free(top);
-
- return true;
-}
-
-static int _test_talloc_free_in_destructor(void **ptr)
-{
- talloc_free(*ptr);
- return 0;
-}
-
-static bool test_talloc_free_in_destructor(void)
-{
- void *level0;
- void *level1;
- void *level2;
- void *level3;
- void *level4;
- void **level5;
-
- level0 = talloc_new(NULL);
- level1 = talloc_new(level0);
- level2 = talloc_new(level1);
- level3 = talloc_new(level2);
- level4 = talloc_new(level3);
- level5 = talloc(level4, void *);
-
- *level5 = level3;
- (void)talloc_reference(level0, level3);
- (void)talloc_reference(level3, level3);
- (void)talloc_reference(level5, level3);
-
- talloc_set_destructor(level5, _test_talloc_free_in_destructor);
-
- talloc_free(level1);
-
- talloc_free(level0);
-
- return true;
-}
-
-static bool test_autofree(void)
-{
- /* autofree test would kill smbtorture */
- void *p;
- p = talloc_autofree_context();
- talloc_free(p);
-
- p = talloc_autofree_context();
- talloc_free(p);
-
- return true;
-}
-
-struct torture_context;
-static bool torture_local_talloc(struct torture_context *tctx)
-{
- bool ret = true;
-
- setlinebuf(stdout);
-
- talloc_disable_null_tracking();
- talloc_enable_null_tracking();
-
- ret &= test_ref1();
- ret &= test_ref2();
- ret &= test_ref3();
- ret &= test_ref4();
- ret &= test_unlink1();
- ret &= test_misc();
- ret &= test_realloc();
- ret &= test_realloc_child();
- ret &= test_steal();
- ret &= test_move();
- ret &= test_unref_reparent();
- ret &= test_realloc_fn();
- ret &= test_type();
- ret &= test_lifeless();
- ret &= test_loop();
- ret &= test_free_parent_deny_child();
- ret &= test_talloc_ptrtype();
- ret &= test_talloc_free_in_destructor();
- ret &= test_autofree();
-
- return ret;
-}
-
-int main(void)
-{
- plan_tests(134);
-
- torture_local_talloc(NULL);
- return exit_status();
-}
-
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * tap - Test Anything Protocol
- *
- * The tap package produces simple-to-parse mainly-human-readable test
- * output to assist in the writing of test cases. It is based on the
- * (now-defunct) libtap, which is based on Perl's CPAN TAP module. Its
- * output can be parsed by a harness such as CPAN's Prove.
- *
- * CCAN testcases are expected to output the TAP format, usually using
- * this package.
- *
- * For more information about TAP, see:
- * http://en.wikipedia.org/wiki/Test_Anything_Protocol
- *
- * Based on the original libtap, Copyright (c) 2004 Nik Clayton.
- *
- * Example:
- * #include <string.h>
- * #include "tap/tap.h"
- *
- * // Run some simple (but overly chatty) tests on strcmp().
- * int main(int argc, char *argv[])
- * {
- * const char a[] = "a", another_a[] = "a";
- * const char b[] = "b";
- * const char ab[] = "ab";
- *
- * plan_tests(4);
- * diag("Testing different pointers (%p/%p) with same contents",
- * a, another_a);
- * ok1(strcmp(a, another_a) == 0);
- *
- * diag("'a' comes before 'b'");
- * ok1(strcmp(a, b) < 0);
- * ok1(strcmp(b, a) > 0);
- *
- * diag("'ab' comes after 'a'");
- * ok1(strcmp(ab, a) > 0);
- * return exit_status();
- * }
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0)
- return 0;
-
- if (strcmp(argv[1], "license") == 0)
- return "BSD";
-
- return 1;
-}
+++ /dev/null
-.Dd December 20, 2004
-.Os
-.Dt TAP 3
-.Sh NAME
-.Nm tap
-.Nd write tests that implement the Test Anything Protocol
-.Sh SYNOPSIS
-.In tap.h
-.Sh DESCRIPTION
-The
-.Nm
-library provides functions for writing test scripts that produce output
-consistent with the Test Anything Protocol. A test harness that parses
-this protocol can run these tests and produce useful reports indicating
-their success or failure.
-.Ss PRINTF STRINGS
-In the descriptions that follow, for any function that takes as the
-last two parameters
-.Dq Fa char * , Fa ...
-it can be assumed that the
-.Fa char *
-is a
-.Fn printf
--like format string, and the optional arguments are values to be placed
-in that string.
-.Ss TEST PLANS
-.Bl -tag -width indent
-.It Xo
-.Ft void
-.Fn plan_tests "unsigned int"
-.Xc
-.It Xo
-.Ft void
-.Fn plan_no_plan "void"
-.Xc
-.It Xo
-.Ft void
-.Fn plan_skip_all "char *" "..."
-.Xc
-.El
-.Pp
-You must first specify a test plan. This indicates how many tests you
-intend to run, and allows the test harness to notice if any tests were
-missed, or if the test program exited prematurely.
-.Pp
-To do this, use
-.Fn plan_tests .
-The function will cause your program to exit prematurely if you specify
-0 tests.
-.Pp
-In some situations you may not know how many tests you will be running, or
-you are developing your test program, and do not want to update the
-.Fn plan_tests
-parameter every time you make a change. For those situations use
-.Fn plan_no_plan .
-It indicates to the test harness that an indeterminate number
-of tests will be run.
-.Pp
-Both
-.Fn plan_tests
-and
-.Fn plan_no_plan
-will cause your test program to exit prematurely with a diagnostic
-message if they are called more than once.
-.Pp
-If your test program detects at run time that some required functionality
-is missing (for example, it relies on a database connection which is not
-present, or a particular configuration option that has not been included
-in the running kernel) use
-.Fn plan_skip_all ,
-passing as parameters a string to display indicating the reason for skipping
-the tests.
-.Ss SIMPLE TESTS
-.Bl -tag -width indent
-.It Xo
-.Ft unsigned int
-.Fn ok "expression" "char *" "..."
-.Xc
-.It Xo
-.Ft unsigned int
-.Fn ok1 "expression"
-.Xc
-.It Xo
-.Ft unsigned int
-.Fn pass "char *" "..."
-.Xc
-.It Xo
-.Ft unsigned int
-.Fn fail "char *" "..."
-.Xc
-.El
-.Pp
-Tests are implemented as expressions checked by calls to the
-.Fn ok
-and
-.Fn ok1
-macros. In both cases
-.Fa expression
-should evaluate to true if the test succeeded.
-.Pp
-.Fn ok
-allows you to specify a name, or comment, describing the test which will
-be included in the output.
-.Fn ok1
-is for those times when the expression to be tested is self
-explanatory and does not need an associated comment. In those cases
-the test expression becomes the comment.
-.Pp
-These four calls are equivalent:
-.Bd -literal -offset indent
-int i = 5;
-
-ok(i == 5, "i equals 5"); /* Overly verbose */
-ok(i == 5, "i equals %d", i); /* Just to demonstrate printf-like
- behaviour of the test name */
-ok(i == 5, "i == 5"); /* Needless repetition */
-ok1(i == 5); /* Just right */
-.Ed
-.Pp
-It is good practice to ensure that the test name describes the meaning
-behind the test rather than what you are testing. Viz
-.Bd -literal -offset indent
-ok(db != NULL, "db is not NULL"); /* Not bad, but */
-ok(db != NULL, "Database conn. succeeded"); /* this is better */
-.Ed
-.Pp
-.Fn ok
-and
-.Fn ok1
-return 1 if the expression evaluated to true, and 0 if it evaluated to
-false. This lets you chain calls from
-.Fn ok
-to
-.Fn diag
-to only produce diagnostic output if the test failed. For example, this
-code will include diagnostic information about why the database connection
-failed, but only if the test failed.
-.Bd -literal -offset indent
-if (!ok(db != NULL, "Database conn. succeeded")) {
- diag("Database error code: %d", dberrno);
-}
-.Ed
-.Pp
-You also have
-.Fn pass
-and
-.Fn fail .
-From the Test::More documentation:
-.Bd -literal -offset indent
-Sometimes you just want to say that the tests have passed.
-Usually the case is you've got some complicated condition
-that is difficult to wedge into an ok(). In this case,
-you can simply use pass() (to declare the test ok) or fail
-(for not ok).
-
-Use these very, very, very sparingly.
-.Ed
-.Pp
-These are synonyms for ok(1, ...) and ok(0, ...).
-.Ss SKIPPING TESTS
-.Bl -tag -width indent
-.It Xo
-.Ft void
-.Fn skip "unsigned int" "char *" "..."
-.Xc
-.It Xo
-.Fn skip_if "expression" "unsigned int" "char *" "..."
-.Xc
-.El
-.Pp
-Sets of tests can be skipped. Ordinarily you would do this because
-the test can't be run in this particular testing environment.
-.Pp
-For example, suppose some tests should be run as root. If the test is
-not being run as root then the tests should be skipped. In this
-implementation, skipped tests are flagged as being ok, with a special
-message indicating that they were skipped. It is your responsibility
-to ensure that the number of tests skipped (the first parameter to
-.Fn skip )
-is correct for the number of tests to skip.
-.Pp
-One way of implementing this is with a
-.Dq do { } while(0);
-loop, or an
-.Dq if( ) { } else { }
-construct, to ensure that there are no additional side effects from the
-skipped tests.
-.Bd -literal -offset indent
-if(getuid() != 0) {
- skip(1, "because test only works as root");
-} else {
- ok(do_something_as_root() == 0, "Did something as root");
-}
-.Ed
-.Pp
-A convenient macro is provided to assist with this. The previous example could
-be re-written as follows.
-.Bd -literal -offset indent
-skip_if(getuid() != 0, 1, "because test only works as root") {
- ok(do_something_as_root() == 0, "Did something as root");
-}
-.Ed
-.Ss MARKING TESTS AS Dq TODO
-.Bl -tag -width indent
-.It Xo
-.Ft void
-.Fn todo_start "char *" "..."
-.Xc
-.It Xo
-.Ft void
-.Fn todo_end "void"
-.Xc
-.El
-.Pp
-Sets of tests can be flagged as being
-.Dq TODO .
-These are tests that you expect to fail, probably because you haven't
-fixed a bug, or finished a new feature yet. These tests will still be
-run, but with additional output that indicates that they are expected
-to fail. Should a test start to succeed unexpectedly, tools like
-.Xr prove 1
-will indicate this, and you can move the test out of the todo
-block. This is much more useful than simply commenting out (or
-.Dq #ifdef 0 ... #endif )
-the tests.
-.Bd -literal -offset indent
-todo_start("dwim() not returning true yet");
-
-ok(dwim(), "Did what the user wanted");
-
-todo_end();
-.Ed
-.Pp
-Should
-.Fn dwim
-ever start succeeding you will know about it as soon as you run the
-tests. Note that
-.Em unlike
-the
-.Fn skip_*
-family, additional code between
-.Fn todo_start
-and
-.Fn todo_end
-.Em is
-executed.
-.Ss SKIP vs. TODO
-From the Test::More documentation;
-.Bd -literal -offset indent
-If it's something the user might not be able to do, use SKIP.
-This includes optional modules that aren't installed, running
-under an OS that doesn't have some feature (like fork() or
-symlinks), or maybe you need an Internet connection and one
-isn't available.
-
-If it's something the programmer hasn't done yet, use TODO.
-This is for any code you haven't written yet, or bugs you have
-yet to fix, but want to put tests in your testing script
-(always a good idea).
-.Ed
-.Ss DIAGNOSTIC OUTPUT
-.Bl -tag -width indent
-.It Xo
-.Fr void
-.Fn diag "char *" "..."
-.Xc
-.El
-.Pp
-If your tests need to produce diagnostic output, use
-.Fn diag .
-It ensures that the output will not be considered by the TAP test harness.
-.Fn diag
-adds the necessary trailing
-.Dq \en
-for you.
-.Bd -literal -offset indent
-diag("Expected return code 0, got return code %d", rcode);
-.Ed
-.Ss EXIT STATUS
-.Bl -tag -width indent
-.It Xo
-.Fr int
-.Fn exit_status void
-.Xc
-.El
-.Pp
-For maximum compatability your test program should return a particular
-exit code. This is calculated by
-.Fn exit_status
-so it is sufficient to always return from
-.Fn main
-with either
-.Dq return exit_status();
-or
-.Dq exit(exit_status());
-as appropriate.
-.Sh EXAMPLES
-The
-.Pa tests
-directory in the source distribution contains numerous tests of
-.Nm
-functionality, written using
-.Nm .
-Examine them for examples of how to construct test suites.
-.Sh COMPATABILITY
-.Nm
-strives to be compatible with the Perl Test::More and Test::Harness
-modules. The test suite verifies that
-.Nm
-is bug-for-bug compatible with their behaviour. This is why some
-functions which would more naturally return nothing return constant
-values.
-.Pp
-If the
-.Lb libpthread
-is found at compile time,
-.Nm
-.Em should
-be thread safe. Indications to the contrary (and test cases that expose
-incorrect behaviour) are very welcome.
-.Sh SEE ALSO
-.Xr Test::More 1 ,
-.Xr Test::Harness 1 ,
-.Xr prove 1
-.Sh STANDARDS
-.Nm
-requires a
-.St -isoC-99
-compiler. Some of the
-.Nm
-functionality is implemented as variadic macros, and that functionality
-was not formally codified until C99. Patches to use
-.Nm
-with earlier compilers that have their own implementation of variadic
-macros will be gratefully received.
-.Sh HISTORY
-.Nm
-was written to help improve the quality and coverage of the FreeBSD
-regression test suite, and released in the hope that others find it
-a useful tool to help improve the quality of their code.
-.Sh AUTHORS
-.An "Nik Clayton" Aq nik@ngo.org.uk ,
-.Aq nik@FreeBSD.org
-.Pp
-.Nm
-would not exist without the efforts of
-.An "Michael G Schwern" Aq schqern@pobox.com ,
-.An "Andy Lester" Aq andy@petdance.com ,
-and the countless others who have worked on the Perl QA programme.
-.Sh BUGS
-Ideally, running the tests would have no side effects on the behaviour
-of the application you are testing. However, it is not always possible
-to avoid them. The following side effects of using
-.Nm
-are known.
-.Bl -bullet -offset indent
-.It
-stdout is set to unbuffered mode after calling any of the
-.Fn plan_*
-functions.
-.El
+++ /dev/null
-/*-
- * Copyright (c) 2004 Nik Clayton
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#define _GNU_SOURCE
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "tap.h"
-
-static int no_plan = 0;
-static int skip_all = 0;
-static int have_plan = 0;
-static unsigned int test_count = 0; /* Number of tests that have been run */
-static unsigned int e_tests = 0; /* Expected number of tests to run */
-static unsigned int failures = 0; /* Number of tests that failed */
-static char *todo_msg = NULL;
-static char *todo_msg_fixed = "libtap malloc issue";
-static int todo = 0;
-static int test_died = 0;
-
-/* Encapsulate the pthread code in a conditional. In the absence of
- libpthread the code does nothing */
-#ifdef HAVE_LIBPTHREAD
-#include <pthread.h>
-static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
-# define LOCK pthread_mutex_lock(&M)
-# define UNLOCK pthread_mutex_unlock(&M)
-#else
-# define LOCK
-# define UNLOCK
-#endif
-
-static void
-_expected_tests(unsigned int tests)
-{
-
- printf("1..%d\n", tests);
- e_tests = tests;
-}
-
-static void
-diagv(char *fmt, va_list ap)
-{
- fputs("# ", stderr);
- vfprintf(stderr, fmt, ap);
- fputs("\n", stderr);
-}
-
-static void
-_diag(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- diagv(fmt, ap);
- va_end(ap);
-}
-
-/*
- * Generate a test result.
- *
- * ok -- boolean, indicates whether or not the test passed.
- * test_name -- the name of the test, may be NULL
- * test_comment -- a comment to print afterwards, may be NULL
- */
-unsigned int
-_gen_result(int ok, const char *func, char *file, unsigned int line,
- char *test_name, ...)
-{
- va_list ap;
- char *local_test_name = NULL;
- char *c;
- int name_is_digits;
-
- LOCK;
-
- test_count++;
-
- /* Start by taking the test name and performing any printf()
- expansions on it */
- if(test_name != NULL) {
- va_start(ap, test_name);
- vasprintf(&local_test_name, test_name, ap);
- va_end(ap);
-
- /* Make sure the test name contains more than digits
- and spaces. Emit an error message and exit if it
- does */
- if(local_test_name) {
- name_is_digits = 1;
- for(c = local_test_name; *c != '\0'; c++) {
- if(!isdigit(*c) && !isspace(*c)) {
- name_is_digits = 0;
- break;
- }
- }
-
- if(name_is_digits) {
- _diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name);
- _diag(" Very confusing.");
- }
- }
- }
-
- if(!ok) {
- printf("not ");
- failures++;
- }
-
- printf("ok %d", test_count);
-
- if(test_name != NULL) {
- printf(" - ");
-
- /* Print the test name, escaping any '#' characters it
- might contain */
- if(local_test_name != NULL) {
- flockfile(stdout);
- for(c = local_test_name; *c != '\0'; c++) {
- if(*c == '#')
- fputc('\\', stdout);
- fputc((int)*c, stdout);
- }
- funlockfile(stdout);
- } else { /* vasprintf() failed, use a fixed message */
- printf("%s", todo_msg_fixed);
- }
- }
-
- /* If we're in a todo_start() block then flag the test as being
- TODO. todo_msg should contain the message to print at this
- point. If it's NULL then asprintf() failed, and we should
- use the fixed message.
-
- This is not counted as a failure, so decrement the counter if
- the test failed. */
- if(todo) {
- printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
- if(!ok)
- failures--;
- }
-
- printf("\n");
-
- if(!ok)
- _diag(" Failed %stest (%s:%s() at line %d)",
- todo ? "(TODO) " : "", file, func, line);
-
- free(local_test_name);
-
- UNLOCK;
-
- /* We only care (when testing) that ok is positive, but here we
- specifically only want to return 1 or 0 */
- return ok ? 1 : 0;
-}
-
-/*
- * Cleanup at the end of the run, produce any final output that might be
- * required.
- */
-static void
-_cleanup(void)
-{
-
- LOCK;
-
- /* If plan_no_plan() wasn't called, and we don't have a plan,
- and we're not skipping everything, then something happened
- before we could produce any output */
- if(!no_plan && !have_plan && !skip_all) {
- _diag("Looks like your test died before it could output anything.");
- UNLOCK;
- return;
- }
-
- if(test_died) {
- _diag("Looks like your test died just after %d.", test_count);
- UNLOCK;
- return;
- }
-
-
- /* No plan provided, but now we know how many tests were run, and can
- print the header at the end */
- if(!skip_all && (no_plan || !have_plan)) {
- printf("1..%d\n", test_count);
- }
-
- if((have_plan && !no_plan) && e_tests < test_count) {
- _diag("Looks like you planned %d tests but ran %d extra.",
- e_tests, test_count - e_tests);
- UNLOCK;
- return;
- }
-
- if((have_plan || !no_plan) && e_tests > test_count) {
- _diag("Looks like you planned %d tests but only ran %d.",
- e_tests, test_count);
- if(failures) {
- _diag("Looks like you failed %d tests of %d run.",
- failures, test_count);
- }
- UNLOCK;
- return;
- }
-
- if(failures)
- _diag("Looks like you failed %d tests of %d.",
- failures, test_count);
-
- UNLOCK;
-}
-
-/*
- * Initialise the TAP library. Will only do so once, however many times it's
- * called.
- */
-static void
-_tap_init(void)
-{
- static int run_once = 0;
-
- if(!run_once) {
- atexit(_cleanup);
-
- /* stdout needs to be unbuffered so that the output appears
- in the same place relative to stderr output as it does
- with Test::Harness */
- setbuf(stdout, 0);
- run_once = 1;
- }
-}
-
-/*
- * Note that there's no plan.
- */
-void
-plan_no_plan(void)
-{
-
- LOCK;
-
- _tap_init();
-
- if(have_plan != 0) {
- fprintf(stderr, "You tried to plan twice!\n");
- test_died = 1;
- UNLOCK;
- exit(255);
- }
-
- have_plan = 1;
- no_plan = 1;
-
- UNLOCK;
-}
-
-/*
- * Note that the plan is to skip all tests
- */
-void
-plan_skip_all(char *reason)
-{
-
- LOCK;
-
- _tap_init();
-
- skip_all = 1;
-
- printf("1..0");
-
- if(reason != NULL)
- printf(" # Skip %s", reason);
-
- printf("\n");
-
- UNLOCK;
-}
-
-/*
- * Note the number of tests that will be run.
- */
-void
-plan_tests(unsigned int tests)
-{
-
- LOCK;
-
- _tap_init();
-
- if(have_plan != 0) {
- fprintf(stderr, "You tried to plan twice!\n");
- test_died = 1;
- UNLOCK;
- exit(255);
- }
-
- if(tests == 0) {
- fprintf(stderr, "You said to run 0 tests! You've got to run something.\n");
- test_died = 1;
- UNLOCK;
- exit(255);
- }
-
- have_plan = 1;
-
- _expected_tests(tests);
-
- UNLOCK;
-}
-
-void
-diag(char *fmt, ...)
-{
- va_list ap;
-
- LOCK;
-
- va_start(ap, fmt);
- diagv(fmt, ap);
- va_end(ap);
-
- UNLOCK;
-}
-
-void
-skip(unsigned int n, char *fmt, ...)
-{
- va_list ap;
- char *skip_msg;
-
- LOCK;
-
- va_start(ap, fmt);
- vasprintf(&skip_msg, fmt, ap);
- va_end(ap);
-
- while(n-- > 0) {
- test_count++;
- printf("ok %d # skip %s\n", test_count,
- skip_msg != NULL ?
- skip_msg : "libtap():malloc() failed");
- }
-
- free(skip_msg);
-
- UNLOCK;
-}
-
-void
-todo_start(char *fmt, ...)
-{
- va_list ap;
-
- LOCK;
-
- va_start(ap, fmt);
- vasprintf(&todo_msg, fmt, ap);
- va_end(ap);
-
- todo = 1;
-
- UNLOCK;
-}
-
-void
-todo_end(void)
-{
-
- LOCK;
-
- todo = 0;
- free(todo_msg);
-
- UNLOCK;
-}
-
-int
-exit_status(void)
-{
- int r;
-
- LOCK;
-
- /* If there's no plan, just return the number of failures */
- if(no_plan || !have_plan) {
- UNLOCK;
- return failures;
- }
-
- /* Ran too many tests? Return the number of tests that were run
- that shouldn't have been */
- if(e_tests < test_count) {
- r = test_count - e_tests;
- UNLOCK;
- return r;
- }
-
- /* Return the number of tests that failed + the number of tests
- that weren't run */
- r = failures + e_tests - test_count;
- UNLOCK;
-
- return r;
-}
+++ /dev/null
-/*-
- * Copyright (c) 2004 Nik Clayton
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/**
- * plan_tests - announce the number of tests you plan to run
- * @tests: the number of tests
- *
- * This should be the first call in your test program: it allows tracing
- * of failures which mean that not all tests are run.
- *
- * If you don't know how many tests will actually be run, assume all of them
- * and use skip() if you don't actually run some tests.
- *
- * Example:
- * plan_tests(13);
- */
-void plan_tests(unsigned int tests);
-
-#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(__GNUC__)
-# error "Needs gcc or C99 compiler for variadic macros."
-#else
-
-/**
- * ok1 - Simple conditional test
- * @e: the expression which we expect to be true.
- *
- * This is the simplest kind of test: if the expression is true, the
- * test passes. The name of the test which is printed will simply be
- * file name, line number, and the expression itself.
- *
- * Example:
- * ok1(init_subsystem() == 1);
- */
-# define ok1(e) ((e) ? \
- _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
- _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
-
-/**
- * ok - Conditional test with a name
- * @e: the expression which we expect to be true.
- * @...: the printf-style name of the test.
- *
- * If the expression is true, the test passes. The name of the test will be
- * the filename, line number, and the printf-style string. This can be clearer
- * than simply the expression itself.
- *
- * Example:
- * ok1(init_subsystem() == 1);
- * ok(init_subsystem() == 0, "Second initialization should fail");
- */
-# define ok(e, ...) ((e) ? \
- _gen_result(1, __func__, __FILE__, __LINE__, \
- __VA_ARGS__) : \
- _gen_result(0, __func__, __FILE__, __LINE__, \
- __VA_ARGS__))
-
-/**
- * pass - Note that a test passed
- * @...: the printf-style name of the test.
- *
- * For complicated code paths, it can be easiest to simply call pass() in one
- * branch and fail() in another.
- *
- * Example:
- * x = do_something();
- * if (!checkable(x) || check_value(x))
- * pass("do_something() returned a valid value");
- * else
- * fail("do_something() returned an invalid value");
- */
-# define pass(...) ok(1, __VA_ARGS__)
-
-/**
- * fail - Note that a test failed
- * @...: the printf-style name of the test.
- *
- * For complicated code paths, it can be easiest to simply call pass() in one
- * branch and fail() in another.
- */
-# define fail(...) ok(0, __VA_ARGS__)
-
-/* I don't find these to be useful. */
-# define skip_if(cond, n, ...) \
- if (cond) skip((n), __VA_ARGS__); \
- else
-
-# define skip_start(test, n, ...) \
- do { \
- if((test)) { \
- skip(n, __VA_ARGS__); \
- continue; \
- }
-
-# define skip_end } while(0)
-
-#ifndef PRINTF_ATTRIBUTE
-#ifdef __GNUC__
-#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
-#else
-#define PRINTF_ATTRIBUTE(a1, a2)
-#endif
-#endif
-
-unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...)
- PRINTF_ATTRIBUTE(5, 6);
-
-/**
- * diag - print a diagnostic message (use instead of printf/fprintf)
- * @fmt: the format of the printf-style message
- *
- * diag ensures that the output will not be considered to be a test
- * result by the TAP test harness. It will append '\n' for you.
- *
- * Example:
- * diag("Now running complex tests");
- */
-void diag(char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
-
-/**
- * skip - print a diagnostic message (use instead of printf/fprintf)
- * @n: number of tests you're skipping.
- * @fmt: the format of the reason you're skipping the tests.
- *
- * Sometimes tests cannot be run because the test system lacks some feature:
- * you should explicitly document that you're skipping tests using skip().
- *
- * From the Test::More documentation:
- * If it's something the user might not be able to do, use SKIP. This
- * includes optional modules that aren't installed, running under an OS that
- * doesn't have some feature (like fork() or symlinks), or maybe you need an
- * Internet connection and one isn't available.
- *
- * Example:
- * #ifdef HAVE_SOME_FEATURE
- * ok1(test_some_feature());
- * #else
- * skip(1, "Don't have SOME_FEATURE");
- * #endif
- */
-void skip(unsigned int n, char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
-
-/**
- * todo_start - mark tests that you expect to fail.
- * @fmt: the reason they currently fail.
- *
- * It's extremely useful to write tests before you implement the matching fix
- * or features: surround these tests by todo_start()/todo_end(). These tests
- * will still be run, but with additional output that indicates that they are
- * expected to fail.
- *
- * This way, should a test start to succeed unexpectedly, tools like prove(1)
- * will indicate this and you can move the test out of the todo block. This
- * is much more useful than simply commenting out (or '#if 0') the tests.
- *
- * From the Test::More documentation:
- * If it's something the programmer hasn't done yet, use TODO. This is for
- * any code you haven't written yet, or bugs you have yet to fix, but want to
- * put tests in your testing script (always a good idea).
- *
- * Example:
- * todo_start("dwim() not returning true yet");
- * ok(dwim(), "Did what the user wanted");
- * todo_end();
- */
-void todo_start(char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
-
-/**
- * todo_end - end of tests you expect to fail.
- *
- * See todo_start().
- */
-void todo_end(void);
-
-/**
- * exit_status - the value that main should return.
- *
- * For maximum compatability your test program should return a particular exit
- * code (ie. 0 if all tests were run, and every test which was expected to
- * succeed succeeded).
- *
- * Example:
- * exit(exit_status());
- */
-int exit_status(void);
-
-/**
- * plan_no_plan - I have no idea how many tests I'm going to run.
- *
- * In some situations you may not know how many tests you will be running, or
- * you are developing your test program, and do not want to update the
- * plan_tests() call every time you make a change. For those situations use
- * plan_no_plan() instead of plan_tests(). It indicates to the test harness
- * that an indeterminate number of tests will be run.
- *
- * Remember, if you fail to plan, you plan to fail.
- *
- * Example:
- * plan_no_plan();
- * while (random() % 2)
- * ok1(some_test());
- * exit(exit_status());
- */
-void plan_no_plan(void);
-
-/**
- * plan_skip_all - Indicate that you will skip all tests.
- * @reason: the string indicating why you can't run any tests.
- *
- * If your test program detects at run time that some required functionality
- * is missing (for example, it relies on a database connection which is not
- * present, or a particular configuration option that has not been included
- * in the running kernel) use plan_skip_all() instead of plan_tests().
- *
- * Example:
- * if (!have_some_feature) {
- * plan_skip_all("Need some_feature support");
- * exit(exit_status());
- * }
- * plan_tests(13);
- */
-void plan_skip_all(char *reason);
-
-#endif /* C99 or gcc */
+++ /dev/null
-/* We use the fact that pipes have a buffer greater than the size of
- * any output, and change stdout and stderr to use that.
- *
- * Since we don't use libtap for output, this looks like one big test. */
-#include "tap/tap.h"
-#include <stdio.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <err.h>
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <stdbool.h>
-
-/* We dup stderr to here. */
-static int stderrfd;
-
-/* Simple replacement for err() */
-static void failmsg(const char *fmt, ...)
-{
- char buf[1024];
- va_list ap;
-
- /* Write into buffer. */
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
-
- write(stderrfd, "# ", 2);
- write(stderrfd, buf, strlen(buf));
- write(stderrfd, "\n", 1);
- _exit(1);
-}
-
-static void expect(int fd, const char *str)
-{
- char buffer[PIPE_BUF];
- int r;
-
- r = read(fd, buffer, sizeof(buffer));
- if (r < 0)
- failmsg("reading from pipe");
-
- if (strlen(str) != r || strncmp(str, buffer, r) != 0)
- failmsg("Expected '%s' got '%.*s'",
- str, r, buffer);
-}
-
-int main(int argc, char *argv[])
-{
- int p[2];
- int stdoutfd;
-
- printf("1..1\n");
- fflush(stdout);
- stderrfd = dup(STDERR_FILENO);
- if (stderrfd < 0)
- err(1, "dup of stderr failed");
-
- stdoutfd = dup(STDOUT_FILENO);
- if (stdoutfd < 0)
- err(1, "dup of stdout failed");
-
- if (pipe(p) != 0)
- failmsg("pipe failed");
-
- if (dup2(p[1], STDERR_FILENO) < 0 || dup2(p[1], STDOUT_FILENO) < 0)
- failmsg("Duplicating file descriptor");
-
- plan_tests(10);
- expect(p[0], "1..10\n");
-
- ok(1, "msg1");
- expect(p[0], "ok 1 - msg1\n");
-
- ok(0, "msg2");
- expect(p[0], "not ok 2 - msg2\n"
- "# Failed test (tap/test/run.c:main() at line 76)\n");
-
- ok1(true);
- expect(p[0], "ok 3 - true\n");
-
- ok1(false);
- expect(p[0], "not ok 4 - false\n"
- "# Failed test (tap/test/run.c:main() at line 83)\n");
-
- pass("passed");
- expect(p[0], "ok 5 - passed\n");
-
- fail("failed");
- expect(p[0], "not ok 6 - failed\n"
- "# Failed test (tap/test/run.c:main() at line 90)\n");
-
- skip(2, "skipping %s", "test");
- expect(p[0], "ok 7 # skip skipping test\n"
- "ok 8 # skip skipping test\n");
-
- todo_start("todo");
- ok1(false);
- expect(p[0], "not ok 9 - false # TODO todo\n"
- "# Failed (TODO) test (tap/test/run.c:main() at line 99)\n");
- ok1(true);
- expect(p[0], "ok 10 - true # TODO todo\n");
- todo_end();
-
- if (exit_status() != 3)
- failmsg("Expected exit status 3, not %i", exit_status());
-
-#if 0
- /* Manually run the atexit command. */
- _cleanup();
- expect(p[0], "# Looks like you failed 2 tests of 9.\n");
-#endif
-
- write(stdoutfd, "ok 1 - All passed\n", strlen("ok 1 - All passed\n"));
- _exit(0);
-}
--- /dev/null
+tools/run_tests: tools/run_tests.o ccan/tap/tap.o ccan/talloc/talloc.o
+
+tools/doc_extract: tools/doc_extract.c ccan/talloc/talloc.o
+
+tools/namespacize: tools/namespacize.c ccan/talloc/talloc.o
+
+tools-clean: ccanlint-clean
+ rm -f run_tests doc_extract namespacize
+
+include tools/ccanlint/Makefile
--- /dev/null
+OBJS := tools/ccanlint/no_info.o \
+ tools/ccanlint/has_main_header.o \
+ tools/ccanlint/has_tests.o \
+ tools/ccanlint/trailing_whitespace.o \
+ tools/ccanlint/idempotent.o \
+
+FUTURE:=tools/ccanlint/if_have_not_ifdef.o \
+ tools/ccanlint/needs_depends.o \
+ tools/ccanlint/has_info_documentation.o \
+ tools/ccanlint/has_header_documentation.o \
+ tools/ccanlint/has_tests.o \
+ tools/ccanlint/builds_ok.o \
+ tools/ccanlint/builds_ok_all_have_variants.o \
+ tools/ccanlint/run_tests.o \
+ tools/ccanlint/test_coverage.o \
+
+tools/ccanlint/generated-init-tests: $(OBJS)
+ cat $(OBJS:.o=.c) | sed -n 's/^struct ccanlint \([A-Za-z0-9_]*\) = {/{ extern struct ccanlint \1; list_add(\&tests, \&\1.list); }/p' >$@
+
+tools/ccanlint/ccanlint.o: tools/ccanlint/generated-init-tests
+
+tools/ccanlint/ccanlint: \
+ $(OBJS) \
+ tools/ccanlint/ccanlint.o \
+ tools/ccanlint/get_file_lines.o \
+ tools/ccanlint/file_analysis.o \
+ talloc/talloc.o noerr/noerr.o
+
+ccanlint-clean:
+ $(RM) tools/ccanlint/generated-init-tests
+ $(RM) tools/ccanlint/ccanlint
+
--- /dev/null
+/*
+ * ccanlint: assorted checks and advice for a ccan package
+ * Copyright (C) 2008 Rusty Russell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "ccanlint.h"
+#include <unistd.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <ctype.h>
+
+static unsigned int verbose = 0;
+static LIST_HEAD(tests);
+
+static void init_tests(void)
+{
+#include "generated-init-tests"
+}
+
+static void usage(const char *name)
+{
+ fprintf(stderr, "Usage: %s [-s] [-v] [-d <dirname>]\n"
+ " -v: verbose mode\n"
+ " -s: simply give one line per FAIL and total score\n"
+ " -d: use this directory instead of the current one\n",
+ name);
+ exit(1);
+}
+
+static void indent_print(const char *string)
+{
+ while (*string) {
+ unsigned int line = strcspn(string, "\n");
+ printf("\t%.*s", line, string);
+ if (string[line] == '\n') {
+ printf("\n");
+ line++;
+ }
+ string += line;
+ }
+}
+
+bool ask(const char *question)
+{
+ char reply[2];
+
+ printf("%s ", question);
+ fflush(stdout);
+
+ return fgets(reply, sizeof(reply), stdin) != NULL
+ && toupper(reply[0]) == 'Y';
+}
+
+static bool run_test(const struct ccanlint *i,
+ bool summary,
+ unsigned int *score,
+ unsigned int *total_score,
+ struct manifest *m)
+{
+ void *result;
+ unsigned int this_score;
+
+ if (i->total_score)
+ *total_score += i->total_score;
+
+ result = i->check(m);
+ if (!result) {
+ if (verbose)
+ printf(" %s: OK\n", i->name);
+ if (i->total_score)
+ *score += i->total_score;
+ return true;
+ }
+
+ if (i->score)
+ this_score = i->score(m, result);
+ else
+ this_score = 0;
+
+ *score += this_score;
+ if (summary) {
+ printf("%s FAILED (%u/%u)\n",
+ i->name, this_score, i->total_score);
+
+ if (verbose)
+ indent_print(i->describe(m, result));
+ return false;
+ }
+
+ printf("%s\n", i->describe(m, result));
+
+ if (i->handle)
+ i->handle(m, result);
+
+ return false;
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ bool summary = false;
+ unsigned int score, total_score;
+ struct manifest *m;
+ const struct ccanlint *i;
+
+ /* I'd love to use long options, but that's not standard. */
+ /* FIXME: getopt_long ccan package? */
+ while ((c = getopt(argc, argv, "sd:v")) != -1) {
+ switch (c) {
+ case 'd':
+ if (chdir(optarg) != 0)
+ err(1, "Changing into directory '%s'", optarg);
+ break;
+ case 's':
+ summary = true;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (optind < argc)
+ usage(argv[0]);
+
+ m = get_manifest();
+
+ init_tests();
+
+ /* If you don't pass the compulsory tests, you don't even get a score */
+ if (verbose)
+ printf("Compulsory tests:\n");
+ list_for_each(&tests, i, list)
+ if (!i->total_score && !run_test(i, summary, NULL, NULL, m))
+ exit(1);
+
+ if (verbose)
+ printf("\nNormal tests:\n");
+ score = total_score = 0;
+ list_for_each(&tests, i, list)
+ if (i->total_score)
+ run_test(i, summary, &score, &total_score, m);
+
+ printf("Total score: %u/%u\n", score, total_score);
+
+ return 0;
+}
--- /dev/null
+#ifndef CCAN_LINT_H
+#define CCAN_LINT_H
+#include <list/list.h>
+#include <stdbool.h>
+
+struct manifest {
+ char *basename;
+ struct ccan_file *info_file;
+
+ struct list_head c_files;
+ struct list_head h_files;
+
+ struct list_head run_tests;
+ struct list_head compile_ok_tests;
+ struct list_head compile_fail_tests;
+ struct list_head other_test_files;
+
+ struct list_head other_files;
+};
+
+struct manifest *get_manifest(void);
+
+struct ccanlint {
+ struct list_node list;
+
+ /* Unique name of test */
+ const char *name;
+
+ /* Total score that this test is worth. 0 means compulsory tests. */
+ unsigned int total_score;
+
+ /* If this returns non-NULL, it means the check failed. */
+ void *(*check)(struct manifest *m);
+
+ /* The non-NULL return from check is passed to one of these: */
+
+ /* So, what did this get out of the total_score? (NULL means 0). */
+ unsigned int (*score)(struct manifest *m, void *check_result);
+
+ /* Verbose description of what was wrong. */
+ const char *(*describe)(struct manifest *m, void *check_result);
+
+ /* Can we do something about it? (NULL if not) */
+ void (*handle)(struct manifest *m, void *check_result);
+};
+
+/* Ask the user a yes/no question: the answer is NO if there's an error. */
+bool ask(const char *question);
+
+struct ccan_file {
+ struct list_node list;
+
+ char *name;
+
+ unsigned int num_lines;
+ char **lines;
+};
+
+/* Use this rather than accessing f->lines directly: loads on demand. */
+char **get_ccan_file_lines(struct ccan_file *f);
+
+/* Call the reporting on every line in the file. sofar contains
+ * previous results. */
+char *report_on_lines(struct list_head *files,
+ char *(*report)(const char *),
+ char *sofar);
+
+/* The critical tests which mean fail if they don't pass. */
+extern struct ccanlint no_info;
+extern struct ccanlint has_main_header;
+
+/* Normal tests. */
+extern struct ccanlint trailing_whitespace;
+
+
+#endif /* CCAN_LINT_H */
--- /dev/null
+#include "ccanlint.h"
+#include "get_file_lines.h"
+#include <talloc/talloc.h>
+#include <string/string.h>
+#include <noerr/noerr.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <dirent.h>
+
+char **get_ccan_file_lines(struct ccan_file *f)
+{
+ if (!f->lines)
+ f->lines = get_file_lines(f, f->name, &f->num_lines);
+ return f->lines;
+}
+
+static void add_files(struct manifest *m, const char *dir)
+{
+ DIR *d;
+ struct dirent *ent;
+
+ if (dir[0])
+ d = opendir(dir);
+ else
+ d = opendir(".");
+ if (!d)
+ err(1, "Opening directory %s", dir[0] ? dir : ".");
+
+ while ((ent = readdir(d)) != NULL) {
+ struct stat st;
+ struct ccan_file *f;
+ struct list_head *dest;
+ bool is_c_src;
+
+ if (ent->d_name[0] == '.')
+ continue;
+
+ f = talloc(m, struct ccan_file);
+ f->lines = NULL;
+ f->name = talloc_asprintf(f, "%s%s", dir, ent->d_name);
+ if (lstat(f->name, &st) != 0)
+ err(1, "lstat %s", f->name);
+
+ if (S_ISDIR(st.st_mode)) {
+ f->name = talloc_append_string(f->name, "/");
+ add_files(m, f->name);
+ continue;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ talloc_free(f);
+ continue;
+ }
+
+ if (streq(f->name, "_info.c")) {
+ m->info_file = f;
+ continue;
+ }
+
+ is_c_src = strends(f->name, ".c");
+ if (!is_c_src && !strends(f->name, ".h"))
+ dest = &m->other_files;
+ else if (!strchr(f->name, '/')) {
+ if (is_c_src)
+ dest = &m->c_files;
+ else
+ dest = &m->h_files;
+ } else if (strstarts(f->name, "test/")) {
+ if (is_c_src) {
+ if (strstarts(f->name, "test/run"))
+ dest = &m->run_tests;
+ else if (strstarts(f->name, "test/compile_ok"))
+ dest = &m->compile_ok_tests;
+ else if (strstarts(f->name, "test/compile_fail"))
+ dest = &m->compile_fail_tests;
+ else
+ dest = &m->other_test_files;
+ } else
+ dest = &m->other_test_files;
+ } else
+ dest = &m->other_files;
+
+ list_add(dest, &f->list);
+ }
+ closedir(d);
+}
+
+char *report_on_lines(struct list_head *files,
+ char *(*report)(const char *),
+ char *sofar)
+{
+ struct ccan_file *f;
+
+ list_for_each(files, f, list) {
+ unsigned int i;
+ char **lines = get_ccan_file_lines(f);
+
+ for (i = 0; i < f->num_lines; i++) {
+ char *r = report(lines[i]);
+ if (!r)
+ continue;
+
+ sofar = talloc_asprintf_append(sofar,
+ "%s:%u:%s\n",
+ f->name, i+1, r);
+ talloc_free(r);
+ }
+ }
+ return sofar;
+}
+
+struct manifest *get_manifest(void)
+{
+ struct manifest *m = talloc(NULL, struct manifest);
+ unsigned int len;
+
+ m->info_file = NULL;
+ list_head_init(&m->c_files);
+ list_head_init(&m->h_files);
+ list_head_init(&m->run_tests);
+ list_head_init(&m->compile_ok_tests);
+ list_head_init(&m->compile_fail_tests);
+ list_head_init(&m->other_test_files);
+ list_head_init(&m->other_files);
+
+ /* *This* is why people hate C. */
+ len = 32;
+ m->basename = talloc_array(m, char, len);
+ while (!getcwd(m->basename, len)) {
+ if (errno != ERANGE)
+ err(1, "Getting current directory");
+ m->basename = talloc_realloc(m, m->basename, char, len *= 2);
+ }
+
+ len = strlen(m->basename);
+ while (len && m->basename[len-1] == '/')
+ m->basename[--len] = '\0';
+
+ m->basename = strrchr(m->basename, '/');
+ if (!m->basename)
+ errx(1, "I don't expect to be run from the root directory");
+ m->basename++;
+
+ add_files(m, "");
+ return m;
+}
--- /dev/null
+#include "get_file_lines.h"
+#include <talloc/talloc.h>
+#include <string/string.h>
+#include <noerr/noerr.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <err.h>
+#include <dirent.h>
+
+static void *grab_fd(const void *ctx, int fd)
+{
+ int ret;
+ unsigned int max = 16384, size = 0;
+ char *buffer;
+
+ buffer = talloc_array(ctx, char, max+1);
+ while ((ret = read(fd, buffer + size, max - size)) > 0) {
+ size += ret;
+ if (size == max)
+ buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1);
+ }
+ if (ret < 0) {
+ talloc_free(buffer);
+ buffer = NULL;
+ } else
+ buffer[size] = '\0';
+
+ return buffer;
+}
+
+/* This version adds one byte (for nul term) */
+static void *grab_file(const void *ctx, const char *filename)
+{
+ int fd;
+ char *buffer;
+
+ if (streq(filename, "-"))
+ fd = dup(STDIN_FILENO);
+ else
+ fd = open(filename, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ buffer = grab_fd(ctx, fd);
+ close_noerr(fd);
+ return buffer;
+}
+
+/* This is a dumb one which copies. We could mangle instead. */
+static char **split(const void *ctx, const char *text, const char *delims,
+ unsigned int *nump)
+{
+ char **lines = NULL;
+ unsigned int max = 64, num = 0;
+
+ lines = talloc_array(ctx, char *, max+1);
+
+ while (*text != '\0') {
+ unsigned int len = strcspn(text, delims);
+ lines[num] = talloc_array(lines, char, len + 1);
+ memcpy(lines[num], text, len);
+ lines[num][len] = '\0';
+ text += len;
+ text += strspn(text, delims);
+ if (++num == max)
+ lines = talloc_realloc(ctx, lines, char *, max*=2 + 1);
+ }
+ lines[num] = NULL;
+ if (nump)
+ *nump = num;
+ return lines;
+}
+
+char **get_file_lines(void *ctx, const char *name, unsigned int *num_lines)
+{
+ char *buffer = grab_file(ctx, name);
+
+ if (!buffer)
+ err(1, "Getting file %s", name);
+
+ return split(buffer, buffer, "\n", num_lines);
+}
--- /dev/null
+#ifndef GET_FILE_LINES_H
+#define GET_FILE_LINES_H
+
+char **get_file_lines(void *ctx, const char *name, unsigned int *num_lines);
+
+#endif /* GET_FILE_LINES_H */
--- /dev/null
+#include "ccanlint.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string/string.h>
+#include <talloc/talloc.h>
+#include <noerr/noerr.h>
+
+static void *check_has_main_header(struct manifest *m)
+{
+ struct ccan_file *f;
+
+ list_for_each(&m->h_files, f, list) {
+ if (strstarts(f->name, m->basename)
+ && strlen(f->name) == strlen(m->basename) + 2)
+ return NULL;
+ }
+ return m;
+}
+
+static const char *describe_has_main_header(struct manifest *m,
+ void *check_result)
+{
+ return talloc_asprintf(m,
+ "You have no %s/%s.h header file.\n\n"
+ "CCAN modules have a name, the same as the directory name. They're\n"
+ "expected to have an interface in the header of the same name.\n",
+ m->basename, m->basename);
+}
+
+struct ccanlint has_main_header = {
+ .name = "No main header file",
+ .check = check_has_main_header,
+ .describe = describe_has_main_header,
+};
--- /dev/null
+#include "ccanlint.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string/string.h>
+#include <talloc/talloc.h>
+#include <noerr/noerr.h>
+
+static char test_is_not_dir[] = "test is not a directory";
+
+static void *check_has_tests(struct manifest *m)
+{
+ struct stat st;
+
+ if (lstat("test", &st) != 0) {
+ if (errno != ENOENT)
+ err(1, "statting test/");
+ return "You have no test directory";
+ }
+
+ if (!S_ISDIR(st.st_mode))
+ return test_is_not_dir;
+
+ if (list_empty(&m->run_tests) && list_empty(&m->compile_ok_tests)) {
+ if (list_empty(&m->compile_fail_tests))
+ return "You have no tests in the test directory";
+ else
+ return "You have no positive tests in the test directory";
+ }
+ return NULL;
+}
+
+static const char *describe_has_tests(struct manifest *m, void *check_result)
+{
+ return talloc_asprintf(m, "%s\n\n"
+ "CCAN modules have a directory called test/ which contains tests.\n"
+ "There are three kinds of tests: run, compile_ok and compile_fail:\n"
+ "you can tell which type of test a C file is by its name, eg 'run.c'\n"
+ "and 'run-simple.c' are both run tests.\n\n"
+ "The simplest kind of test is a run test, which must compile with no\n"
+ "warnings, and then run: it is expected to use libtap to report its\n"
+ "results in a simple and portable format.\n"
+ "compile_ok tests are a subset of run tests: they must compile and\n"
+ "link, but aren't run.\n"
+ "compile_fail tests are tests which should fail to compile (or emit\n"
+ "warnings) or link when FAIL is defined, but should compile and link\n"
+ "when it's not defined: this helps ensure unrelated errors don't make\n"
+ "compilation fail.\n\n"
+ "Note that the tests are not linked against the files in the\n"
+ "above: you should directly #include those C files you want. This\n"
+ "allows access to static functions and use special effects inside\n"
+ "test files\n", (char *)check_result);
+}
+
+static void handle_no_tests(struct manifest *m, void *check_result)
+{
+ FILE *run;
+ struct ccan_file *i;
+
+ if (check_result == test_is_not_dir)
+ return;
+
+ if (!ask("Should I create a template test/run.c file for you?"))
+ return;
+
+ if (mkdir("test", 0600) != 0) {
+ if (errno != EEXIST)
+ err(1, "Creating test/ directory");
+ }
+
+ run = fopen("test/run.c", "w");
+ if (!run)
+ err(1, "Trying to create a test/run.c");
+
+ fputs("/* Include the main header first, to test it works */\n", run);
+ fprintf(run, "#include \"%s/%s.h\"\n", m->basename, m->basename);
+ fputs("/* Include the C files directly. */\n", run);
+ list_for_each(&m->c_files, i, list)
+ fprintf(run, "#include \"%s/%s\"\n", m->basename, i->name);
+ fputs("#include \"tap/tap.h\"\n", run);
+ fputs("\n", run);
+
+ fputs("int main(int argc, char *argv[])\n", run);
+ fputs("{\n", run);
+ fputs("\t/* This is how many tests you plan to run\n", run);
+ fputs("\tplan_tests(3);\n", run);
+ fputs("\n", run);
+ fputs("\t/* Simple thing we expect to succeed */\n", run);
+ fputs("\tok1(some_test())\n", run);
+ fputs("\t/* Same, with an explicit description of the test. */\n", run);
+ fputs("\tok(some_test(), \"%s with no args should return 1\", \"some_test\")\n", run);
+ fputs("\t/* How to print out messages for debugging. */\n", run);
+ fputs("\tdiag(\"Address of some_test is %p\", &some_test)\n", run);
+ fputs("\t/* Conditional tests must be explicitly skipped. */\n", run);
+ fputs("#if HAVE_SOME_FEATURE\n", run);
+ fputs("\tok1(test_some_feature())\n", run);
+ fputs("#else\n", run);
+ fputs("\tskip(1, \"Don\'t have SOME_FEATURE\")\n", run);
+ fputs("#endif\n", run);
+ fputs("\n", run);
+ fputs("\t/* This exits depending on whether all tests passed */\n", run);
+ fputs("\return exit_status()\n", run);
+
+ fclose(run);
+}
+
+struct ccanlint has_tests = {
+ .name = "No tests",
+ .check = check_has_tests,
+ .describe = describe_has_tests,
+ .handle = handle_no_tests,
+};
--- /dev/null
+#include "ccanlint.h"
+#include <talloc/talloc.h>
+#include <string/string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+
+static const char explain[]
+= "Headers usually start with the C preprocessor lines to prevent multiple\n"
+ "inclusions. These look like the following:\n"
+ "#ifndef MY_HEADER_H\n"
+ "#define MY_HEADER_H\n"
+ "...\n"
+ "#endif /* MY_HEADER_H */\n";
+
+static char *report_idem(struct ccan_file *f, char *sofar)
+{
+ char **lines;
+ char *secondline;
+
+ lines = get_ccan_file_lines(f);
+ if (f->num_lines < 3)
+ /* FIXME: We assume small headers probably uninteresting. */
+ return NULL;
+
+ if (!strstarts(lines[0], "#ifndef "))
+ return talloc_asprintf_append(sofar,
+ "%s:1:expect first line to be #ifndef.\n", f->name);
+
+ secondline = talloc_asprintf(f, "#define %s",
+ lines[0] + strlen("#ifndef "));
+ if (!streq(lines[1], secondline))
+ return talloc_asprintf_append(sofar,
+ "%s:2:expect second line to be '%s'.\n",
+ f->name, secondline);
+
+ return sofar;
+}
+
+static void *check_idempotent(struct manifest *m)
+{
+ struct ccan_file *f;
+ char *report = NULL;
+
+ list_for_each(&m->h_files, f, list)
+ report = report_idem(f, report);
+
+ return report;
+}
+
+static const char *describe_idempotent(struct manifest *m, void *check_result)
+{
+ return talloc_asprintf(check_result,
+ "Some headers not idempotent:\n"
+ "%s\n%s", (char *)check_result,
+ explain);
+}
+
+struct ccanlint idempotent = {
+ .name = "Headers are #ifndef/#define idempotent wrapped",
+ .total_score = 1,
+ .check = check_idempotent,
+ .describe = describe_idempotent,
+};
--- /dev/null
+#include "ccanlint.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include <noerr/noerr.h>
+
+static void *check_no_info(struct manifest *m)
+{
+ if (m->info_file)
+ return NULL;
+ return m;
+}
+
+static const char *describe_no_info(struct manifest *m, void *check_result)
+{
+ return "You have no _info.c file.\n\n"
+ "The file _info.c contains the metadata for a ccan package: things\n"
+ "like the dependencies, the documentation for the package as a whole\n"
+ "and license information.\n";
+}
+
+static const char template[] =
+ "#include <string.h>\n"
+ "#include \"config.h\"\n"
+ "\n"
+ "/**\n"
+ " * %s - YOUR-ONE-LINE-DESCRIPTION-HERE\n"
+ " *\n"
+ " * This code ... YOUR-BRIEF-SUMMARY-HERE\n"
+ " *\n"
+ " * Example:\n"
+ " * FULLY-COMPILABLE-INDENTED-TRIVIAL-BUT-USEFUL-EXAMPLE-HERE\n"
+ " */\n"
+ "int main(int argc, char *argv[])\n"
+ "{\n"
+ " /* Expect exactly one argument\n"
+ " if (argc != 2)\n"
+ " return 1;\n"
+ "\n"
+ " if (strcmp(argv[1], \"depends\") == 0) {\n"
+ " PRINTF-CCAN-PACKAGES-YOU-NEED-ONE-PER-LINE-IF-ANY\n"
+ " return 0;\n"
+ " }\n"
+ "\n"
+ " return 1;\n"
+ "}\n";
+
+static void create_info_template(struct manifest *m, void *check_result)
+{
+ FILE *info;
+
+ if (!ask("Should I create a template _info.c file for you?"))
+ return;
+
+ info = fopen("_info.c", "w");
+ if (!info)
+ err(1, "Trying to create a template _info.c");
+
+ if (fprintf(info, template, m->basename) < 0) {
+ unlink_noerr("_info.c");
+ err(1, "Writing template into _info.c");
+ }
+ fclose(info);
+}
+
+struct ccanlint no_info = {
+ .name = "No _info.c file",
+ .check = check_no_info,
+ .describe = describe_no_info,
+ .handle = create_info_template,
+};
--- /dev/null
+/* Trailing whitespace test. Almost embarrassing, but trivial. */
+#include "ccanlint.h"
+#include <talloc/talloc.h>
+#include <string/string.h>
+
+static char *report_on_trailing_whitespace(const char *line)
+{
+ if (!strends(line, " ") && !strends(line, "\t"))
+ return NULL;
+
+ if (strlen(line) > 20)
+ return talloc_asprintf(line, "...'%s'",
+ line + strlen(line) - 20);
+ return talloc_asprintf(line, "'%s'", line);
+}
+
+static void *check_trailing_whitespace(struct manifest *m)
+{
+ char *report;
+
+ report = report_on_lines(&m->c_files, report_on_trailing_whitespace,
+ NULL);
+ report = report_on_lines(&m->h_files, report_on_trailing_whitespace,
+ report);
+
+ return report;
+}
+
+static const char *describe_trailing_whitespace(struct manifest *m,
+ void *check_result)
+{
+ return talloc_asprintf(check_result,
+ "Some source files have trailing whitespace:\n"
+ "%s", (char *)check_result);
+}
+
+struct ccanlint trailing_whitespace = {
+ .name = "Lines with unnecessary trailing whitespace",
+ .total_score = 1,
+ .check = check_trailing_whitespace,
+ .describe = describe_trailing_whitespace,
+};
--- /dev/null
+/* This merely extracts, doesn't do XML or anything. */
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include "talloc/talloc.h"
+
+/* Is A == B ? */
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/* Does A start with B ? */
+#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0)
+
+/* This version adds one byte (for nul term) */
+static void *grab_file(void *ctx, const char *filename)
+{
+ unsigned int max = 16384, size = 0;
+ int ret, fd;
+ char *buffer;
+
+ if (streq(filename, "-"))
+ fd = dup(STDIN_FILENO);
+ else
+ fd = open(filename, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ buffer = talloc_array(ctx, char, max+1);
+ while ((ret = read(fd, buffer + size, max - size)) > 0) {
+ size += ret;
+ if (size == max)
+ buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1);
+ }
+ if (ret < 0) {
+ talloc_free(buffer);
+ buffer = NULL;
+ } else
+ buffer[size] = '\0';
+ close(fd);
+ return buffer;
+}
+
+/* This is a dumb one which copies. We could mangle instead. */
+static char **split(const char *text)
+{
+ char **lines = NULL;
+ unsigned int max = 64, num = 0;
+
+ lines = talloc_array(text, char *, max+1);
+
+ while (*text != '\0') {
+ unsigned int len = strcspn(text, "\n");
+ lines[num] = talloc_array(lines, char, len + 1);
+ memcpy(lines[num], text, len);
+ lines[num][len] = '\0';
+ text += len + 1;
+ if (++num == max)
+ lines = talloc_realloc(text, lines, char *, max*=2 + 1);
+ }
+ lines[num] = NULL;
+ return lines;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+
+ for (i = 1; i < argc; i++) {
+ char *file;
+ char **lines;
+ bool printing = false, printed = false;
+
+ file = grab_file(NULL, argv[i]);
+ if (!file)
+ err(1, "Reading file %s", argv[i]);
+ lines = split(file);
+
+ for (j = 0; lines[j]; j++) {
+ if (streq(lines[j], "/**")) {
+ printing = true;
+ if (printed++)
+ puts("\n");
+ } else if (streq(lines[j], " */"))
+ printing = false;
+ else if (printing) {
+ if (strstarts(lines[j], " * "))
+ puts(lines[j] + 3);
+ else if (strstarts(lines[j], " *"))
+ puts(lines[j] + 2);
+ else
+ errx(1, "Malformed line %s:%u",
+ argv[i], j);
+ }
+ }
+ talloc_free(file);
+ }
+ return 0;
+}
+
+
+
--- /dev/null
+/* Code to move a ccan module into the ccan_ namespace. */
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include "talloc/talloc.h"
+
+#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I. -Iccan_tools/libtap/src/"
+
+#define IDENT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "abcdefghijklmnopqrstuvwxyz" \
+ "01234567889_"
+
+static bool verbose = false;
+static int indent = 0;
+#define verbose(args...) \
+ do { if (verbose) { \
+ unsigned int _i; \
+ for (_i = 0; _i < indent; _i++) printf(" "); \
+ printf(args); \
+ } \
+ } while(0)
+#define verbose_indent() (indent += 2)
+#define verbose_unindent() (indent -= 2)
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
+
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return streq(str + strlen(str) - strlen(postfix), postfix);
+}
+
+static int close_no_errno(int fd)
+{
+ int ret = 0, serrno = errno;
+ if (close(fd) < 0)
+ ret = errno;
+ errno = serrno;
+ return ret;
+}
+
+static int unlink_no_errno(const char *filename)
+{
+ int ret = 0, serrno = errno;
+ if (unlink(filename) < 0)
+ ret = errno;
+ errno = serrno;
+ return ret;
+}
+
+static void *grab_fd(const void *ctx, int fd)
+{
+ int ret;
+ unsigned int max = 16384, size = 0;
+ char *buffer;
+
+ buffer = talloc_array(ctx, char, max+1);
+ while ((ret = read(fd, buffer + size, max - size)) > 0) {
+ size += ret;
+ if (size == max)
+ buffer = talloc_realloc(ctx, buffer, char, max*=2 + 1);
+ }
+ if (ret < 0) {
+ talloc_free(buffer);
+ buffer = NULL;
+ } else
+ buffer[size] = '\0';
+
+ return buffer;
+}
+
+/* This version adds one byte (for nul term) */
+static void *grab_file(const void *ctx, const char *filename)
+{
+ int fd;
+ char *buffer;
+
+ if (streq(filename, "-"))
+ fd = dup(STDIN_FILENO);
+ else
+ fd = open(filename, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ buffer = grab_fd(ctx, fd);
+ close_no_errno(fd);
+ return buffer;
+}
+
+/* This is a dumb one which copies. We could mangle instead. */
+static char **split(const void *ctx, const char *text, const char *delims,
+ unsigned int *nump)
+{
+ char **lines = NULL;
+ unsigned int max = 64, num = 0;
+
+ lines = talloc_array(ctx, char *, max+1);
+
+ while (*text != '\0') {
+ unsigned int len = strcspn(text, delims);
+ lines[num] = talloc_array(lines, char, len + 1);
+ memcpy(lines[num], text, len);
+ lines[num][len] = '\0';
+ text += len;
+ text += strspn(text, delims);
+ if (++num == max)
+ lines = talloc_realloc(ctx, lines, char *, max*=2 + 1);
+ }
+ lines[num] = NULL;
+ if (nump)
+ *nump = num;
+ return lines;
+}
+
+static char **get_dir(const char *dir)
+{
+ DIR *d;
+ struct dirent *ent;
+ char **names = NULL;
+ unsigned int size = 0;
+
+ d = opendir(dir);
+ if (!d)
+ return NULL;
+
+ while ((ent = readdir(d)) != NULL) {
+ names = talloc_realloc(dir, names, char *, size + 2);
+ names[size++]
+ = talloc_asprintf(names, "%s/%s", dir, ent->d_name);
+ }
+ names[size++] = NULL;
+ closedir(d);
+ return names;
+}
+
+static char ** __attribute__((format(printf, 2, 3)))
+lines_from_cmd(const void *ctx, char *format, ...)
+{
+ va_list ap;
+ char *cmd, *buffer;
+ FILE *p;
+
+ va_start(ap, format);
+ cmd = talloc_vasprintf(ctx, format, ap);
+ va_end(ap);
+
+ p = popen(cmd, "r");
+ if (!p)
+ err(1, "Executing '%s'", cmd);
+
+ buffer = grab_fd(ctx, fileno(p));
+ if (!buffer)
+ err(1, "Reading from '%s'", cmd);
+ pclose(p);
+
+ return split(ctx, buffer, "\n", NULL);
+}
+
+struct replace
+{
+ struct replace *next;
+ char *string;
+};
+
+static void __attribute__((noreturn)) usage(void)
+{
+ errx(1, "Usage:\n"
+ "namespacize [--verbose] <dir>\n"
+ "namespacize [--verbose] --adjust <dir>...\n"
+ "The first form converts dir/ to insert 'ccan_' prefixes, and\n"
+ "then adjusts any other ccan directories at the same level which\n"
+ "are effected.\n"
+ "--adjust does an adjustment for each directory, in case a\n"
+ "dependency has been namespacized\n");
+}
+
+static void add_replace(struct replace **repl, const char *str)
+{
+ struct replace *new, *i;
+
+ /* Avoid duplicates. */
+ for (i = *repl; i; i = i->next)
+ if (streq(i->string, str))
+ return;
+
+ new = talloc(*repl, struct replace);
+ new->next = *repl;
+ new->string = talloc_strdup(new, str);
+ *repl = new;
+}
+
+static void add_replace_tok(struct replace **repl, const char *s)
+{
+ struct replace *new;
+ unsigned int len = strspn(s, IDENT_CHARS);
+
+ new = talloc(*repl, struct replace);
+ new->next = *repl;
+ new->string = talloc_strndup(new, s, len);
+ *repl = new;
+}
+
+static char *basename(const void *ctx, const char *dir)
+{
+ char *p = strrchr(dir, '/');
+
+ if (!p)
+ return (char *)dir;
+ return talloc_strdup(ctx, p+1);
+}
+
+static void look_for_macros(char *contents, struct replace **repl)
+{
+ char *p;
+ enum { LINESTART, HASH, DEFINE, NONE } state = LINESTART;
+
+ /* Look for lines of form #define X */
+ for (p = contents; *p; p++) {
+ if (*p == '\n')
+ state = LINESTART;
+ else if (!isspace(*p)) {
+ if (state == LINESTART && *p == '#')
+ state = HASH;
+ else if (state==HASH && !strncmp(p, "define", 6)) {
+ state = DEFINE;
+ p += 5;
+ } else if (state == DEFINE) {
+ unsigned int len;
+
+ len = strspn(p, IDENT_CHARS);
+ if (len) {
+ char *s;
+ s = talloc_strndup(contents, p, len);
+ /* Don't wrap idempotent wrappers */
+ if (!strstarts(s, "CCAN_")) {
+ verbose("Found %s\n", s);
+ add_replace(repl, s);
+ }
+ }
+ state = NONE;
+ } else
+ state = NONE;
+ }
+ }
+}
+
+/* Blank out preprocessor lines, and eliminate \ */
+static void preprocess(char *p)
+{
+ char *s;
+
+ /* We assume backslashes are only used for macros. */
+ while ((s = strstr(p, "\\\n")) != NULL)
+ s[0] = s[1] = ' ';
+
+ /* Now eliminate # lines. */
+ if (p[0] == '#') {
+ unsigned int i;
+ for (i = 0; p[i] != '\n'; i++)
+ p[i] = ' ';
+ }
+ while ((s = strstr(p, "\n#")) != NULL) {
+ unsigned int i;
+ for (i = 1; s[i] != '\n'; i++)
+ s[i] = ' ';
+ }
+}
+
+static char *get_statement(const void *ctx, char **p)
+{
+ unsigned brackets = 0;
+ bool seen_brackets = false;
+ char *answer = talloc_strdup(ctx, "");
+
+ for (;;) {
+ if ((*p)[0] == '/' && (*p)[1] == '/')
+ *p += strcspn(*p, "\n");
+ else if ((*p)[0] == '/' && (*p)[1] == '*')
+ *p = strstr(*p, "*/") + 1;
+ else {
+ char c = **p;
+ if (c == ';' && !brackets) {
+ (*p)++;
+ return answer;
+ }
+ /* Compress whitespace into a single ' ' */
+ if (isspace(c)) {
+ c = ' ';
+ while (isspace((*p)[1]))
+ (*p)++;
+ } else if (c == '{' || c == '(' || c == '[') {
+ if (c == '(')
+ seen_brackets = true;
+ brackets++;
+ } else if (c == '}' || c == ')' || c == ']')
+ brackets--;
+
+ if (answer[0] != '\0' || c != ' ') {
+ answer = talloc_realloc(NULL, answer, char,
+ strlen(answer) + 2);
+ answer[strlen(answer)+1] = '\0';
+ answer[strlen(answer)] = c;
+ }
+ if (c == '}' && seen_brackets && brackets == 0) {
+ (*p)++;
+ return answer;
+ }
+ }
+ (*p)++;
+ if (**p == '\0')
+ return NULL;
+ }
+}
+
+/* This hack should handle well-formatted code. */
+static void look_for_definitions(char *contents, struct replace **repl)
+{
+ char *stmt, *p = contents;
+
+ preprocess(contents);
+
+ while ((stmt = get_statement(contents, &p)) != NULL) {
+ int i, len;
+
+ /* Definition of struct/union? */
+ if ((strncmp(stmt, "struct", 5) == 0
+ || strncmp(stmt, "union", 5) == 0)
+ && strchr(stmt, '{') && stmt[7] != '{')
+ add_replace_tok(repl, stmt+7);
+
+ /* Definition of var or typedef? */
+ for (i = strlen(stmt)-1; i >= 0; i--)
+ if (strspn(stmt+i, IDENT_CHARS) == 0)
+ break;
+
+ if (i != strlen(stmt)-1) {
+ add_replace_tok(repl, stmt+i+1);
+ continue;
+ }
+
+ /* function or array declaration? */
+ len = strspn(stmt, IDENT_CHARS "* ");
+ if (len > 0 && (stmt[len] == '(' || stmt[len] == '[')) {
+ if (strspn(stmt + len + 1, IDENT_CHARS) != 0) {
+ for (i = len-1; i >= 0; i--)
+ if (strspn(stmt+i, IDENT_CHARS) == 0)
+ break;
+ if (i != len-1) {
+ add_replace_tok(repl, stmt+i+1);
+ continue;
+ }
+ } else {
+ /* Pointer to function? */
+ len++;
+ len += strspn(stmt + len, " *");
+ i = strspn(stmt + len, IDENT_CHARS);
+ if (i > 0 && stmt[len + i] == ')')
+ add_replace_tok(repl, stmt+len);
+ }
+ }
+ }
+}
+
+/* FIXME: Only does main header, should chase local includes. */
+static void analyze_headers(const char *dir, struct replace **repl)
+{
+ char *hdr, *contents;
+
+ /* Get hold of header, assume that's it. */
+ hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir));
+ contents = grab_file(dir, hdr);
+ if (!contents)
+ err(1, "Reading %s", hdr);
+
+ verbose("Looking in %s for macros\n", hdr);
+ verbose_indent();
+ look_for_macros(contents, repl);
+ verbose_unindent();
+
+ verbose("Looking in %s for symbols\n", hdr);
+ verbose_indent();
+ look_for_definitions(contents, repl);
+ verbose_unindent();
+}
+
+static void write_replacement_file(const char *dir, struct replace **repl)
+{
+ char *replname = talloc_asprintf(dir, "%s/.namespacize", dir);
+ int fd;
+ struct replace *r;
+
+ fd = open(replname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd < 0) {
+ if (errno == EEXIST)
+ errx(1, "%s already exists: can't namespacize twice",
+ replname);
+ err(1, "Opening %s", replname);
+ }
+
+ for (r = *repl; r; r = r->next) {
+ if (write(fd,r->string,strlen(r->string)) != strlen(r->string)
+ || write(fd, "\n", 1) != 1) {
+ unlink_no_errno(replname);
+ if (errno == 0)
+ errx(1, "Short write to %s: disk full?",
+ replname);
+ errx(1, "Writing to %s", replname);
+ }
+ }
+
+ close(fd);
+}
+
+static int unlink_destroy(char *name)
+{
+ unlink(name);
+ return 0;
+}
+
+static char *find_word(char *f, const char *str)
+{
+ char *p = f;
+
+ while ((p = strstr(p, str)) != NULL) {
+ /* Check it's not in the middle of a word. */
+ if (p > f && (isalnum(p[-1]) || p[-1] == '_')) {
+ p++;
+ continue;
+ }
+ if (isalnum(p[strlen(str)]) || p[strlen(str)] == '_') {
+ p++;
+ continue;
+ }
+ return p;
+ }
+ return NULL;
+}
+
+/* This is horribly inefficient but simple. */
+static const char *rewrite_file(const char *filename,
+ const struct replace *repl)
+{
+ char *newname, *file;
+ int fd;
+
+ verbose("Rewriting %s\n", filename);
+ file = grab_file(filename, filename);
+ if (!file)
+ err(1, "Reading file %s", filename);
+
+ for (; repl; repl = repl->next) {
+ char *p;
+
+ while ((p = find_word(file, repl->string)) != NULL) {
+ unsigned int off;
+ char *new = talloc_array(file, char, strlen(file)+6);
+
+ off = p - file;
+ memcpy(new, file, off);
+ if (isupper(repl->string[0]))
+ memcpy(new + off, "CCAN_", 5);
+ else
+ memcpy(new + off, "ccan_", 5);
+ strcpy(new + off + 5, file + off);
+ file = new;
+ }
+ }
+
+ /* If we exit for some reason, we want this erased. */
+ newname = talloc_asprintf(talloc_autofree_context(), "%s.tmp",
+ filename);
+ fd = open(newname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd < 0)
+ err(1, "Creating %s", newname);
+
+ talloc_set_destructor(newname, unlink_destroy);
+ if (write(fd, file, strlen(file)) != strlen(file)) {
+ if (errno == 0)
+ errx(1, "Short write to %s: disk full?", newname);
+ errx(1, "Writing to %s", newname);
+ }
+ close(fd);
+ return newname;
+}
+
+struct adjusted
+{
+ struct adjusted *next;
+ const char *file;
+ const char *tmpfile;
+};
+
+static void setup_adjust_files(const char *dir,
+ const struct replace *repl,
+ struct adjusted **adj)
+{
+ char **files;
+
+ for (files = get_dir(dir); *files; files++) {
+ if (strends(*files, "/test"))
+ setup_adjust_files(*files, repl, adj);
+ else if (strends(*files, ".c") || strends(*files, ".h")) {
+ struct adjusted *a = talloc(dir, struct adjusted);
+ a->next = *adj;
+ a->file = *files;
+ a->tmpfile = rewrite_file(a->file, repl);
+ *adj = a;
+ }
+ }
+}
+
+/* This is the "commit" stage, so we hope it won't fail. */
+static void rename_files(const struct adjusted *adj)
+{
+ while (adj) {
+ if (rename(adj->tmpfile, adj->file) != 0)
+ warn("Could not rename over '%s', we're in trouble",
+ adj->file);
+ adj = adj->next;
+ }
+}
+
+static void convert_dir(const char *dir)
+{
+ char *name;
+ struct replace *replace = NULL;
+ struct adjusted *adj = NULL;
+
+ /* Remove any ugly trailing slashes. */
+ name = talloc_strdup(NULL, dir);
+ while (strends(name, "/"))
+ name[strlen(name)-1] = '\0';
+
+ analyze_headers(name, &replace);
+ write_replacement_file(name, &replace);
+ setup_adjust_files(name, replace, &adj);
+ rename_files(adj);
+ talloc_free(name);
+ talloc_free(replace);
+}
+
+static struct replace *read_replacement_file(const char *depdir)
+{
+ struct replace *repl = NULL;
+ char *replname = talloc_asprintf(depdir, "%s/.namespacize", depdir);
+ char *file, **line;
+
+ file = grab_file(replname, replname);
+ if (!file) {
+ if (errno != ENOENT)
+ err(1, "Opening %s", replname);
+ return NULL;
+ }
+
+ for (line = split(file, file, "\n", NULL); *line; line++)
+ add_replace(&repl, *line);
+ return repl;
+}
+
+static char *build_info(const void *ctx, const char *dir)
+{
+ char *file, *cfile, *cmd;
+
+ cfile = talloc_asprintf(ctx, "%s/%s", dir, "_info.c");
+ file = talloc_asprintf(cfile, "%s/%s", dir, "_info");
+ cmd = talloc_asprintf(file, "gcc " CFLAGS " -o %s %s", file, cfile);
+ if (system(cmd) != 0)
+ errx(1, "Failed to compile %s", file);
+
+ return file;
+}
+
+static char **get_deps(const void *ctx, const char *dir)
+{
+ char **deps, *cmd;
+
+ cmd = talloc_asprintf(ctx, "%s depends", build_info(ctx, dir));
+ deps = lines_from_cmd(cmd, cmd);
+ if (!deps)
+ err(1, "Could not run '%s'", cmd);
+ return deps;
+}
+
+static char *parent_dir(const void *ctx, const char *dir)
+{
+ char *parent, *slash;
+
+ parent = talloc_strdup(ctx, dir);
+ slash = strrchr(parent, '/');
+ if (slash)
+ *slash = '\0';
+ else
+ parent = talloc_strdup(ctx, ".");
+ return parent;
+}
+
+static void adjust_dir(const char *dir)
+{
+ char *parent = parent_dir(NULL, dir);
+ char **deps;
+
+ verbose("Adjusting %s\n", dir);
+ verbose_indent();
+ for (deps = get_deps(parent, dir); *deps; deps++) {
+ char *depdir;
+ struct adjusted *adj = NULL;
+ struct replace *repl;
+
+ depdir = talloc_asprintf(parent, "%s/%s", parent, *deps);
+ repl = read_replacement_file(depdir);
+ if (repl) {
+ verbose("%s has been namespacized\n", depdir);
+ setup_adjust_files(parent, repl, &adj);
+ rename_files(adj);
+ } else
+ verbose("%s has not been namespacized\n", depdir);
+ talloc_free(depdir);
+ }
+ verbose_unindent();
+}
+
+static void adjust_dependents(const char *dir)
+{
+ char *parent = parent_dir(NULL, dir);
+ char *base = basename(parent, dir);
+ char **file;
+
+ verbose("Looking for dependents in %s\n", parent);
+ verbose_indent();
+ for (file = get_dir(parent); *file; file++) {
+ char *infoc, **deps;
+ bool isdep = false;
+
+ if (basename(*file, *file)[0] == '.')
+ continue;
+
+ infoc = talloc_asprintf(*file, "%s/_info.c", *file);
+ if (access(infoc, R_OK) != 0)
+ continue;
+
+ for (deps = get_deps(*file, *file); *deps; deps++) {
+ if (streq(*deps, base))
+ isdep = true;
+ }
+ if (isdep)
+ adjust_dir(*file);
+ else
+ verbose("%s is not dependent\n", *file);
+ }
+ verbose_unindent();
+}
+
+int main(int argc, char *argv[])
+{
+ if (argv[1] && streq(argv[1], "--verbose")) {
+ verbose = true;
+ argv++;
+ argc--;
+ }
+
+ if (argc == 2) {
+ verbose("Namespacizing %s\n", argv[1]);
+ verbose_indent();
+ convert_dir(argv[1]);
+ adjust_dependents(argv[1]);
+ verbose_unindent();
+ return 0;
+ }
+
+ if (argc > 2 && streq(argv[1], "--adjust")) {
+ unsigned int i;
+
+ for (i = 2; i < argc; i++)
+ adjust_dir(argv[i]);
+ return 0;
+ }
+ usage();
+}
--- /dev/null
+#include <err.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <assert.h>
+#include <unistd.h>
+#include "ccan/tap/tap.h"
+#include "ccan/talloc/talloc.h"
+#include "ccan/string/string.h"
+
+#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -Iccan -I."
+
+/* FIXME: Use build bug later. */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static struct test *tests = NULL;
+static struct obj *objs = NULL;
+static int verbose;
+
+struct test_type
+{
+ const char *name;
+ void (*testfn)(struct test_type *t, const char *name);
+};
+
+struct test
+{
+ struct test *next;
+ struct test_type *type;
+ char *name;
+};
+
+struct obj
+{
+ struct obj *next;
+ char *name;
+};
+
+static char *output_name(const char *name)
+{
+ char *ret;
+
+ assert(strends(name, ".c"));
+
+ ret = talloc_strdup(name, name);
+ ret[strlen(ret) - 2] = '\0';
+ return ret;
+}
+
+static char *obj_list(void)
+{
+ char *list = talloc_strdup(objs, "");
+ struct obj *i;
+
+ for (i = objs; i; i = i->next)
+ list = talloc_asprintf_append(list, "%s ", i->name);
+
+ /* FIXME */
+ list = talloc_asprintf_append(list, "ccan/tap/tap.o");
+ return list;
+}
+
+static void compile_objs(void)
+{
+ struct obj *i;
+
+ for (i = objs; i; i = i->next) {
+ char *cmd = talloc_asprintf(i, "gcc " CFLAGS " -o %s.o -c %s%s",
+ output_name(i->name), i->name,
+ verbose ? "" : "> /dev/null 2>&1");
+ ok(system(cmd) == 0, "%s", cmd);
+ }
+}
+
+static void cleanup_objs(void)
+{
+ struct obj *i;
+
+ for (i = objs; i; i = i->next)
+ unlink(talloc_asprintf(i, "%s.o", output_name(i->name)));
+}
+
+static void add_test(const char *testdir, const char *name, struct test_type *t)
+{
+ struct test *test = talloc(testdir, struct test);
+
+ test->next = tests;
+ test->type = t;
+ test->name = talloc_asprintf(test, "%s/%s", testdir, name);
+ tests = test;
+}
+
+static void add_obj(const char *testdir, const char *name)
+{
+ struct obj *obj = talloc(testdir, struct obj);
+
+ obj->next = objs;
+ obj->name = talloc_asprintf(obj, "%s/%s", testdir, name);
+ objs = obj;
+}
+
+static int build(const char *name, int fail)
+{
+ const char *cmd;
+ int ret;
+
+ cmd = talloc_asprintf(name, "gcc " CFLAGS " %s -o %s %s %s%s",
+ fail ? "-DFAIL" : "",
+ output_name(name), name, obj_list(),
+ verbose ? "" : "> /dev/null 2>&1");
+
+ if (verbose)
+ fprintf(stderr, "Running %s\n", cmd);
+
+ ret = system(cmd);
+ if (ret == -1)
+ diag("cmd '%s' failed to execute", cmd);
+
+ return ret;
+}
+
+static void compile_ok(struct test_type *t, const char *name)
+{
+ ok(build(name, 0) == 0, "%s %s", t->name, name);
+}
+
+static void compile_fail(struct test_type *t, const char *name)
+{
+ if (build(name, 0) != 0)
+ fail("non-FAIL build %s", name);
+ else
+ ok(build(name, 1) > 0, "%s %s", t->name, name);
+}
+
+static void run(const char *name)
+{
+ if (system(output_name(name)) == -1)
+ fail("running %s had error %m", name);
+}
+
+static void cleanup(const char *name)
+{
+ unlink(output_name(name));
+}
+
+static struct test_type test_types[] = {
+ { "compile_ok", compile_ok },
+ { "compile_fail", compile_fail },
+ { "run", compile_ok },
+};
+
+int main(int argc, char *argv[])
+{
+ DIR *dir;
+ struct dirent *d;
+ char *testdir;
+ struct test *test;
+ unsigned int num_tests = 0, num_objs = 0;
+
+ if (argc > 1 && streq(argv[1], "--verbose")) {
+ verbose = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc != 2)
+ errx(1, "Usage: run_tests [--verbose] <dir>");
+
+ testdir = talloc_asprintf(NULL, "%s/test", argv[1]);
+ dir = opendir(testdir);
+ if (!dir)
+ err(1, "Opening '%s'", testdir);
+
+ while ((d = readdir(dir)) != NULL) {
+ unsigned int i;
+ if (d->d_name[0] == '.' || !strends(d->d_name, ".c"))
+ continue;
+
+ for (i = 0; i < ARRAY_SIZE(test_types); i++) {
+ if (strstarts(d->d_name, test_types[i].name)) {
+ add_test(testdir, d->d_name, &test_types[i]);
+ num_tests++;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(test_types)) {
+ add_obj(testdir, d->d_name);
+ num_objs++;
+ }
+ }
+
+ plan_tests(num_tests + num_objs);
+ /* First all the extra object compilations. */
+ compile_objs();
+
+ /* Do all the test compilations. */
+ for (test = tests; test; test = test->next)
+ test->type->testfn(test->type, test->name);
+
+ cleanup_objs();
+
+ /* Now run all the ones which wanted to run. */
+ for (test = tests; test; test = test->next) {
+ if (streq(test->type->name, "run"))
+ run(test->name);
+ cleanup(test->name);
+ }
+
+ exit(exit_status());
+}
--- /dev/null
+#! /bin/sh
+
+# First, test normal config.
+if ! make -s; then
+ echo Normal config failed.
+ exit 1
+fi
+
+# Now, remove one HAVE_ at a time.
+cp config.h original-config.h
+trap "mv original-config.h config.h && rm -f .newconfig" EXIT
+
+while grep -q '1$' config.h; do
+ tr '\012' @ < config.h | sed 's/1@/0@/' | tr @ '\012' > .newconfig
+ diff -u config.h .newconfig
+ mv .newconfig config.h
+ if ! make -s; then
+ echo Failed config:
+ cat config.h
+ exit 1
+ fi
+done
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include "config.h"
-
-/**
- * typesafe_cb - macros for safe callbacks.
- *
- * The basis of the typesafe_cb header is cast_if_type(): a
- * conditional cast macro. If an expression exactly matches a given
- * type, it is cast to the target type, otherwise it is left alone.
- *
- * This allows us to create functions which take a small number of
- * specific types, rather than being forced to use a void *. In
- * particular, it is useful for creating typesafe callbacks as the
- * helpers typesafe_cb(), typesafe_cb_preargs() and
- * typesafe_cb_postargs() demonstrate.
- *
- * The standard way of passing arguments to callback functions in C is
- * to use a void pointer, which the callback then casts back to the
- * expected type. This unfortunately subverts the type checking the
- * compiler would perform if it were a direct call. Here's an example:
- *
- * static void my_callback(void *_obj)
- * {
- * struct obj *obj = _obj;
- * ...
- * }
- * ...
- * register_callback(my_callback, &my_obj);
- *
- * If we wanted to use the natural type for my_callback (ie. "void
- * my_callback(struct obj *obj)"), we could make register_callback()
- * take a void * as its first argument, but this would subvert all
- * type checking. We really want register_callback() to accept only
- * the exactly correct function type to match the argument, or a
- * function which takes a void *.
- *
- * This is where typesafe_cb() comes in: it uses cast_if_type() to
- * cast the callback function if it matches the argument type:
- *
- * void _register_callback(void (*cb)(void *arg), void *arg);
- * #define register_callback(cb, arg) \
- * _register_callback(typesafe_cb(void, (cb), (arg)), (arg))
- *
- * On compilers which don't support the extensions required
- * cast_if_type() and friend become an unconditional cast, so your
- * code will compile but you won't get type checking.
- */
-int main(int argc, char *argv[])
-{
- if (argc != 2)
- return 1;
-
- if (strcmp(argv[1], "depends") == 0) {
- return 0;
- }
-
- return 1;
-}
+++ /dev/null
-#include "typesafe_cb/typesafe_cb.h"
-
-void _set_some_value(void *val);
-
-void _set_some_value(void *val)
-{
-}
-
-#define set_some_value(expr) \
- _set_some_value(cast_if_type((expr), unsigned long, void *))
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- int x = 0;
- set_some_value(x);
-#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
-#error "Unfortunately we don't fail if cast_if_type is a noop."
-#endif
-#else
- void *p = 0;
- set_some_value(p);
-#endif
- return 0;
-}
+++ /dev/null
-#include "typesafe_cb/typesafe_cb.h"
-#include <stdlib.h>
-
-void _callback(void (*fn)(void *arg), void *arg);
-void _callback(void (*fn)(void *arg), void *arg)
-{
- fn(arg);
-}
-
-/* Callback is set up to warn if arg isn't a pointer (since it won't
- * pass cleanly to _callback's second arg. */
-#define callback(fn, arg) \
- _callback(typesafe_cb(void, (fn), (arg)), (arg))
-
-void my_callback(int something);
-void my_callback(int something)
-{
-}
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- /* This fails due to arg, not due to cast. */
- callback(my_callback, 100);
-#endif
- return 0;
-}
+++ /dev/null
-#include "typesafe_cb/typesafe_cb.h"
-#include <stdlib.h>
-
-static void _register_callback(void (*cb)(void *arg), void *arg)
-{
-}
-
-#define register_callback(cb, arg) \
- _register_callback(typesafe_cb(void, (cb), (arg)), (arg))
-
-static void my_callback(char *p)
-{
-}
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- int *p;
-#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
-#error "Unfortunately we don't fail if cast_if_type is a noop."
-#endif
-#else
- char *p;
-#endif
- p = NULL;
-
- /* This should work always. */
- register_callback(my_callback, "hello world");
-
- /* This will fail with FAIL defined */
- register_callback(my_callback, p);
- return 0;
-}
+++ /dev/null
-#include "typesafe_cb/typesafe_cb.h"
-#include <stdlib.h>
-
-static void _register_callback(void (*cb)(void *arg, int x), void *arg)
-{
-}
-#define register_callback(cb, arg) \
- _register_callback(typesafe_cb_postargs(void, (cb), (arg), int), (arg))
-
-static void my_callback(char *p, int x)
-{
-}
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- int *p;
-#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
-#error "Unfortunately we don't fail if cast_if_type is a noop."
-#endif
-#else
- char *p;
-#endif
- p = NULL;
- register_callback(my_callback, p);
- return 0;
-}
+++ /dev/null
-#include "typesafe_cb/typesafe_cb.h"
-#include <stdlib.h>
-
-static void _register_callback(void (*cb)(int x, void *arg), void *arg)
-{
-}
-
-#define register_callback(cb, arg) \
- _register_callback(typesafe_cb_preargs(void, (cb), (arg), int), (arg))
-
-static void my_callback(int x, char *p)
-{
-}
-
-int main(int argc, char *argv[])
-{
-#ifdef FAIL
- int *p;
-#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P
-#error "Unfortunately we don't fail if cast_if_type is a noop."
-#endif
-#else
- char *p;
-#endif
- p = NULL;
- register_callback(my_callback, p);
- return 0;
-}
+++ /dev/null
-#include "typesafe_cb/typesafe_cb.h"
-#include <string.h>
-#include "tap/tap.h"
-
-static char dummy = 0;
-
-/* The example usage. */
-static void _set_some_value(void *val)
-{
- ok1(val == &dummy);
-}
-
-#define set_some_value(expr) \
- _set_some_value(cast_if_type((expr), unsigned long, void *))
-
-static void _callback_onearg(void (*fn)(void *arg), void *arg)
-{
- fn(arg);
-}
-
-static void _callback_preargs(void (*fn)(int a, int b, void *arg), void *arg)
-{
- fn(1, 2, arg);
-}
-
-static void _callback_postargs(void (*fn)(void *arg, int a, int b), void *arg)
-{
- fn(arg, 1, 2);
-}
-
-#define callback_onearg(cb, arg) \
- _callback_onearg(typesafe_cb(void, (cb), (arg)), (arg))
-
-#define callback_preargs(cb, arg) \
- _callback_preargs(typesafe_cb_preargs(void, (cb), (arg), int, int), (arg))
-
-#define callback_postargs(cb, arg) \
- _callback_postargs(typesafe_cb_postargs(void, (cb), (arg), int, int), (arg))
-
-static void my_callback_onearg(char *p)
-{
- ok1(strcmp(p, "hello world") == 0);
-}
-
-static void my_callback_onearg_const(const char *p)
-{
- ok1(strcmp(p, "hello world") == 0);
-}
-
-static void my_callback_onearg_volatile(volatile char *p)
-{
- ok1(strcmp((char *)p, "hello world") == 0);
-}
-
-static void my_callback_preargs(int a, int b, char *p)
-{
- ok1(a == 1);
- ok1(b == 2);
- ok1(strcmp(p, "hello world") == 0);
-}
-
-static void my_callback_preargs_const(int a, int b, const char *p)
-{
- ok1(a == 1);
- ok1(b == 2);
- ok1(strcmp(p, "hello world") == 0);
-}
-
-static void my_callback_preargs_volatile(int a, int b, volatile char *p)
-{
- ok1(a == 1);
- ok1(b == 2);
- ok1(strcmp((char *)p, "hello world") == 0);
-}
-
-static void my_callback_postargs(char *p, int a, int b)
-{
- ok1(a == 1);
- ok1(b == 2);
- ok1(strcmp(p, "hello world") == 0);
-}
-
-static void my_callback_postargs_const(const char *p, int a, int b)
-{
- ok1(a == 1);
- ok1(b == 2);
- ok1(strcmp(p, "hello world") == 0);
-}
-
-static void my_callback_postargs_volatile(volatile char *p, int a, int b)
-{
- ok1(a == 1);
- ok1(b == 2);
- ok1(strcmp((char *)p, "hello world") == 0);
-}
-
-/* This is simply a compile test; we promised cast_if_type can be in a
- * static initializer. */
-struct callback_onearg
-{
- void (*fn)(void *arg);
- void *arg;
-};
-
-struct callback_onearg cb_onearg
-= { typesafe_cb(void, my_callback_onearg, "hello world"), "hello world" };
-
-struct callback_preargs
-{
- void (*fn)(int a, int b, void *arg);
- void *arg;
-};
-
-struct callback_preargs cb_preargs
-= { typesafe_cb_preargs(void, my_callback_preargs, "hi", int, int), "hi" };
-
-struct callback_postargs
-{
- void (*fn)(void *arg, int a, int b);
- void *arg;
-};
-
-struct callback_postargs cb_postargs
-= { typesafe_cb_postargs(void, my_callback_postargs, "hi", int, int), "hi" };
-
-int main(int argc, char *argv[])
-{
- void *p = &dummy;
- unsigned long l = (unsigned long)p;
-
- plan_tests(2 + 3 + 9 + 9);
- set_some_value(p);
- set_some_value(l);
-
- callback_onearg(my_callback_onearg, "hello world");
- callback_onearg(my_callback_onearg_const, "hello world");
- callback_onearg(my_callback_onearg_volatile, "hello world");
-
- callback_preargs(my_callback_preargs, "hello world");
- callback_preargs(my_callback_preargs_const, "hello world");
- callback_preargs(my_callback_preargs_volatile, "hello world");
-
- callback_postargs(my_callback_postargs, "hello world");
- callback_postargs(my_callback_postargs_const, "hello world");
- callback_postargs(my_callback_postargs_volatile, "hello world");
-
- return exit_status();
-}
+++ /dev/null
-#ifndef CCAN_CAST_IF_TYPE_H
-#define CCAN_CAST_IF_TYPE_H
-#include "config.h"
-
-#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
-/**
- * cast_if_type - only cast an expression if it is of a given type
- * @expr: the expression to cast
- * @oktype: the type we allow
- * @desttype: the type to cast to
- *
- * This macro is used to create functions which allow multiple types.
- * The result of this macro is used somewhere that a @desttype type is
- * expected: if @expr was of type @oktype, it will be cast to
- * @desttype type. As a result, if @expr is any type other than
- * @oktype or @desttype, a compiler warning will be issued.
- *
- * This macro can be used in static initializers.
- *
- * This is merely useful for warnings: if the compiler does not
- * support the primitives required for cast_if_type(), it becomes an
- * unconditional cast, and the @oktype argument is not used. In
- * particular, this means that @oktype can be a type which uses
- * the "typeof": it will not be evaluated if typeof is not supported.
- *
- * Example:
- * // We can take either an unsigned long or a void *.
- * void _set_some_value(void *val);
- * #define set_some_value(expr) \
- * _set_some_value(cast_if_type((expr), unsigned long, void *))
- */
-#define cast_if_type(expr, oktype, desttype) \
-__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(expr):0), oktype), \
- (desttype)(expr), (expr))
-#else
-#define cast_if_type(expr, oktype, desttype) ((desttype)(expr))
-#endif
-
-/**
- * typesafe_cb - cast a callback function if it matches the arg
- * @rettype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * If a callback function takes a single argument, this macro does
- * appropriate casts to a function which takes a single void * argument if the
- * callback provided matches the @arg (or a const or volatile version).
- *
- * It is assumed that @arg is of pointer type: usually @arg is passed
- * or assigned to a void * elsewhere anyway.
- *
- * Example:
- * void _register_callback(void (*fn)(void *arg), void *arg);
- * #define register_callback(fn, arg) \
- * _register_callback(typesafe_cb(void, (fn), (arg)), (arg))
- */
-#define typesafe_cb(rettype, fn, arg) \
- cast_if_type(cast_if_type(cast_if_type((fn), \
- rettype (*)(const typeof(arg)), \
- rettype (*)(void *)), \
- rettype (*)(volatile typeof(arg)), \
- rettype (*)(void *)), \
- rettype (*)(typeof(arg)), \
- rettype (*)(void *))
-
-/**
- * typesafe_cb_preargs - cast a callback function if it matches the arg
- * @rettype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * This is a version of typesafe_cb() for callbacks that take other arguments
- * before the @arg.
- *
- * Example:
- * void _register_callback(void (*fn)(int, void *arg), void *arg);
- * #define register_callback(fn, arg) \
- * _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
- * (arg))
- */
-#define typesafe_cb_preargs(rettype, fn, arg, ...) \
- cast_if_type(cast_if_type(cast_if_type((fn), \
- rettype (*)(__VA_ARGS__, \
- const typeof(arg)), \
- rettype (*)(__VA_ARGS__, \
- void *)), \
- rettype (*)(__VA_ARGS__, \
- volatile typeof(arg)), \
- rettype (*)(__VA_ARGS__, void *)), \
- rettype (*)(__VA_ARGS__, typeof(arg)), \
- rettype (*)(__VA_ARGS__, void *))
-
-/**
- * typesafe_cb_postargs - cast a callback function if it matches the arg
- * @rettype: the return type of the callback function
- * @fn: the callback function to cast
- * @arg: the (pointer) argument to hand to the callback function.
- *
- * This is a version of typesafe_cb() for callbacks that take other arguments
- * after the @arg.
- *
- * Example:
- * void _register_callback(void (*fn)(void *arg, int), void *arg);
- * #define register_callback(fn, arg) \
- * _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
- * (arg))
- */
-#define typesafe_cb_postargs(rettype, fn, arg, ...) \
- cast_if_type(cast_if_type(cast_if_type((fn), \
- rettype (*)(const typeof(arg), \
- __VA_ARGS__), \
- rettype (*)(void *, \
- __VA_ARGS__)), \
- rettype (*)(volatile typeof(arg), \
- __VA_ARGS__), \
- rettype (*)(void *, __VA_ARGS__)), \
- rettype (*)(typeof(arg), __VA_ARGS__), \
- rettype (*)(void *, __VA_ARGS__))
-
-#endif /* CCAN_CAST_IF_TYPE_H */