Line data Source code
1 0 : /*
2 :
3 : OOConstToJSString.m
4 :
5 :
6 : Oolite
7 : Copyright (C) 2004-2013 Giles C Williams and contributors
8 :
9 : This program is free software; you can redistribute it and/or
10 : modify it under the terms of the GNU General Public License
11 : as published by the Free Software Foundation; either version 2
12 : of the License, or (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 : MA 02110-1301, USA.
23 :
24 : */
25 :
26 : #include "OOConstToJSString.h"
27 :
28 :
29 : /*
30 : Each type of constant has its own lookup table, which is a linear list of
31 : TableEntry structs plus a count.
32 :
33 : The list is statically initialized with the constant values and C strings.
34 : OOConstToJSStringInit() (through InitTable()) replaces the C strings with
35 : interned JSStrings (hence the void * type). These are subsequently
36 : constant and no other strings with the same value should occur, i.e. they
37 : should be comparable with pointer equality. Because I'm paranoid, we fall
38 : back to full string comparison if this fails.
39 :
40 : ConstTables are globals, which are accessed as local externs in the inlines
41 : in the header. All the advantages of globals with most of the advantages
42 : of encapsulation, sorta.
43 :
44 : -- Ahruman 2011-01-15
45 : */
46 :
47 0 : typedef struct
48 : {
49 0 : NSInteger value;
50 0 : const char *cString;
51 0 : JSString *jsString;
52 : } TableEntry;
53 :
54 0 : typedef struct ConstTable
55 : {
56 0 : NSUInteger count;
57 0 : TableEntry *entries;
58 0 : } ConstTable;
59 :
60 0 : #define TABLE(entries) { sizeof entries / sizeof *entries, entries }
61 :
62 :
63 0 : static BOOL sInited = NO;
64 :
65 : /*
66 : The interned string "UNDEFINED", returned by OOJSStringFromConstantPRIVATE()
67 : if passed a bogus constant value.
68 : */
69 0 : static JSString *sUndefinedString;
70 :
71 :
72 : /*
73 : Initialize table contents (with C strings, see above) from table files.
74 : */
75 0 : #define ENTRY(label, val) { .value = label, .cString = #label },
76 0 : #define GALACTIC_HYPERSPACE_ENTRY(label, val) { .value = GALACTIC_HYPERSPACE_##label, .cString = #label },
77 0 : #define DIFF_STRING_ENTRY(label, string) { .value = label, .cString = string },
78 :
79 0 : static TableEntry sOOCompassModeTableEntries[] =
80 : {
81 : #include "OOCompassMode.tbl"
82 : };
83 :
84 0 : static TableEntry sOOEntityStatusTableEntries[] =
85 : {
86 : #include "OOEntityStatus.tbl"
87 : };
88 :
89 0 : static TableEntry sOOGalacticHyperspaceBehaviourTableEntries[] =
90 : {
91 : #include "OOGalacticHyperspaceBehaviour.tbl"
92 : };
93 :
94 0 : static TableEntry sOOGUIScreenIDTableEntries[] =
95 : {
96 : #include "OOGUIScreenID.tbl"
97 : };
98 :
99 0 : static TableEntry sOOScanClassTableEntries[] =
100 : {
101 : #include "OOScanClass.tbl"
102 : };
103 :
104 0 : static TableEntry sOOViewIDTableEntries[] =
105 : {
106 : #include "OOViewID.tbl"
107 : };
108 :
109 0 : static TableEntry sOOShipDamageTypeTableEntries[] =
110 : {
111 : #include "OOShipDamageType.tbl"
112 : };
113 :
114 0 : static TableEntry sOOLegalStatusReasonTableEntries[] =
115 : {
116 : #include "OOLegalStatusReason.tbl"
117 : };
118 :
119 0 : static TableEntry sOOLongRangeChartModeTableEntries[] =
120 : {
121 : #include "OOLongRangeChartMode.tbl"
122 : };
123 :
124 : #undef ENTRY
125 : #undef GALACTIC_HYPERSPACE_ENTRY
126 : #undef DIFF_STRING_ENTRY
127 :
128 :
129 0 : ConstTable gOOCompassModeConstTable = TABLE(sOOCompassModeTableEntries);
130 0 : ConstTable gOOEntityStatusConstTable = TABLE(sOOEntityStatusTableEntries);
131 0 : ConstTable gOOGalacticHyperspaceBehaviourConstTable = TABLE(sOOGalacticHyperspaceBehaviourTableEntries);
132 0 : ConstTable gOOGUIScreenIDConstTable = TABLE(sOOGUIScreenIDTableEntries);
133 0 : ConstTable gOOScanClassConstTable = TABLE(sOOScanClassTableEntries);
134 0 : ConstTable gOOViewIDConstTable = TABLE(sOOViewIDTableEntries);
135 0 : ConstTable gOOShipDamageTypeConstTable = TABLE(sOOShipDamageTypeTableEntries);
136 0 : ConstTable gOOLegalStatusReasonConstTable = TABLE(sOOLegalStatusReasonTableEntries);
137 0 : ConstTable gOOLongRangeChartModeConstTable = TABLE(sOOLongRangeChartModeTableEntries);
138 :
139 : static void InitTable(JSContext *context, ConstTable *table);
140 :
141 :
142 : // MARK: Initialization
143 :
144 0 : void OOConstToJSStringInit(JSContext *context)
145 : {
146 : NSCAssert(!sInited, @"OOConstToJSStringInit() called while already inited.");
147 : NSCParameterAssert(context != NULL && JS_IsInRequest(context));
148 :
149 : sUndefinedString = JS_InternString(context, "UNDEFINED");
150 :
151 : InitTable(context, &gOOEntityStatusConstTable);
152 : InitTable(context, &gOOCompassModeConstTable);
153 : InitTable(context, &gOOGalacticHyperspaceBehaviourConstTable);
154 : InitTable(context, &gOOGUIScreenIDConstTable);
155 : InitTable(context, &gOOScanClassConstTable);
156 : InitTable(context, &gOOViewIDConstTable);
157 : InitTable(context, &gOOShipDamageTypeConstTable);
158 : InitTable(context, &gOOLegalStatusReasonConstTable);
159 : InitTable(context, &gOOLongRangeChartModeConstTable);
160 :
161 : sInited = YES;
162 : }
163 :
164 :
165 0 : void OOConstToJSStringDestroy(void)
166 : {
167 : NSCAssert(sInited, @"OOConstToJSStringDestroy() called while not inited.");
168 : sInited = NO;
169 : // jsString pointers are now officially junk.
170 : }
171 :
172 :
173 0 : static int CompareEntries(const void *a, const void *b)
174 : {
175 : const TableEntry *entA = a;
176 : const TableEntry *entB = b;
177 :
178 : if (entA->value < entB->value) return -1;
179 : if (entA->value > entB->value) return 1;
180 : return 0;
181 : }
182 :
183 :
184 0 : static void InitTable(JSContext *context, ConstTable *table)
185 : {
186 : NSCParameterAssert(context != NULL && JS_IsInRequest(context) && table != NULL);
187 :
188 : NSUInteger i;
189 : for(i = 0; i < table->count; i++)
190 : {
191 : table->entries[i].jsString = JS_InternString(context, table->entries[i].cString);
192 : }
193 :
194 : qsort(table->entries, table->count, sizeof *table->entries, CompareEntries);
195 : }
196 :
197 :
198 : // MARK: Lookup
199 :
200 0 : JSString *OOJSStringFromConstantPRIVATE(JSContext *context, NSInteger value, struct ConstTable *table)
201 : {
202 : NSCAssert1(sInited, @"%s called before OOConstToJSStringInit().", __PRETTY_FUNCTION__);
203 : NSCParameterAssert(context != NULL && JS_IsInRequest(context));
204 : NSCParameterAssert(table != NULL && table->count > 0);
205 :
206 : // Binary search.
207 : NSUInteger min = 0, max = table->count - 1;
208 : NSInteger current;
209 : do
210 : {
211 : NSUInteger mid = (min + max) / 2;
212 : current = table->entries[mid].value;
213 : if (current < value)
214 : {
215 : min = mid + 1;
216 : }
217 : else if (current > value)
218 : {
219 : max = mid - 1;
220 : }
221 : else
222 : {
223 : return table->entries[mid].jsString;
224 : }
225 : }
226 : while (min <= max);
227 :
228 : return sUndefinedString;
229 : }
230 :
231 :
232 0 : NSUInteger OOConstantFromJSStringPRIVATE(JSContext *context, JSString *string, struct ConstTable *table, NSInteger defaultValue)
233 : {
234 : NSCAssert1(sInited, @"%s called before OOConstToJSStringInit().", __PRETTY_FUNCTION__);
235 : NSCParameterAssert(context != NULL && JS_IsInRequest(context) && table != NULL);
236 :
237 : // Quick pass: look for pointer-equal string.
238 : NSUInteger i, count = table->count;
239 : for(i = 0; i < count; i++)
240 : {
241 : if (table->entries[i].jsString == string)
242 : {
243 : return table->entries[i].value;
244 : }
245 : }
246 :
247 :
248 : // Slow pass: use string comparison. This is expected to fail.
249 : if (string != NULL)
250 : {
251 : for(i = 0; i < count; i++)
252 : {
253 : int32 result;
254 : if (JS_CompareStrings(context, string, table->entries[i].jsString, &result) && result == 0)
255 : {
256 : return table->entries[i].value;
257 : }
258 : }
259 : }
260 :
261 : // Fail.
262 : return defaultValue;
263 : }
264 :
265 :
266 0 : NSUInteger OOConstantFromJSValuePRIVATE(JSContext *context, jsval value, struct ConstTable *table, NSInteger defaultValue)
267 : {
268 : if (EXPECT(JSVAL_IS_STRING(value)))
269 : {
270 : return OOConstantFromJSStringPRIVATE(context, JSVAL_TO_STRING(value), table, defaultValue);
271 : }
272 : else
273 : {
274 : return defaultValue;
275 : }
276 :
277 : }
|