Squashed 'libraries/ZMusic/' content from commit ac3e232b00

git-subtree-dir: libraries/ZMusic
git-subtree-split: ac3e232b001129c740b7b65196ae0e1b13b82513
This commit is contained in:
Rachael Alexanderson 2025-07-30 00:24:15 -04:00
commit 9f3cb3d92e
852 changed files with 381622 additions and 0 deletions

113
source/loader/i_module.cpp Normal file
View file

@ -0,0 +1,113 @@
/*
** i_module.cpp
**
**---------------------------------------------------------------------------
** Copyright 2016 Braden Obrzut
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "i_module.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#ifndef _WIN32
#define LoadLibraryA(x) dlopen((x), RTLD_LAZY)
#define GetProcAddress(a,b) dlsym((a),(b))
#define FreeLibrary(x) dlclose((x))
using HMODULE = void*;
#endif
bool FModule::Load(std::initializer_list<const char*> libnames)
{
for(auto lib : libnames)
{
if(!Open(lib))
continue;
StaticProc *proc;
for(proc = reqSymbols;proc;proc = proc->Next)
{
if(!(proc->Call = GetSym(proc->Name)) && !proc->Optional)
{
Unload();
break;
}
}
if(IsLoaded())
return true;
}
return false;
}
void FModule::Unload()
{
if(handle)
{
FreeLibrary((HMODULE)handle);
handle = nullptr;
}
}
bool FModule::Open(const char* lib)
{
#ifdef _WIN32
if((handle = GetModuleHandleA(lib)) != nullptr)
return true;
#else
// Loading an empty string in Linux doesn't do what we expect it to.
if(*lib == '\0')
return false;
#endif
handle = LoadLibraryA(lib);
return handle != nullptr;
}
void *FModule::GetSym(const char* name)
{
return (void *)GetProcAddress((HMODULE)handle, name);
}
static std::string module_progdir("."); // current program directory used to look up dynamic libraries. Default to something harmless in case the user didn't set it.
void FModule_SetProgDir(const char* progdir)
{
module_progdir = progdir;
}
const std::string& FModule_GetProgDir()
{
return module_progdir;
}

233
source/loader/i_module.h Normal file
View file

@ -0,0 +1,233 @@
/*
** i_module.h
**
**---------------------------------------------------------------------------
** Copyright 2016 Braden Obrzut
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#pragma once
#include <assert.h>
#include <string>
#include <initializer_list>
/* FModule Run Time Library Loader
*
* This provides an interface for loading optional dependencies or detecting
* version specific symbols at run time. These classes largely provide an
* interface for statically declaring the symbols that are going to be used
* ahead of time, thus should not be used on the stack or as part of a
* dynamically allocated object. The procedure templates take the FModule
* as a template argument largely to make such use of FModule awkward.
*
* Declared procedures register themselves with FModule and the module will not
* be considered loaded unless all required procedures can be resolved. In
* order to remove the need for boilerplate code, optional procedures do not
* enforce the requirement that the value is null checked before use. As a
* debugging aid debug builds will check that operator bool was called at some
* point, but this is just a first order sanity check.
*/
class FModule;
class FStaticModule;
template<FModule &Module, typename Proto>
class TOptProc;
template<FModule &Module, typename Proto>
class TReqProc;
template<FStaticModule &Module, typename Proto, Proto Sym>
class TStaticProc;
class FModule
{
template<FModule &Module, typename Proto>
friend class TOptProc;
template<FModule &Module, typename Proto>
friend class TReqProc;
struct StaticProc
{
void *Call;
const char* Name;
StaticProc *Next;
bool Optional;
};
void RegisterStatic(StaticProc &proc)
{
proc.Next = reqSymbols;
reqSymbols = &proc;
}
void *handle = nullptr;
// Debugging aid
const char *name;
// Since FModule is supposed to be statically allocated it is assumed that
// reqSymbols will be initialized to nullptr avoiding initialization order
// problems with declaring procedures.
StaticProc *reqSymbols;
bool Open(const char* lib);
void *GetSym(const char* name);
public:
template<FModule &Module, typename Proto, Proto Sym>
using Opt = TOptProc<Module, Proto>;
template<FModule &Module, typename Proto, Proto Sym>
using Req = TReqProc<Module, Proto>;
FModule(const char* name) : name(name) {};
~FModule() { Unload(); }
// Load a shared library using the first library name which satisfies all
// of the required symbols.
bool Load(std::initializer_list<const char*> libnames);
void Unload();
bool IsLoaded() const { return handle != nullptr; }
};
// Null version of FModule which satisfies the API so the same code can be used
// for run time and compile time linking.
class FStaticModule
{
template<FStaticModule &Module, typename Proto, Proto Sym>
friend class TStaticProc;
const char *name;
public:
template<FStaticModule &Module, typename Proto, Proto Sym>
using Opt = TStaticProc<Module, Proto, Sym>;
template<FStaticModule &Module, typename Proto, Proto Sym>
using Req = TStaticProc<Module, Proto, Sym>;
FStaticModule(const char* name) : name(name) {};
bool Load(std::initializer_list<const char*> libnames) { return true; }
void Unload() {}
bool IsLoaded() const { return true; }
};
// Allow FModuleMaybe<DYN_XYZ> to switch based on preprocessor flag.
// Use FModuleMaybe<DYN_XYZ>::Opt and FModuleMaybe<DYN_XYZ>::Req for procs.
template<bool Dynamic>
struct TModuleType { using Type = FModule; };
template<>
struct TModuleType<false> { using Type = FStaticModule; };
template<bool Dynamic>
using FModuleMaybe = typename TModuleType<Dynamic>::Type;
// ------------------------------------------------------------------------
template<FModule &Module, typename Proto>
class TOptProc
{
FModule::StaticProc proc;
#ifndef NDEBUG
mutable bool checked = false;
#endif
// I am not a pointer
bool operator==(void*) const;
bool operator!=(void*) const;
public:
TOptProc(const char* function)
{
proc.Name = function;
proc.Optional = true;
Module.RegisterStatic(proc);
}
operator Proto() const
{
#ifndef NDEBUG
assert(checked);
#endif
return (Proto)proc.Call;
}
explicit operator bool() const
{
#ifndef NDEBUG
assert(Module.IsLoaded());
checked = true;
#endif
return proc.Call != nullptr;
}
};
template<FModule &Module, typename Proto>
class TReqProc
{
FModule::StaticProc proc;
// I am not a pointer
bool operator==(void*) const;
bool operator!=(void*) const;
public:
TReqProc(const char* function)
{
proc.Name = function;
proc.Optional = false;
Module.RegisterStatic(proc);
}
operator Proto() const
{
#ifndef NDEBUG
assert(Module.IsLoaded());
#endif
return (Proto)proc.Call;
}
explicit operator bool() const { return true; }
};
template<FStaticModule &Module, typename Proto, Proto Sym>
class TStaticProc
{
// I am not a pointer
bool operator==(void*) const;
bool operator!=(void*) const;
public:
TStaticProc(const char* function) {}
operator Proto() const { return Sym; }
explicit operator bool() const { return Sym != nullptr; }
};
void FModule_SetProgDir(const char* progdir);
const std::string& FModule_GetProgDir();

2
source/loader/test.c Normal file
View file

@ -0,0 +1,2 @@
// This file is only here to have one module that includes the header from a pure C source, so that it immediately errors out when something incompatible is found.
#include "zmusic.h"