summaryrefslogtreecommitdiff
path: root/src/til_setup.c
blob: d5231a1ad36cedaa1542d296d794f8f7864a79af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#include "til_jenkins.h"
#include "til_settings.h"
#include "til_setup.h"
#include "til_str.h"


/* Allocate and initialize a new til_setup_t of size bytes.
 * free_func is assigned to til_setup_t.free, and will be used for freeing the
 * instance returned when destroyed.  If free_func is NULL, free() will be
 * used by default.
 *
 * A copy of the provided settings' path is stored at til_setup_t.path, and will
 * always be freed automatically when the setup instance is freed, independent of
 * free_func.
 *
 * Note this returns void * despite creating a til_setup_t, this is for convenience
 * as the callers are generally using it in place of calloc(), and assign it to a
 * container struct of some other type but having an embedded til_setup_t.
 */
void * til_setup_new(const til_settings_t *settings, size_t size, void (*free_func)(til_setup_t *setup), const void *creator)
{
	char		*path_buf = NULL;
	size_t		path_len;
	til_str_t	*path_str;
	til_setup_t	*setup;
	int		r;

	assert(settings);
	assert(size >= sizeof(til_setup_t));

	path_str = til_str_new("");
	if (!path_str)
		return NULL;

	r = til_settings_strprint_path(settings, path_str);
	if (r < 0)
		return til_str_free(path_str);

	path_buf = til_str_to_buf(path_str, &path_len);

	setup = calloc(1, size);
	if (!setup) {
		free(path_buf);
		return NULL;
	}

	setup->path = path_buf;
	setup->path_hash = til_jenkins((uint8_t *)path_buf, path_len + 1 /* include the \0 */);
	setup->refcount = 1;
	setup->free = free_func;
	setup->creator = creator;

	return setup;
}


/* bump refcount on setup */
void * til_setup_ref(til_setup_t *setup)
{
	assert(setup);

	setup->refcount++;

	return setup;
}


/* unref setup, freeing it when refcount reaches zero.
 * returns NULL if setup is freed (including when NULL was supplied for setup)
 * resturns setup when setup persists.
 * the public api is to just use til_setup_free() and discard that information,
 * but this is kept here as distinct for potential debugging purposes.
 */
static void * til_setup_unref(til_setup_t *setup)
{
	if (!setup)
		return NULL;

	assert(setup->refcount > 0);

	setup->refcount--;
	if (!setup->refcount) {
		/* don't make setup->free() free the path when provided */
		free((void *)setup->path);

		if (setup->free)
			setup->free(setup);
		else
			free(setup);

		return NULL;
	}

	return setup;
}


/* like til_setup_unref() except always returns NULL so you
 * can't tell if it was actually freed or not, but this is sometimes
 * a convenient free-style wrapper if you have to NULL-assign a placeholder.
 */
void * til_setup_free(til_setup_t *setup)
{
	(void) til_setup_unref(setup);

	return NULL;
}


/* ergonomic helper for setup_funcs to use in res_setup baking */
int til_setup_free_with_failed_setting_ret_err(til_setup_t *setup, til_setting_t *failed_setting, til_setting_t **res_setting, int err)
{
	assert(failed_setting);
	assert(res_setting);
	assert(err < 0);

	til_setup_free(setup);
	*res_setting = failed_setting;

	return err;
}


/* another ergonomic helper for setup_funcs to use in res_setup baking */
int til_setup_free_with_ret_err(til_setup_t *setup, int err)
{
	assert(err < 0);

	til_setup_free(setup);

	return err;
}
© All Rights Reserved