1 /***************************************************************************
2
3 driver.c
4
5 Driver construction helpers.
6
7 Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
8 Visit http://mamedev.org for licensing and usage restrictions.
9
10 ***************************************************************************/
11
12 #include "driver.h"
13 #include <ctype.h>
14
15
16
17 #if 0 /* QUASI88 */
18 /***************************************************************************
19 CONSTANTS
20 ***************************************************************************/
21
22 #define DRIVER_LRU_SIZE 10
23
24
25
26 /***************************************************************************
27 GLOBAL VARIABLES
28 ***************************************************************************/
29
30 static int driver_lru[DRIVER_LRU_SIZE];
31
32
33
34 /***************************************************************************
35 FUNCTION PROTOTYPES
36 ***************************************************************************/
37
38 static int penalty_compare(const char *source, const char *target);
39
40
41
42 /***************************************************************************
43 MISCELLANEOUS BITS & PIECES
44 ***************************************************************************/
45
46 /*-------------------------------------------------
47 expand_machine_driver - construct a machine
48 driver from the macroized state
49 -------------------------------------------------*/
50
51 void expand_machine_driver(void (*constructor)(machine_config *), machine_config *output)
52 {
53 /* initialize the tag on the first screen */
54 memset(output, 0, sizeof(*output));
55
56 /* keeping this function allows us to pre-init the driver before constructing it */
57 (*constructor)(output);
58
59 /* if no screen tagged, tag screen 0 as main */
60 if (output->screen[0].tag == NULL && output->screen[0].defstate.format != BITMAP_FORMAT_INVALID)
61 output->screen[0].tag = "main";
62
63 /* if no screens, set a dummy refresh for the main screen */
64 if (output->screen[0].tag == NULL)
65 output->screen[0].defstate.refresh = 60;
66 }
67
68
69 /*-------------------------------------------------
70 driver_add_cpu - add a CPU during machine
71 driver expansion
72 -------------------------------------------------*/
73
74 cpu_config *driver_add_cpu(machine_config *machine, const char *tag, int type, int cpuclock)
75 {
76 int cpunum;
77
78 for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
79 if (machine->cpu[cpunum].cpu_type == 0)
80 {
81 machine->cpu[cpunum].tag = tag;
82 machine->cpu[cpunum].cpu_type = type;
83 machine->cpu[cpunum].cpu_clock = cpuclock;
84 return &machine->cpu[cpunum];
85 }
86
87 fatalerror("Out of CPU's!\n");
88 return NULL;
89 }
90
91
92 /*-------------------------------------------------
93 driver_find_cpu - find a tagged CPU during
94 machine driver expansion
95 -------------------------------------------------*/
96
97 cpu_config *driver_find_cpu(machine_config *machine, const char *tag)
98 {
99 int cpunum;
100
101 for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
102 if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0)
103 return &machine->cpu[cpunum];
104
105 fatalerror("Can't find CPU '%s'!\n", tag);
106 return NULL;
107 }
108
109
110 /*-------------------------------------------------
111 driver_remove_cpu - remove a tagged CPU
112 during machine driver expansion
113 -------------------------------------------------*/
114
115 void driver_remove_cpu(machine_config *machine, const char *tag)
116 {
117 int cpunum;
118
119 for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
120 if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0)
121 {
122 memmove(&machine->cpu[cpunum], &machine->cpu[cpunum + 1], sizeof(machine->cpu[0]) * (MAX_CPU - cpunum - 1));
123 memset(&machine->cpu[MAX_CPU - 1], 0, sizeof(machine->cpu[0]));
124 return;
125 }
126
127 fatalerror("Can't find CPU '%s'!\n", tag);
128 }
129 #endif /* QUASI88 */
130
131
132 /*-------------------------------------------------
133 driver_add_speaker - add a speaker during
134 machine driver expansion
135 -------------------------------------------------*/
136
driver_add_speaker(machine_config * machine,const char * tag,float x,float y,float z)137 speaker_config *driver_add_speaker(machine_config *machine, const char *tag, float x, float y, float z)
138 {
139 int speakernum;
140
141 for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++)
142 if (machine->speaker[speakernum].tag == NULL)
143 {
144 machine->speaker[speakernum].tag = tag;
145 machine->speaker[speakernum].x = x;
146 machine->speaker[speakernum].y = y;
147 machine->speaker[speakernum].z = z;
148 return &machine->speaker[speakernum];
149 }
150
151 fatalerror("Out of speakers!\n");
152 return NULL;
153 }
154
155
156 /*-------------------------------------------------
157 driver_find_speaker - find a tagged speaker
158 system during machine driver expansion
159 -------------------------------------------------*/
160
driver_find_speaker(machine_config * machine,const char * tag)161 speaker_config *driver_find_speaker(machine_config *machine, const char *tag)
162 {
163 int speakernum;
164
165 for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++)
166 if (machine->speaker[speakernum].tag && strcmp(machine->speaker[speakernum].tag, tag) == 0)
167 return &machine->speaker[speakernum];
168
169 fatalerror("Can't find speaker '%s'!\n", tag);
170 return NULL;
171 }
172
173
174 /*-------------------------------------------------
175 driver_remove_speaker - remove a tagged speaker
176 system during machine driver expansion
177 -------------------------------------------------*/
178
driver_remove_speaker(machine_config * machine,const char * tag)179 void driver_remove_speaker(machine_config *machine, const char *tag)
180 {
181 int speakernum;
182
183 for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++)
184 if (machine->speaker[speakernum].tag && strcmp(machine->speaker[speakernum].tag, tag) == 0)
185 {
186 memmove(&machine->speaker[speakernum], &machine->speaker[speakernum + 1], sizeof(machine->speaker[0]) * (MAX_SPEAKER - speakernum - 1));
187 memset(&machine->speaker[MAX_SPEAKER - 1], 0, sizeof(machine->speaker[0]));
188 return;
189 }
190
191 fatalerror("Can't find speaker '%s'!\n", tag);
192 }
193
194
195 /*-------------------------------------------------
196 driver_add_sound - add a sound system during
197 machine driver expansion
198 -------------------------------------------------*/
199
driver_add_sound(machine_config * machine,const char * tag,int type,int clock)200 sound_config *driver_add_sound(machine_config *machine, const char *tag, int type, int clock)
201 {
202 int soundnum;
203
204 for (soundnum = 0; soundnum < MAX_SOUND; soundnum++)
205 if (machine->sound[soundnum].sound_type == 0)
206 {
207 machine->sound[soundnum].tag = tag;
208 machine->sound[soundnum].sound_type = type;
209 machine->sound[soundnum].clock = clock;
210 machine->sound[soundnum].config = NULL;
211 machine->sound[soundnum].routes = 0;
212 return &machine->sound[soundnum];
213 }
214
215 fatalerror("Out of sounds!\n");
216 return NULL;
217 }
218
219
220 /*-------------------------------------------------
221 driver_find_sound - find a tagged sound
222 system during machine driver expansion
223 -------------------------------------------------*/
224
driver_find_sound(machine_config * machine,const char * tag)225 sound_config *driver_find_sound(machine_config *machine, const char *tag)
226 {
227 int soundnum;
228
229 for (soundnum = 0; soundnum < MAX_SOUND; soundnum++)
230 if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0)
231 return &machine->sound[soundnum];
232
233 fatalerror("Can't find sound '%s'!\n", tag);
234 return NULL;
235 }
236
237
238 /*-------------------------------------------------
239 driver_remove_sound - remove a tagged sound
240 system during machine driver expansion
241 -------------------------------------------------*/
242
driver_remove_sound(machine_config * machine,const char * tag)243 void driver_remove_sound(machine_config *machine, const char *tag)
244 {
245 int soundnum;
246
247 for (soundnum = 0; soundnum < MAX_SOUND; soundnum++)
248 if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0)
249 {
250 memmove(&machine->sound[soundnum], &machine->sound[soundnum + 1], sizeof(machine->sound[0]) * (MAX_SOUND - soundnum - 1));
251 memset(&machine->sound[MAX_SOUND - 1], 0, sizeof(machine->sound[0]));
252 return;
253 }
254
255 fatalerror("Can't find sound '%s'!\n", tag);
256 }
257
258
259 #if 0 /* QUASI88 */
260 /*-------------------------------------------------
261 driver_add_screen - add a screen during
262 machine driver expansion
263 -------------------------------------------------*/
264
265 screen_config *driver_add_screen(machine_config *machine, const char *tag, int palbase)
266 {
267 int screennum;
268
269 for (screennum = 0; screennum < MAX_SCREENS; screennum++)
270 if (machine->screen[screennum].tag == NULL)
271 {
272 machine->screen[screennum].tag = tag;
273 machine->screen[screennum].palette_base = palbase;
274 return &machine->screen[screennum];
275 }
276
277 fatalerror("Out of screens!\n");
278 return NULL;
279 }
280
281
282 /*-------------------------------------------------
283 driver_find_screen - find a tagged screen
284 during machine driver expansion
285 -------------------------------------------------*/
286
287 screen_config *driver_find_screen(machine_config *machine, const char *tag)
288 {
289 int screennum;
290
291 for (screennum = 0; screennum < MAX_SCREENS; screennum++)
292 if (machine->screen[screennum].tag && strcmp(machine->screen[screennum].tag, tag) == 0)
293 return &machine->screen[screennum];
294
295 fatalerror("Can't find screen '%s'!\n", tag);
296 return NULL;
297 }
298
299
300 /*-------------------------------------------------
301 driver_remove_screen - remove a tagged screen
302 during machine driver expansion
303 -------------------------------------------------*/
304
305 void driver_remove_screen(machine_config *machine, const char *tag)
306 {
307 int screennum;
308
309 for (screennum = 0; screennum < MAX_SCREENS; screennum++)
310 if (machine->screen[screennum].tag && strcmp(machine->screen[screennum].tag, tag) == 0)
311 {
312 memmove(&machine->screen[screennum], &machine->screen[screennum + 1], sizeof(machine->screen[0]) * (MAX_SCREENS - screennum - 1));
313 memset(&machine->screen[MAX_SCREENS - 1], 0, sizeof(machine->screen[0]));
314 return;
315 }
316
317 fatalerror("Can't find screen '%s'!\n", tag);
318 }
319
320
321 /*-------------------------------------------------
322 driver_get_index - return the index of a
323 driver given its name.
324 -------------------------------------------------*/
325
326 int driver_get_index(const char *name)
327 {
328 int lurnum, drvnum;
329
330 /* scan the LRU list first */
331 for (lurnum = 0; lurnum < DRIVER_LRU_SIZE; lurnum++)
332 if (mame_stricmp(drivers[driver_lru[lurnum]]->name, name) == 0)
333 {
334 /* if not first, swap with the head */
335 if (lurnum != 0)
336 {
337 int temp = driver_lru[0];
338 driver_lru[0] = driver_lru[lurnum];
339 driver_lru[lurnum] = temp;
340 }
341 return driver_lru[0];
342 }
343
344 /* scan for a match in the drivers -- slow! */
345 for (drvnum = 0; drivers[drvnum] != NULL; drvnum++)
346 if (mame_stricmp(drivers[drvnum]->name, name) == 0)
347 {
348 memmove((void *)&driver_lru[1], (void *)&driver_lru[0], sizeof(driver_lru[0]) * (DRIVER_LRU_SIZE - 1));
349 driver_lru[0] = drvnum;
350 return drvnum;
351 }
352
353 /* shouldn't happen */
354 return -1;
355 }
356
357
358 /*-------------------------------------------------
359 driver_get_clone - return a pointer to the
360 clone of a game driver.
361 -------------------------------------------------*/
362
363 const game_driver *driver_get_clone(const game_driver *driver)
364 {
365 int index;
366
367 /* if no clone, easy out */
368 if (driver->parent == NULL || (driver->parent[0] == '0' && driver->parent[1] == 0))
369 return NULL;
370
371 /* convert the name to an index */
372 index = driver_get_index(driver->parent);
373 return (index == -1) ? NULL : drivers[index];
374 }
375
376
377 /*-------------------------------------------------
378 driver_get_approx_matches - find the best n
379 matches to a driver name.
380 -------------------------------------------------*/
381
382 void driver_get_approx_matches(const char *name, int matches, int *indexes)
383 {
384 int *penalty;
385 int drvnum;
386 int matchnum;
387
388 /* allocate some temp memory */
389 penalty = malloc_or_die(matches * sizeof(*penalty));
390
391 /* initialize everyone's states */
392 for (matchnum = 0; matchnum < matches; matchnum++)
393 {
394 penalty[matchnum] = 9999;
395 indexes[matchnum] = -1;
396 }
397
398 /* scan the entire drivers array */
399 for (drvnum = 0; drivers[drvnum] != NULL; drvnum++)
400 {
401 int curpenalty, tmp;
402
403 /* skip non-drivers */
404 if ((drivers[drvnum]->flags & NOT_A_DRIVER) != 0)
405 continue;
406
407 /* pick the best match between driver name and description */
408 curpenalty = penalty_compare(name, drivers[drvnum]->description);
409 tmp = penalty_compare(name, drivers[drvnum]->name);
410 curpenalty = MIN(curpenalty, tmp);
411
412 /* insert into the sorted table of matches */
413 for (matchnum = matches - 1; matchnum >= 0; matchnum--)
414 {
415 /* stop if we're worse than the current entry */
416 if (curpenalty >= penalty[matchnum])
417 break;
418
419 /* as lng as this isn't the last entry, bump this one down */
420 if (matchnum < matches - 1)
421 {
422 penalty[matchnum + 1] = penalty[matchnum];
423 indexes[matchnum + 1] = indexes[matchnum];
424 }
425 indexes[matchnum] = drvnum;
426 penalty[matchnum] = curpenalty;
427 }
428 }
429
430 /* free our temp memory */
431 free(penalty);
432 }
433
434
435 /*-------------------------------------------------
436 penalty_compare - compare two strings for
437 closeness and assign a score.
438 -------------------------------------------------*/
439
440 static int penalty_compare(const char *source, const char *target)
441 {
442 int gaps = 0;
443 int last = 1;
444
445 /* scan the strings */
446 for ( ; *source && *target; target++)
447 {
448 /* do a case insensitive match */
449 int match = (tolower(*source) == tolower(*target));
450
451 /* if we matched, advance the source */
452 if (match)
453 source++;
454
455 /* if the match state changed, count gaps */
456 if (match != last)
457 {
458 last = match;
459 if (!match)
460 gaps++;
461 }
462 }
463
464 /* penalty if short string does not completely fit in */
465 for ( ; *source; source++)
466 gaps++;
467
468 return gaps;
469 }
470 #endif /* QUASI88 */
471