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