Squashed 'libraries/ZMusic/' content from commit ac3e232b00
git-subtree-dir: libraries/ZMusic git-subtree-split: ac3e232b001129c740b7b65196ae0e1b13b82513
This commit is contained in:
commit
9f3cb3d92e
852 changed files with 381622 additions and 0 deletions
113
source/loader/i_module.cpp
Normal file
113
source/loader/i_module.cpp
Normal 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
233
source/loader/i_module.h
Normal 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
2
source/loader/test.c
Normal 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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue