1 
2 module ws.sys.library;
3 
4 import
5 	std.string,
6 	std.conv,
7 	std.traits,
8 	ws.log;
9 
10 version(Windows) import derelict.util.wintypes;
11 version(Posix) import core.sys.posix.dlfcn;
12 
13 
14 string embedFunc(string n, string t)(){
15 	return t ~ ' ' ~ n ~ ";\n";
16 }
17 
18 string embedFunc(string n, T)(){
19 	return fullyQualifiedName!T ~ ' ' ~ n ~ ";\n";
20 }
21 
22 string getFunc()(){
23 	return "";
24 }
25 
26 string getFunc(string n, T, More...)(){
27 	return embedFunc!(n, T)() ~ getFunc!More();
28 	//return t ~ ' ' ~ n ~ ";\n" ~ getFunc!More();
29 }
30 
31 string getFunc(string n, string t, More...)(){
32 	return embedFunc!(n, t)() ~ getFunc!More();
33 }
34 
35 string loadFunc(string f)(){
36 	return f ~ " = cast(typeof(" ~ f ~ "))l.get(\"" ~ f ~ "\");";
37 }
38 
39 mixin template library(string refname, string name, Args...){
40 
41 	mixin("
42 		struct " ~ refname ~ " {
43 			static Library lib;
44 			static this(){
45 				try
46 					lib = load();
47 				catch(Exception e){
48 					ws.log.Log.error(e.toString());
49 					throw e;
50 				}
51 			}
52 			static Library load(){
53 				Library l = new Library(\"" ~ name ~ "\");
54 				loadFuncs!Args(l);
55 				return l;
56 			}
57 		}
58 	");
59 	
60 	void loadFuncs(string f, More...)(Library l){
61 		mixin(loadFunc!(f)());
62 		static if(More.length >= 2)
63 			loadFuncs!(More[1..$])(l);
64 	}
65 
66 	// put last due to possible override
67 	mixin(getFunc!Args());
68 
69 }
70 
71 class Library {
72 
73 	void* get(string s){
74 		void* p = null;
75 		version(Windows)
76 			p = GetProcAddress(lib, s.toStringz());
77 		version(Posix)
78 			p = dlsym(lib, s.toStringz);
79 		if(!p)
80 			throw new Exception("Failed to load symbol \"" ~ s ~ "\": " ~ getError());
81 		return p;
82 	}
83 	
84 
85 	T call(T, string name, Args...)(Args args){
86 		alias T function(Args) FT;
87 		static FT func;
88 		if(!func)
89 			func = cast(FT)get(name);
90 		return func(args);
91 	}
92 	
93 
94 	this(string s, string vers = ""){
95 		version(Windows)
96 			lib = LoadLibraryA(s.toStringz());
97 		version(Posix)
98 			lib = dlopen(("lib" ~ s ~ ".so" ~ vers).toStringz(), RTLD_NOW);
99 		if(!lib)
100 			throw new Exception("Failed to load library \"" ~ s ~ "\": " ~ getError());
101 	}
102 
103 
104 	~this(){
105 		version(Windows)
106 			FreeLibrary(lib);
107 		version(Posix)
108 			dlclose(lib);
109 	}
110 
111 	version(Windows) private HMODULE lib;
112 	version(Posix) private void* lib;
113 
114 	private string getError(){
115 		version(Windows){
116 			DWORD errcode = GetLastError();
117 			LPCSTR msgBuf;
118 			DWORD i = FormatMessageA(
119 				FORMAT_MESSAGE_ALLOCATE_BUFFER |
120 				FORMAT_MESSAGE_FROM_SYSTEM |
121 				FORMAT_MESSAGE_IGNORE_INSERTS,
122 				null,
123 				errcode,
124 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
125 				cast(LPCSTR)&msgBuf,
126 				0,
127 				null);
128 			string text = to!string(msgBuf);
129 			LocalFree(cast(HLOCAL)msgBuf);
130 			if(i >= 2)
131 				i -= 2;
132 			return text[0 .. i];
133 		}version(Posix){
134 			auto err = dlerror();
135 			if(!err)
136 				return "Unknown Error";
137 			return to!string(err);		
138 		}
139 	}
140 }
141 
142 
143 class AutoLibrary {
144 
145 	protected {
146 		Library lib;
147 		string prefix;
148 
149 	}
150 
151 	this(string name, string prefix){
152 		this.prefix = prefix;
153 		lib = new Library(name);
154 	}
155 
156 
157 
158 }
159