mapi: Add a generic C dispatcher.
[mesa.git] / src / mapi / mapi / mapi.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "u_current.h"
33 #include "u_thread.h"
34 #include "mapi.h"
35 #include "stub.h"
36 #include "table.h"
37
38 /* dynamic stubs will run out before this array */
39 #define MAPI_MAX_STUBS (sizeof(struct mapi_table) / sizeof(mapi_func))
40 static const struct mapi_stub *mapi_stub_map[MAPI_MAX_STUBS];
41 static int mapi_num_stubs;
42
43 static const struct mapi_stub *
44 get_stub(const char *name, const struct mapi_stub *alias)
45 {
46 const struct mapi_stub *stub;
47
48 stub = stub_find_public(name);
49 if (!stub) {
50 struct mapi_stub *dyn = stub_find_dynamic(name, 1);
51 if (dyn) {
52 stub_fix_dynamic(dyn, alias);
53 stub = dyn;
54 }
55 }
56
57 return stub;
58 }
59
60 /**
61 * Initialize mapi. spec consists of NULL-separated strings. The first string
62 * denotes the version. It is followed by variable numbers of entries. Each
63 * entry can have multiple names. An empty name terminates an entry. An empty
64 * entry terminates the spec. A spec of two entries, Foo and Bar, is as
65 * follows
66 *
67 * "1\0"
68 * "Foo\0"
69 * "FooEXT\0"
70 * "\0"
71 * "Bar\0"
72 * "\0"
73 */
74 void
75 mapi_init(const char *spec)
76 {
77 u_mutex_declare_static(mutex);
78 const char *p;
79 int ver, count;
80
81 u_mutex_lock(mutex);
82
83 /* already initialized */
84 if (mapi_num_stubs) {
85 u_mutex_unlock(mutex);
86 return;
87 }
88
89 count = 0;
90 p = spec;
91
92 /* parse version string */
93 ver = atoi(p);
94 if (ver != 1) {
95 u_mutex_unlock(mutex);
96 return;
97 }
98 p += strlen(p) + 1;
99
100 while (*p) {
101 const struct mapi_stub *stub;
102
103 stub = get_stub(p, NULL);
104 /* out of dynamic entries */
105 if (!stub)
106 break;
107 p += strlen(p) + 1;
108
109 while (*p) {
110 get_stub(p, stub);
111 p += strlen(p) + 1;
112 }
113
114 mapi_stub_map[count++] = stub;
115 p++;
116 }
117
118 mapi_num_stubs = count;
119
120 u_mutex_unlock(mutex);
121 }
122
123 /**
124 * Return the address of an entry. Optionally generate the entry if it does
125 * not exist.
126 */
127 mapi_proc
128 mapi_get_proc_address(const char *name)
129 {
130 const struct mapi_stub *stub;
131
132 stub = stub_find_public(name);
133 if (!stub)
134 stub = stub_find_dynamic(name, 0);
135
136 return (stub) ? (mapi_proc) stub->addr : NULL;
137 }
138
139 /**
140 * Create a dispatch table.
141 */
142 struct mapi_table *
143 mapi_table_create(void)
144 {
145 const struct mapi_table *noop = table_get_noop();
146 struct mapi_table *tbl;
147
148 tbl = malloc(sizeof(*tbl));
149 if (tbl)
150 memcpy(tbl, noop, sizeof(*tbl));
151
152 return tbl;
153 }
154
155 /**
156 * Destroy a dispatch table.
157 */
158 void
159 mapi_table_destroy(struct mapi_table *tbl)
160 {
161 free(tbl);
162 }
163
164 /**
165 * Fill a dispatch table. The order of the procs is determined when mapi_init
166 * is called.
167 */
168 void
169 mapi_table_fill(struct mapi_table *tbl, const mapi_proc *procs)
170 {
171 const struct mapi_table *noop = table_get_noop();
172 int i;
173
174 for (i = 0; i < mapi_num_stubs; i++) {
175 const struct mapi_stub *stub = mapi_stub_map[i];
176 mapi_func func = (mapi_func) procs[i];
177
178 if (!func)
179 func = table_get_func(noop, stub);
180 table_set_func(tbl, stub, func);
181 }
182 }
183
184 /**
185 * Make a dispatch table current.
186 */
187 void
188 mapi_table_make_current(const struct mapi_table *tbl)
189 {
190 u_current_set(tbl);
191 }