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; +} |