diff options
Diffstat (limited to 'libcoopgamma_get_methods.c')
| -rw-r--r-- | libcoopgamma_get_methods.c | 67 | 
1 files changed, 67 insertions, 0 deletions
| diff --git a/libcoopgamma_get_methods.c b/libcoopgamma_get_methods.c new file mode 100644 index 0000000..2761bd1 --- /dev/null +++ b/libcoopgamma_get_methods.c @@ -0,0 +1,67 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * List all recognised adjustment method + *  + * SIGCHLD must not be ignored or blocked + *  + * @return  A `NULL`-terminated list of names. You should only free + *          the outer pointer, inner pointers are subpointers of the + *          outer pointer and cannot be freed. `NULL` on error. + */ +char ** +libcoopgamma_get_methods(void) +{ +	char num[5]; /* The size is base on the fact that we have limited `n` in the loop below */ +	char **methods = NULL; +	char *method; +	char **rc; +	char *buffer; +	size_t n = 0; +	size_t size = 0; +	void *new; + +	methods = malloc(4U * sizeof(*methods)); +	if (!methods) +		goto fail; + +	for (n = 0; n < 10000 /* just to be safe */; n++) { +		if (n >= 4 && (n & (~n + 1U)) == n) { +			new = realloc(methods, (n << 1) * sizeof(*methods)); +			if (!new) +				goto fail; +			methods = new; +		} +		sprintf(num, "%zu", n); +		if (libcoopgamma_get_method_and_site(num, NULL, &method, NULL)) +			goto fail; +		if (!strcmp(method, num)) { +			free(method); +			break; +		} +		methods[n] = method; +		size += strlen(method) + 1U; +	} + +	rc = malloc((n + 1U) * sizeof(char *) + size); +	if (!rc) +		goto fail; +	buffer = (char *)&rc[n + 1U]; +	rc[n] = NULL; +	while (n--) { +		rc[n] = buffer; +		buffer = &stpcpy(buffer, methods[n])[1U]; +		free(methods[n]); +	} +	free(methods); + +	return rc; + +fail: +	while (n--) +		free(methods[n]); +	free(methods); +	return NULL; +} | 
