Don't truncate checkInputs error string
[supercollider.git] / server / scsynth / SC_Lib_Cintf.cpp
blob6825758dee0e32ad38c57453de41385e5ffec1ab
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "SC_Lib_Cintf.h"
24 #include "SC_CoreAudio.h"
25 #include "SC_UnitDef.h"
26 #include "SC_BufGen.h"
27 #include "SC_World.h"
28 #include "SC_StringParser.h"
29 #include "SC_InterfaceTable.h"
30 #include "SC_DirUtils.h"
31 #include <stdexcept>
32 #ifndef _MSC_VER
33 #include <dirent.h>
34 #endif //_MSC_VER
36 #ifndef _WIN32
37 #include <dlfcn.h>
38 #endif
40 #ifdef _WIN32
41 #include "SC_Win32Utils.h"
42 #else
43 #include <libgen.h>
44 #endif
46 // Plugin directory in resource directory
47 #if defined(_WIN32) && defined(_DEBUG)
48 # define SC_PLUGIN_DIR_NAME "plugins_debug"
49 #else
50 # define SC_PLUGIN_DIR_NAME "plugins"
51 #endif
53 // Extension for binary plugins
54 #ifndef SC_PLUGIN_EXT
55 # define SC_PLUGIN_EXT ".scx"
56 #endif
59 #ifndef _WIN32
60 # include <sys/param.h>
61 #endif
63 #ifdef __APPLE__
64 extern "C" {
65 #include <mach-o/dyld.h>
66 #include <mach-o/getsect.h>
68 char gTempVal;
69 #endif
71 Malloc gMalloc;
72 HashTable<SC_LibCmd, Malloc> *gCmdLib;
73 HashTable<struct UnitDef, Malloc> *gUnitDefLib = 0;
74 HashTable<struct BufGen, Malloc> *gBufGenLib = 0;
75 HashTable<struct PlugInCmd, Malloc> *gPlugInCmds = 0;
76 extern struct InterfaceTable gInterfaceTable;
77 SC_LibCmd* gCmdArray[NUMBER_OF_COMMANDS];
79 void initMiscCommands();
80 static bool PlugIn_LoadDir(const char *dirname, bool reportError);
82 #ifdef __APPLE__
83 void read_section(const struct mach_header *mhp, unsigned long slide, const char *segname, const char *sectname)
85 u_int32_t size;
86 char *sect = getsectdatafromheader(mhp, segname, sectname, &size);
87 if(!sect) return;
89 char *start = sect + slide;
90 char *end = start + size;
92 while(start != end) {
93 gTempVal += *(char *)start;
94 start++;
97 #endif
99 extern void IO_Load(InterfaceTable *table);
100 extern void Osc_Load(InterfaceTable *table);
101 extern void Delay_Load(InterfaceTable *table);
102 extern void BinaryOp_Load(InterfaceTable *table);
103 extern void Filter_Load(InterfaceTable *table);
104 extern void Gendyn_Load(InterfaceTable *table);
105 extern void LF_Load(InterfaceTable *table);
106 extern void Noise_Load(InterfaceTable *table);
107 extern void MulAdd_Load(InterfaceTable *table);
108 extern void Grain_Load(InterfaceTable *table);
109 extern void Pan_Load(InterfaceTable *table);
110 extern void Reverb_Load(InterfaceTable *table);
111 extern void Trigger_Load(InterfaceTable *table);
112 extern void UnaryOp_Load(InterfaceTable *table);
113 extern void DiskIO_Load(InterfaceTable *table);
114 extern void Test_Load(InterfaceTable *table);
115 extern void PhysicalModeling_Load(InterfaceTable *table);
116 extern void Demand_Load(InterfaceTable *table);
117 extern void DynNoise_Load(InterfaceTable *table);
118 extern void FFT_UGens_Load(InterfaceTable *table);
119 extern void iPhone_Load(InterfaceTable *table);
121 void initialize_library(const char *uGensPluginPath)
123 gCmdLib = new HashTable<SC_LibCmd, Malloc>(&gMalloc, 64, true);
124 gUnitDefLib = new HashTable<UnitDef, Malloc>(&gMalloc, 512, true);
125 gBufGenLib = new HashTable<BufGen, Malloc>(&gMalloc, 512, true);
126 gPlugInCmds = new HashTable<PlugInCmd, Malloc>(&gMalloc, 64, true);
128 initMiscCommands();
130 #ifdef STATIC_PLUGINS
131 IO_Load(&gInterfaceTable);
132 Osc_Load(&gInterfaceTable);
133 Delay_Load(&gInterfaceTable);
134 BinaryOp_Load(&gInterfaceTable);
135 Filter_Load(&gInterfaceTable);
136 Gendyn_Load(&gInterfaceTable);
137 LF_Load(&gInterfaceTable);
138 Noise_Load(&gInterfaceTable);
139 MulAdd_Load(&gInterfaceTable);
140 Grain_Load(&gInterfaceTable);
141 Pan_Load(&gInterfaceTable);
142 Reverb_Load(&gInterfaceTable);
143 Trigger_Load(&gInterfaceTable);
144 UnaryOp_Load(&gInterfaceTable);
145 DiskIO_Load(&gInterfaceTable);
146 PhysicalModeling_Load(&gInterfaceTable);
147 Test_Load(&gInterfaceTable);
148 Demand_Load(&gInterfaceTable);
149 DynNoise_Load(&gInterfaceTable);
150 #if defined(SC_IPHONE) && !TARGET_IPHONE_SIMULATOR
151 iPhone_Load(&gInterfaceTable);
152 #endif
153 FFT_UGens_Load(&gInterfaceTable);
154 return;
155 #endif
157 // If uGensPluginPath is supplied, it is exclusive.
158 bool loadUGensExtDirs = true;
159 if(uGensPluginPath){
160 loadUGensExtDirs = false;
161 SC_StringParser sp(uGensPluginPath, SC_STRPARSE_PATHDELIMITER);
162 while (!sp.AtEnd()) {
163 PlugIn_LoadDir(const_cast<char *>(sp.NextToken()), true);
167 if(loadUGensExtDirs) {
168 #ifdef SC_PLUGIN_DIR
169 // load globally installed plugins
170 if (sc_DirectoryExists(SC_PLUGIN_DIR)) {
171 PlugIn_LoadDir(SC_PLUGIN_DIR, true);
173 #endif
174 // load default plugin directory
175 char pluginDir[MAXPATHLEN];
176 sc_GetResourceDirectory(pluginDir, MAXPATHLEN);
177 sc_AppendToPath(pluginDir, MAXPATHLEN, SC_PLUGIN_DIR_NAME);
179 if (sc_DirectoryExists(pluginDir)) {
180 PlugIn_LoadDir(pluginDir, true);
184 // get extension directories
185 char extensionDir[MAXPATHLEN];
186 if (!sc_IsStandAlone() && loadUGensExtDirs) {
187 // load system extension plugins
188 sc_GetSystemExtensionDirectory(extensionDir, MAXPATHLEN);
189 PlugIn_LoadDir(extensionDir, false);
191 // load user extension plugins
192 sc_GetUserExtensionDirectory(extensionDir, MAXPATHLEN);
193 PlugIn_LoadDir(extensionDir, false);
195 // load user plugin directories
196 SC_StringParser sp(getenv("SC_PLUGIN_PATH"), SC_STRPARSE_PATHDELIMITER);
197 while (!sp.AtEnd()) {
198 PlugIn_LoadDir(const_cast<char *>(sp.NextToken()), true);
201 #ifdef __APPLE__
202 /* on darwin plugins are lazily loaded (dlopen uses mmap internally), which can produce audible
203 glitches when UGens have to be paged-in. to work around this we preload all the plugins by
204 iterating through their memory space. */
206 #ifndef __x86_64__
207 /* seems to cause a stack corruption on llvm-gcc-4.2, sdk 10.5 on 10.6 */
209 unsigned long images = _dyld_image_count();
210 for(unsigned long i = 0; i < images; i++) {
211 const mach_header *hdr = _dyld_get_image_header(i);
212 unsigned long slide = _dyld_get_image_vmaddr_slide(i);
213 const char *name = _dyld_get_image_name(i);
214 uint32_t size;
215 char *sect;
217 if(!strcmp(name + (strlen(name) - 4), ".scx")) {
218 read_section(hdr, slide, "__TEXT", "__text");
219 read_section(hdr, slide, "__TEXT", "__const");
220 read_section(hdr, slide, "__TEXT", "__cstring");
221 read_section(hdr, slide, "__TEXT", "__picsymbol_stub");
222 read_section(hdr, slide, "__TEXT", "__symbol_stub");
223 read_section(hdr, slide, "__TEXT", "__const");
224 read_section(hdr, slide, "__TEXT", "__literal4");
225 read_section(hdr, slide, "__TEXT", "__literal8");
227 read_section(hdr, slide, "__DATA", "__data");
228 read_section(hdr, slide, "__DATA", "__la_symbol_ptr");
229 read_section(hdr, slide, "__DATA", "__nl_symbol_ptr");
230 read_section(hdr, slide, "__DATA", "__dyld");
231 read_section(hdr, slide, "__DATA", "__const");
232 read_section(hdr, slide, "__DATA", "__mod_init_func");
233 read_section(hdr, slide, "__DATA", "__bss");
234 read_section(hdr, slide, "__DATA", "__common");
236 read_section(hdr, slide, "__IMPORT", "__jump_table");
237 read_section(hdr, slide, "__IMPORT", "__pointers");
240 #endif
242 #endif
245 typedef int (*InfoFunction)();
247 bool checkAPIVersion(void * f, const char * filename)
249 if (f) {
250 InfoFunction fn = (InfoFunction)f;
251 if ((*fn)() == sc_api_version)
252 return true;
254 scprintf("*** ERROR: API Version Mismatch: %s\n", filename);
255 return false;
258 static bool PlugIn_Load(const char *filename)
260 #ifdef _WIN32
262 HINSTANCE hinstance = LoadLibrary( filename );
263 if (!hinstance) {
264 char *s;
265 DWORD lastErr = GetLastError();
266 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
267 0, lastErr , 0, (char*)&s, 1, 0 );
268 scprintf("*** ERROR: LoadLibrary '%s' err '%s'\n", filename, s);
269 LocalFree( s );
270 return false;
273 void *apiVersionPtr = (void *)GetProcAddress( hinstance, "api_version" );
274 if (!checkAPIVersion(apiVersionPtr, filename)) {
275 FreeLibrary(hinstance);
276 return false;
279 void *ptr = (void *)GetProcAddress( hinstance, "load" );
280 if (!ptr) {
281 char *s;
282 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
283 0, GetLastError(), 0, (char*)&s, 1, 0 );
284 scprintf("*** ERROR: GetProcAddress err '%s'\n", s);
285 LocalFree( s );
287 FreeLibrary(hinstance);
288 return false;
291 LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr;
292 (*loadFunc)(&gInterfaceTable);
294 // FIXME: at the moment we never call FreeLibrary() on a loaded plugin
296 return true;
298 #else
300 void* handle = dlopen(filename, RTLD_NOW);
302 if (!handle) {
303 scprintf("*** ERROR: dlopen '%s' err '%s'\n", filename, dlerror());
304 dlclose(handle);
305 return false;
308 void *apiVersionPtr = (void *)dlsym( handle, "api_version" );
309 if (!checkAPIVersion(apiVersionPtr, filename)) {
310 dlclose(handle);
311 return false;
314 void *ptr = dlsym(handle, "load");
315 if (!ptr) {
316 scprintf("*** ERROR: dlsym load err '%s'\n", dlerror());
317 dlclose(handle);
318 return false;
321 LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr;
322 (*loadFunc)(&gInterfaceTable);
324 return true;
326 #endif
329 static bool PlugIn_LoadDir(const char *dirname, bool reportError)
331 bool success = true;
333 SC_DirHandle *dir = sc_OpenDir(dirname);
334 if (!dir) {
335 if (reportError) {
336 scprintf("*** ERROR: open directory failed '%s'\n", dirname); fflush(stdout);
338 return false;
341 int firstCharOffset = strlen(dirname)+1;
343 for (;;) {
344 char diritem[MAXPATHLEN];
345 bool skipItem = true;
346 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
347 if (!validItem) break;
348 if (skipItem || (*(diritem+firstCharOffset) == '.')) continue; // skip files+folders whose first char is a dot
350 if (sc_DirectoryExists(diritem)) {
351 success = PlugIn_LoadDir(diritem, reportError);
352 } else {
353 int dnamelen = strlen(diritem);
354 int extlen = strlen(SC_PLUGIN_EXT);
355 char *extptr = diritem+dnamelen-extlen;
356 if (strncmp(extptr, SC_PLUGIN_EXT, extlen) == 0) {
357 success = PlugIn_Load(diritem);
361 if (!success) continue;
364 sc_CloseDir(dir);
365 return success;