1 /* MikMod sound library
\r
2 (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
\r
5 This library is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU Library General Public License as
\r
7 published by the Free Software Foundation; either version 2 of
\r
8 the License, or (at your option) any later version.
\r
10 This program is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 GNU Library General Public License for more details.
\r
15 You should have received a copy of the GNU Library General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
\r
21 /*==============================================================================
\r
23 $Id: mdriver.c,v 1.3 2004/02/18 13:29:19 raph Exp $
\r
25 These routines are used to access the available soundcard drivers.
\r
27 ==============================================================================*/
\r
29 #ifdef HAVE_CONFIG_H
\r
33 #ifdef HAVE_UNISTD_H
\r
37 #if defined unix || (defined __APPLE__ && defined __MACH__)
\r
39 #include <sys/stat.h>
\r
43 #ifdef HAVE_STRINGS_H
\r
44 #include <strings.h>
\r
47 #include "mikmod_internals.h"
\r
50 extern int fprintf(FILE *, const char *, ...);
\r
53 static MDRIVER *firstdriver=NULL;
\r
55 extern MODULE *pf; /* modfile being played */
\r
57 /* Initial global settings */
\r
58 MIKMODAPI UWORD md_device = 0; /* autodetect */
\r
59 MIKMODAPI UWORD md_mixfreq = 44100;
\r
60 MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |
\r
61 DMODE_SURROUND |DMODE_SOFT_MUSIC |
\r
63 MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
\r
64 MIKMODAPI UBYTE md_reverb = 0; /* no reverb */
\r
65 MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */
\r
66 MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */
\r
67 MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */
\r
68 UWORD md_bpm = 125; /* tempo */
\r
70 /* Do not modify the numchn variables yourself! use MD_SetVoices() */
\r
71 UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;
\r
72 UBYTE md_hardchn=0,md_softchn=0;
\r
74 void (*md_player)(void) = Player_HandleTick;
\r
75 static BOOL isplaying=0, initialized = 0;
\r
76 static UBYTE *sfxinfo;
\r
79 static SAMPLE **md_sample = NULL;
\r
81 /* Previous driver in use *
\r
82 static SWORD olddevice = -1;
\r
84 /* Limits the number of hardware voices to the specified amount.
\r
85 This function should only be used by the low-level drivers. */
\r
86 static void LimitHardVoices(int limit)
\r
90 if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
\r
91 if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
\r
93 if (!(md_mode & DMODE_SOFT_SNDFX))
\r
94 md_hardchn=md_sfxchn;
\r
98 if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
\r
100 while (md_hardchn>limit) {
\r
102 if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
\r
104 if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
\r
107 if (!(md_mode & DMODE_SOFT_SNDFX))
\r
108 md_hardchn=md_sfxchn;
\r
112 if (!(md_mode & DMODE_SOFT_MUSIC))
\r
113 md_hardchn+=md_sngchn;
\r
115 md_numchn=md_hardchn+md_softchn;
\r
118 /* Limits the number of hardware voices to the specified amount.
\r
119 This function should only be used by the low-level drivers. */
\r
120 static void LimitSoftVoices(int limit)
\r
124 if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
\r
125 if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
\r
127 if (md_mode & DMODE_SOFT_SNDFX)
\r
128 md_softchn=md_sfxchn;
\r
132 if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;
\r
134 while (md_softchn>limit) {
\r
136 if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
\r
138 if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
\r
141 if (!(md_mode & DMODE_SOFT_SNDFX))
\r
142 md_softchn=md_sfxchn;
\r
146 if (!(md_mode & DMODE_SOFT_MUSIC))
\r
147 md_softchn+=md_sngchn;
\r
149 md_numchn=md_hardchn+md_softchn;
\r
152 /* Note: 'type' indicates whether the returned value should be for music or for
\r
154 ULONG MD_SampleSpace(int type)
\r
157 type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
\r
158 else if(type==MD_SNDFX)
\r
159 type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
\r
161 return VC_SampleSpace(type);
\r
164 ULONG MD_SampleLength(int type,SAMPLE* s)
\r
167 type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
\r
170 type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
\r
172 return VC_SampleLength(type,s);
\r
175 MIKMODAPI CHAR* MikMod_InfoDriver(void)
\r
182 /* compute size of buffer *
\r
183 for(l=firstdriver;l;l=l->next)
\r
184 len+=4+(l->next?1:0)+strlen(l->Version);
\r
187 if((list=_mm_malloc(len*sizeof(CHAR)))) {
\r
189 /* list all registered device drivers : *
\r
190 for(t=1,l=firstdriver;l;l=l->next,t++)
\r
191 sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",
\r
192 list,t,l->Version);
\r
194 MUTEX_UNLOCK(lists);
\r
198 void _mm_registerdriver(struct MDRIVER* drv)
\r
200 MDRIVER *cruise = firstdriver;
\r
202 /* don't register a MISSING() driver */
\r
203 if ((drv->Name) && (drv->Version)) {
\r
205 while (cruise->next) cruise = cruise->next;
\r
206 cruise->next = drv;
\r
208 firstdriver = drv;
\r
212 MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)
\r
214 /* if we try to register an invalid driver, or an already registered driver,
\r
215 ignore this attempt */
\r
216 if ((!drv)||(drv->next)||(!drv->Name))
\r
220 _mm_registerdriver(drv);
\r
221 MUTEX_UNLOCK(lists);
\r
224 MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)
\r
230 cruise=firstdriver;
\r
232 if (cruise->Alias) {
\r
233 if (!(strcasecmp(alias,cruise->Alias))) break;
\r
236 cruise=cruise->next;
\r
238 if(!cruise) rank=0;
\r
239 MUTEX_UNLOCK(lists);
\r
244 MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)
\r
248 /* Allow only driver ordinals > 0 */
\r
253 cruise = firstdriver;
\r
254 while (cruise && --ordinal)
\r
255 cruise = cruise->next;
\r
256 MUTEX_UNLOCK(lists);
\r
260 SWORD MD_SampleLoad(SAMPLOAD* s, int type)
\r
265 type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
\r
266 else if(type==MD_SNDFX)
\r
267 type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
\r
270 result=VC_SampleLoad(s,type);
\r
276 void MD_SampleUnload(SWORD handle)
\r
278 VC_SampleUnload(handle);
\r
281 MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
\r
283 MikMod_player_t result;
\r
288 MUTEX_UNLOCK(vars);
\r
293 MIKMODAPI void MikMod_Update(void)
\r
296 /* FIXME - if I'm broken...
\r
299 if((!pf)||(!pf->forbid))
\r
301 md_driver->Update();
\r
305 if (md_driver->Pause)
\r
306 md_driver->Pause();
\r
310 MUTEX_UNLOCK(vars);
\r
313 void Voice_SetVolume_internal(SBYTE voice,UWORD vol)
\r
317 if((voice<0)||(voice>=md_numchn)) return;
\r
320 if(md_musicvolume>128) md_musicvolume=128;
\r
321 if(md_sndfxvolume>128) md_sndfxvolume=128;
\r
322 if(md_volume>128) md_volume=128;
\r
324 tmp=(ULONG)vol*(ULONG)md_volume*
\r
325 ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
\r
326 VC_VoiceSetVolume(voice,tmp/16384UL);
\r
329 MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
\r
332 Voice_SetVolume_internal(voice,vol);
\r
333 MUTEX_UNLOCK(vars);
\r
336 MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)
\r
341 if((voice>=0)&&(voice<md_numchn))
\r
342 result=VC_VoiceGetVolume(voice);
\r
343 MUTEX_UNLOCK(vars);
\r
348 void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)
\r
350 if((voice<0)||(voice>=md_numchn)) return;
\r
351 if((md_sample[voice])&&(md_sample[voice]->divfactor))
\r
352 frq/=md_sample[voice]->divfactor;
\r
353 VC_VoiceSetFrequency(voice,frq);
\r
356 MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
\r
359 Voice_SetFrequency_internal(voice,frq);
\r
360 MUTEX_UNLOCK(vars);
\r
363 MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)
\r
368 if((voice>=0)&&(voice<md_numchn))
\r
369 result=VC_VoiceGetFrequency(voice);
\r
370 MUTEX_UNLOCK(vars);
\r
375 void Voice_SetPanning_internal(SBYTE voice,ULONG pan)
\r
377 if((voice<0)||(voice>=md_numchn)) return;
\r
378 if(pan!=PAN_SURROUND) {
\r
379 if(md_pansep>128) md_pansep=128;
\r
380 if(md_mode & DMODE_REVERSE) pan=255-pan;
\r
381 pan = (((SWORD)(pan-128)*md_pansep)/128)+128;
\r
383 VC_VoiceSetPanning(voice, pan);
\r
386 MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)
\r
388 #ifdef MIKMOD_DEBUG
\r
389 if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))
\r
390 fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);
\r
394 Voice_SetPanning_internal(voice,pan);
\r
395 MUTEX_UNLOCK(vars);
\r
398 MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)
\r
400 ULONG result=PAN_CENTER;
\r
403 if((voice>=0)&&(voice<md_numchn))
\r
404 result=VC_VoiceGetPanning(voice);
\r
405 MUTEX_UNLOCK(vars);
\r
410 void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)
\r
414 if((voice<0)||(voice>=md_numchn)) return;
\r
416 md_sample[voice]=s;
\r
419 if(s->flags&SF_LOOP)
\r
420 /* repend can't be bigger than size */
\r
421 if(repend>s->length) repend=s->length;
\r
423 VC_VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
\r
426 MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
\r
428 if(start>s->length) return;
\r
431 Voice_Play_internal(voice,s,start);
\r
432 MUTEX_UNLOCK(vars);
\r
435 void Voice_Stop_internal(SBYTE voice)
\r
437 if((voice<0)||(voice>=md_numchn)) return;
\r
438 if(voice>=md_sngchn)
\r
439 /* It is a sound effects channel, so flag the voice as non-critical! */
\r
440 sfxinfo[voice-md_sngchn]=0;
\r
441 VC_VoiceStop(voice);
\r
444 MIKMODAPI void Voice_Stop(SBYTE voice)
\r
447 Voice_Stop_internal(voice);
\r
448 MUTEX_UNLOCK(vars);
\r
451 BOOL Voice_Stopped_internal(SBYTE voice)
\r
453 if((voice<0)||(voice>=md_numchn)) return 0;
\r
454 return(VC_VoiceStopped(voice));
\r
457 MIKMODAPI BOOL Voice_Stopped(SBYTE voice)
\r
462 result=Voice_Stopped_internal(voice);
\r
463 MUTEX_UNLOCK(vars);
\r
468 MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)
\r
473 if((voice>=0)&&(voice<md_numchn)) {
\r
474 /*if (VC_VoiceGetPosition)*/
\r
475 result=(VC_VoiceGetPosition(voice));
\r
479 MUTEX_UNLOCK(vars);
\r
484 MIKMODAPI ULONG Voice_RealVolume(SBYTE voice)
\r
489 if((voice>=0)&&(voice<md_numchn)/*&& VC_VoiceRealVolume*/)
\r
490 result=(VC_VoiceRealVolume(voice));
\r
491 MUTEX_UNLOCK(vars);
\r
496 static BOOL _mm_init(CHAR *cmdline)
\r
503 /* if md_device==0, try to find a device number *
\r
507 for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)
\r
508 if(md_driver->IsPresent()) break;
\r
511 _mm_errno = MMERR_DETECTING_DEVICE;
\r
512 if(_mm_errorhandler) _mm_errorhandler();
\r
513 md_driver = &drv_nos;
\r
519 /* if n>0, use that driver *
\r
520 for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next)
\r
524 _mm_errno = MMERR_INVALID_DEVICE;
\r
525 if(_mm_errorhandler) _mm_errorhandler();
\r
526 md_driver = &drv_nos;
\r
530 /* arguments here might be necessary for the presence check to succeed *
\r
531 if(cmdline&&(md_driver->CommandLine))
\r
532 md_driver->CommandLine(cmdline);
\r
534 if(!md_driver->IsPresent()) {
\r
535 _mm_errno = MMERR_DETECTING_DEVICE;
\r
536 if(_mm_errorhandler) _mm_errorhandler();
\r
537 md_driver = &drv_nos;
\r
542 olddevice = md_device;
\r
544 md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
\r
547 MikMod_Exit_internal();
\r
548 if(_mm_errorhandler) _mm_errorhandler();
\r
558 MIKMODAPI BOOL MikMod_Init(CHAR *cmdline)
\r
564 result=_mm_init(cmdline);
\r
565 MUTEX_UNLOCK(lists);
\r
566 MUTEX_UNLOCK(vars);
\r
571 void MikMod_Exit_internal(void)
\r
573 MikMod_DisableOutput_internal();
\r
575 md_numchn = md_sfxchn = md_sngchn = 0;
\r
576 //md_driver = &drv_nos;
\r
578 if(sfxinfo) free(sfxinfo);
\r
579 if(md_sample) free(md_sample);
\r
586 MIKMODAPI void MikMod_Exit(void)
\r
590 MikMod_Exit_internal();
\r
591 MUTEX_UNLOCK(lists);
\r
592 MUTEX_UNLOCK(vars);
\r
595 /* Reset the driver using the new global variable settings.
\r
596 If the driver has not been initialized, it will be now. */
\r
597 static BOOL _mm_reset(CHAR *cmdline)
\r
599 BOOL wasplaying = 0;
\r
601 if(!initialized) return _mm_init(cmdline);
\r
608 if((!md_driver->Reset)||(md_device != olddevice)) {
\r
609 /* md_driver->Reset was NULL, or md_device was changed, so do a full
\r
610 reset of the driver. *
\r
612 if(_mm_init(cmdline)) {
\r
613 MikMod_Exit_internal();
\r
615 if(_mm_errorhandler) _mm_errorhandler();
\r
619 if(md_driver->Reset()) {
\r
620 MikMod_Exit_internal();
\r
622 if(_mm_errorhandler) _mm_errorhandler();
\r
627 if (wasplaying) VC_PlayStart();
\r
631 MIKMODAPI BOOL MikMod_Reset(CHAR *cmdline)
\r
637 result=_mm_reset(cmdline);
\r
638 MUTEX_UNLOCK(lists);
\r
639 MUTEX_UNLOCK(vars);
\r
644 /* If either parameter is -1, the current set value will be retained. */
\r
645 BOOL MikMod_SetNumVoices_internal(int music, int sfx)
\r
650 if((!music)&&(!sfx)) return 1;
\r
653 MikMod_DisableOutput_internal();
\r
654 oldchn = md_numchn;
\r
658 if(sfxinfo) free(sfxinfo);
\r
659 if(md_sample) free(md_sample);
\r
663 if(music!=-1) md_sngchn = music;
\r
664 if(sfx!=-1) md_sfxchn = sfx;
\r
665 md_numchn = md_sngchn + md_sfxchn;
\r
667 LimitHardVoices(md_driver->HardVoiceLimit);
\r
668 LimitSoftVoices(md_driver->SoftVoiceLimit);
\r
670 LimitHardVoices(0);
\r
671 LimitSoftVoices(255);
\r
673 if(VC_SetNumVoices()) {
\r
674 MikMod_Exit_internal();
\r
676 if(_mm_errorhandler!=NULL) _mm_errorhandler();
\r
677 md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
\r
681 if(md_sngchn+md_sfxchn)
\r
682 md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));
\r
684 sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE));
\r
686 /* make sure the player doesn't start with garbage */
\r
687 for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t);
\r
690 if(resume) MikMod_EnableOutput_internal();
\r
696 MIKMODAPI BOOL MikMod_SetNumVoices(int music, int sfx)
\r
701 result=MikMod_SetNumVoices_internal(music,sfx);
\r
702 MUTEX_UNLOCK(vars);
\r
707 BOOL MikMod_EnableOutput_internal(void)
\r
711 if(VC_PlayStart()) return 1;
\r
718 MIKMODAPI BOOL MikMod_EnableOutput(void)
\r
723 result=MikMod_EnableOutput_internal();
\r
724 MUTEX_UNLOCK(vars);
\r
729 void MikMod_DisableOutput_internal(void)
\r
731 if(isplaying/* && md_driver*/) {
\r
737 MIKMODAPI void MikMod_DisableOutput(void)
\r
740 MikMod_DisableOutput_internal();
\r
741 MUTEX_UNLOCK(vars);
\r
744 BOOL MikMod_Active_internal(void)
\r
749 MIKMODAPI BOOL MikMod_Active(void)
\r
754 result=MikMod_Active_internal();
\r
755 MUTEX_UNLOCK(vars);
\r
760 /* Plays a sound effects sample. Picks a voice from the number of voices
\r
761 allocated for use as sound effects (loops through voices, skipping all active
\r
764 Returns the voice that the sound is being played on. */
\r
765 SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)
\r
767 int orig=sfxpool;/* for cases where all channels are critical */
\r
770 if(!md_sfxchn) return -1;
\r
771 if(s->volume>64) s->volume = 64;
\r
773 /* check the first location after sfxpool */
\r
775 if(sfxinfo[sfxpool]&SFX_CRITICAL) {
\r
776 if(VC_VoiceStopped(c=sfxpool+md_sngchn)) {
\r
777 sfxinfo[sfxpool]=flags;
\r
778 Voice_Play_internal(c,s,start);
\r
779 VC_VoiceSetVolume(c,s->volume<<2);
\r
780 Voice_SetPanning_internal(c,s->panning);
\r
781 VC_VoiceSetFrequency(c,s->speed);
\r
783 if(sfxpool>=md_sfxchn) sfxpool=0;
\r
787 sfxinfo[sfxpool]=flags;
\r
788 Voice_Play_internal(c=sfxpool+md_sngchn,s,start);
\r
789 VC_VoiceSetVolume(c,s->volume<<2);
\r
790 Voice_SetPanning_internal(c,s->panning);
\r
791 VC_VoiceSetFrequency(c,s->speed);
\r
793 if(sfxpool>=md_sfxchn) sfxpool=0;
\r
798 if(sfxpool>=md_sfxchn) sfxpool = 0;
\r
799 } while(sfxpool!=orig);
\r
804 MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)
\r
809 result=Sample_Play_internal(s,start,flags);
\r
810 MUTEX_UNLOCK(vars);
\r
815 MIKMODAPI long MikMod_GetVersion(void)
\r
817 return LIBMIKMOD_VERSION;
\r
820 /*========== MT-safe stuff */
\r
822 #ifdef HAVE_PTHREAD
\r
823 #define INIT_MUTEX(name) \
\r
824 pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER
\r
825 #elif defined(__OS2__)||defined(__EMX__)
\r
826 #define INIT_MUTEX(name) \
\r
827 HMTX _mm_mutex_##name
\r
828 #elif defined(WIN32)
\r
829 #define INIT_MUTEX(name) \
\r
830 HANDLE _mm_mutex_##name
\r
832 #define INIT_MUTEX(name) \
\r
833 void *_mm_mutex_##name = NULL
\r
839 MIKMODAPI BOOL MikMod_InitThreads(void)
\r
841 static int firstcall=1;
\r
842 static int result=0;
\r
846 #ifdef HAVE_PTHREAD
\r
848 #elif defined(__OS2__)||defined(__EMX__)
\r
849 if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) ||
\r
850 DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) {
\r
851 _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL;
\r
855 #elif defined(WIN32)
\r
856 if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))||
\r
857 (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)"))))
\r
866 MIKMODAPI void MikMod_Unlock(void)
\r
868 MUTEX_UNLOCK(lists);
\r
869 MUTEX_UNLOCK(vars);
\r
872 MIKMODAPI void MikMod_Lock(void)
\r
878 /*========== Parameter extraction helper */
\r
880 CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,BOOL implicit)
\r
885 CHAR *buf=strstr(cmdline,atomname);
\r
887 if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {
\r
888 CHAR *ptr=buf+strlen(atomname);
\r
891 for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);
\r
892 ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));
\r
894 strncpy(ret,buf,ptr-buf);
\r
895 } else if((*ptr==',')||(!*ptr)) {
\r
897 ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));
\r
899 strncpy(ret,buf,ptr-buf);
\r
907 #if defined unix || (defined __APPLE__ && defined __MACH__)
\r
909 /*========== Posix helper functions */
\r
911 /* Check if the file is a regular or nonexistant file (or a link to a such a
\r
912 file), and that, should the calling program be setuid, the access rights are
\r
913 reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise.
\r
914 The goal is to prevent a setuid root libmikmod application from overriding
\r
915 files like /etc/passwd with digital sound... */
\r
916 BOOL MD_Access(CHAR *filename)
\r
920 if(!stat(filename,&buf)) {
\r
921 /* not a regular file ? */
\r
922 if(!S_ISREG(buf.st_mode)) return 0;
\r
923 /* more than one hard link to the file ? */
\r
924 if(buf.st_nlink>1) return 0;
\r
925 /* check access rights with the real user and group id */
\r
926 if(getuid()==buf.st_uid) {
\r
927 if(!(buf.st_mode&S_IWUSR)) return 0;
\r
928 } else if(getgid()==buf.st_gid) {
\r
929 if(!(buf.st_mode&S_IWGRP)) return 0;
\r
931 if(!(buf.st_mode&S_IWOTH)) return 0;
\r
937 /* Drop all root privileges we might have */
\r
938 BOOL MD_DropPrivileges(void)
\r
942 /* we are setuid root -> drop setuid to become the real user */
\r
943 if(setuid(getuid())) return 1;
\r
945 /* we are run as root -> drop all and become user 'nobody' */
\r
946 struct passwd *nobody;
\r
949 if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */
\r
950 uid=nobody->pw_uid;
\r
951 if (!uid) /* user 'nobody' has root privileges ? weird... */
\r
953 if (setuid(uid)) return 1;
\r