libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
dr_cmd_reg.c
1/*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14*/
15/*
16 * Copyright 2019 Saso Kiselkov. All rights reserved.
17 */
18
19#include <stdbool.h>
20#include <stddef.h>
21
22#include "acfutils/avl.h"
23#include "acfutils/dr_cmd_reg.h"
24#include "acfutils/safe_alloc.h"
25
26static bool inited = false;
27static avl_tree_t drs;
28static avl_tree_t cmds;
29
30typedef struct {
31 XPLMCommandRef cmd;
32 XPLMCommandCallback_f cb;
33 bool before;
34 void *refcon;
35 avl_node_t node;
36} reg_cmd_t;
37
38typedef struct {
39 dr_t dr;
40 avl_node_t node;
41} reg_dr_t;
42
43static int
44reg_dr_compar(const void *a, const void *b)
45{
46 const reg_dr_t *ra = a, *rb = b;
47 int res = strcmp(ra->dr.name, rb->dr.name);
48
49 if (res < 0)
50 return (-1);
51 if (res > 0)
52 return (1);
53 return (0);
54}
55
56static int
57reg_cmd_compar(const void *a, const void *b)
58{
59 int res = memcmp(a, b, offsetof(reg_cmd_t, node));
60
61 if (res < 0)
62 return (-1);
63 if (res > 0)
64 return (1);
65
66 return (0);
67}
68
74void
76{
77 ASSERT(!inited);
78 inited = true;
79
80 avl_create(&drs, reg_dr_compar, sizeof (reg_dr_t),
81 offsetof(reg_dr_t, node));
82 avl_create(&cmds, reg_cmd_compar, sizeof (reg_cmd_t),
83 offsetof(reg_cmd_t, node));
84}
85
95void
97{
98 reg_dr_t *rdr;
99 reg_cmd_t *cmd;
100 void *cookie;
101
102 if (!inited)
103 return;
104 inited = B_FALSE;
105
106 cookie = NULL;
107 while ((rdr = avl_destroy_nodes(&drs, &cookie)) != NULL) {
108 dr_delete(&rdr->dr);
109 free(rdr);
110 }
111 avl_destroy(&drs);
112
113 cookie = NULL;
114 while ((cmd = avl_destroy_nodes(&cmds, &cookie)) != NULL) {
115 XPLMUnregisterCommandHandler(cmd->cmd, cmd->cb, cmd->before,
116 cmd->refcon);
117 free(cmd);
118 }
119 avl_destroy(&cmds);
120}
121
123void *
125{
126 ASSERT(inited);
127 return (safe_calloc(1, sizeof (reg_dr_t)));
128}
129
131dr_t *
132dcr_get_dr(void *token)
133{
134 ASSERT(inited);
135 ASSERT(token != NULL);
136 return (&((reg_dr_t *)token)->dr);
137}
138
140void
141dcr_insert_rdr(void *token)
142{
143 reg_dr_t *rdr;
144 avl_index_t where;
145
146 ASSERT(inited);
147 ASSERT(token != NULL);
148 rdr = token;
149 ASSERT(rdr->dr.dr != NULL);
150
151 VERIFY_MSG(avl_find(&drs, rdr, &where) == NULL,
152 "Duplicate dataref registration for dr %s\n", rdr->dr.name);
153 avl_insert(&drs, rdr, where);
154}
155
172XPLMCommandRef
173dcr_find_cmd(const char *fmt, XPLMCommandCallback_f cb, bool before,
174 void *refcon, ...)
175{
176 XPLMCommandRef ref;
177 va_list ap;
178
179 va_start(ap, refcon);
180 ref = dcr_find_cmd_v(fmt, cb, before, refcon, ap);
181 va_end(ap);
182
183 return ref;
184}
185
191XPLMCommandRef
192dcr_find_cmd_v(const char *fmt, XPLMCommandCallback_f cb, bool before,
193 void *refcon, va_list ap)
194{
195 char *cmdname;
196 reg_cmd_t *cmd;
197 avl_index_t where;
198
199 ASSERT(inited);
200 ASSERT(fmt != NULL);
201 ASSERT(cb != NULL);
202
203 cmdname = vsprintf_alloc(fmt, ap);
204 cmd = safe_calloc(1, sizeof (*cmd));
205 cmd->cmd = XPLMFindCommand(cmdname);
206 if (cmd->cmd == NULL) {
207 free(cmd);
208 free(cmdname);
209 return (NULL);
210 }
211 cmd->cb = cb;
212 cmd->before = before;
213 cmd->refcon = refcon;
214
215 XPLMRegisterCommandHandler(cmd->cmd, cb, before, refcon);
216
217 VERIFY_MSG(avl_find(&cmds, cmd, &where) == NULL,
218 "Found duplicate registration of command %s with cb: %p "
219 "before: %d, refcon: %p", cmdname, cb, before, refcon);
220 avl_insert(&cmds, cmd, where);
221
222 free(cmdname);
223
224 return (cmd->cmd);
225}
226
233XPLMCommandRef
234f_dcr_find_cmd(const char *fmt, XPLMCommandCallback_f cb, bool before,
235 void *refcon, ...)
236{
237 XPLMCommandRef ref;
238 va_list ap;
239
240 va_start(ap, refcon);
241 ref = f_dcr_find_cmd_v(fmt, cb, before, refcon, ap);
242 va_end(ap);
243
244 return (ref);
245}
246
253XPLMCommandRef
254f_dcr_find_cmd_v(const char *fmt, XPLMCommandCallback_f cb, bool before,
255 void *refcon, va_list ap)
256{
257 XPLMCommandRef ref;
258 va_list ap2;
259
260 va_copy(ap2, ap);
261 ref = dcr_find_cmd_v(fmt, cb, before, refcon, ap);
262 if (ref == NULL) {
263 /* No need to dealloc here, we'll be crashing anyway */
264 VERIFY_MSG(ref != NULL, "Command %s not found",
265 vsprintf_alloc(fmt, ap2));
266 }
267 va_end(ap2);
268
269 return (ref);
270}
271
288XPLMCommandRef
289dcr_create_cmd(const char *cmdname, const char *cmddesc,
290 XPLMCommandCallback_f cb, bool before, void *refcon)
291{
292 XPLMCommandRef ref;
293
294 ASSERT(inited);
295
296 ref = XPLMCreateCommand(cmdname, cmddesc);
297 VERIFY_MSG(ref != NULL,
298 "Cannot create command %s: XPLMCreateCommand failed", cmdname);
299
300 return (f_dcr_find_cmd("%s", cb, before, refcon, cmdname));
301}
#define ASSERT(x)
Definition assert.h:208
#define VERIFY_MSG(x, fmt,...)
Definition assert.h:91
void * avl_destroy_nodes(avl_tree_t *tree, void **cookie)
Definition avl.c:938
uintptr_t avl_index_t
Definition avl.h:119
void avl_insert(avl_tree_t *tree, void *node, avl_index_t where)
Definition avl.c:471
void avl_create(avl_tree_t *tree, int(*compar)(const void *, const void *), size_t size, size_t offset)
Definition avl.c:867
void avl_destroy(avl_tree_t *tree)
Definition avl.c:890
void * avl_find(const avl_tree_t *tree, const void *node, avl_index_t *where)
Definition avl.c:244
void dr_delete(dr_t *dr)
Definition dr.c:946
XPLMCommandRef dcr_find_cmd(const char *fmt, XPLMCommandCallback_f cb, bool before, void *refcon,...)
Definition dr_cmd_reg.c:173
void dcr_fini(void)
Definition dr_cmd_reg.c:96
XPLMCommandRef f_dcr_find_cmd_v(const char *fmt, XPLMCommandCallback_f cb, bool before, void *refcon, va_list ap)
Definition dr_cmd_reg.c:254
dr_t * dcr_get_dr(void *token)
Definition dr_cmd_reg.c:132
void dcr_init(void)
Definition dr_cmd_reg.c:75
void dcr_insert_rdr(void *token)
Definition dr_cmd_reg.c:141
XPLMCommandRef f_dcr_find_cmd(const char *fmt, XPLMCommandCallback_f cb, bool before, void *refcon,...)
Definition dr_cmd_reg.c:234
void * dcr_alloc_rdr(void)
Definition dr_cmd_reg.c:124
XPLMCommandRef dcr_create_cmd(const char *cmdname, const char *cmddesc, XPLMCommandCallback_f cb, bool before, void *refcon)
Definition dr_cmd_reg.c:289
XPLMCommandRef dcr_find_cmd_v(const char *fmt, XPLMCommandCallback_f cb, bool before, void *refcon, va_list ap)
Definition dr_cmd_reg.c:192
static char * vsprintf_alloc(const char *fmt, va_list ap)
Definition helpers.h:540
static void * safe_calloc(size_t nmemb, size_t size)
Definition safe_alloc.h:71