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 */
37static const struct mapi_stub *mapi_stub_map[MAPI_TABLE_NUM_SLOTS];
38static int mapi_num_stubs;
39
40static const struct mapi_stub *
41get_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 */
71void
72mapi_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 */
124mapi_proc
125mapi_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 */
139struct mapi_table *
140mapi_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 */
155void
156mapi_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 */
165void
166mapi_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 */
185void
186mapi_table_make_current(const struct mapi_table *tbl)
187{
188   u_current_set_table(tbl);
189}
190