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