1 /*
2 csmodule.c:
3
4 Copyright (C) 2005 Istvan Varga
5 based on dl_opcodes.c, Copyright (C) 2002 John ffitch
6
7 This file is part of Csound.
8
9 The Csound Library is free software; you can redistribute it
10 and/or modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 Csound is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with Csound; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 02110-1301 USA
23 */
24
25 /******************************************************************************
26 * NEW PLUGIN INTERFACE *
27 * ==================== *
28 * *
29 * Plugin libraries are loaded from the directory defined by the environment *
30 * variable OPCODE6DIR (or the current directory if OPCODE6DIR is unset) by *
31 * csoundPreCompile() while initialising a Csound instance, and are unloaded *
32 * at the end of performance by csoundReset(). *
33 * A library may export any of the following five interface functions, *
34 * however, the presence of csoundModuleCreate() is required for identifying *
35 * the file as a Csound plugin module. *
36 * *
37 * int csoundModuleCreate(CSOUND *csound) (required) *
38 * -------------------------------------- *
39 * *
40 * Pre-initialisation function, called by csoundPreCompile(). *
41 * *
42 * int csoundModuleInit(CSOUND *csound) (optional) *
43 * ------------------------------------ *
44 * *
45 * Called by Csound instances before orchestra translation. One possible use *
46 * of csoundModuleInit() is adding new opcodes with csoundAppendOpcode(). *
47 * *
48 * int csoundModuleDestroy(CSOUND *csound) (optional) *
49 * --------------------------------------- *
50 * *
51 * Destructor function for Csound instance 'csound', called at the end of *
52 * performance, after closing audio output. *
53 * *
54 * const char *csoundModuleErrorCodeToString(int errcode) (optional) *
55 * ------------------------------------------------------ *
56 * *
57 * Converts error codes returned by any of the initialisation or destructor *
58 * functions to a string message. *
59 * *
60 * int csoundModuleInfo(void) (optional) *
61 * -------------------------- *
62 * *
63 * Returns information that can be used to determine if the plugin was built *
64 * for a compatible version of libcsound. The return value may be the sum of *
65 * any of the following two values: *
66 * *
67 * ((CS_APIVERSION << 16) + (CS_APISUBVER << 8)) API version *
68 * (int) sizeof(MYFLT) MYFLT type *
69 * *
70 ******************************************************************************/
71
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <errno.h>
76 #include <setjmp.h>
77
78 #include "csoundCore.h"
79 #include "csmodule.h"
80
81 #if defined(__MACH__)
82 #include <TargetConditionals.h>
83 #if (TARGET_OS_IPHONE == 0) && (TARGET_IPHONE_SIMULATOR == 0)
84 #if defined(MAC_OS_X_VERSION_10_6) && \
85 (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_6)
86 #define NEW_MACH_CODE
87 #endif
88 #endif
89 #endif
90
91 #if !(defined (NACL))
92 #if defined(LINUX) || defined(NEW_MACH_CODE) || defined(__HAIKU__)
93 #include <dlfcn.h>
94 #elif defined(WIN32)
95 #include <windows.h>
96 #endif
97 #endif
98
99
100 #if defined(HAVE_DIRENT_H)
101 # include <dirent.h>
102 # if 0 && defined(__MACH__)
103 typedef void* DIR;
104 DIR opendir(const char *);
105 struct dirent *readdir(DIR*);
106 int closedir(DIR*);
107 # endif
108 #endif
109
110 #if defined(WIN32) && !defined(__CYGWIN__)
111 # include <io.h>
112 # include <direct.h>
113 #endif
114
115 extern int allocgen(CSOUND *, char *, int (*)(FGDATA *, FUNC *));
116
117 #if defined(INIT_STATIC_MODULES)
118 extern int init_static_modules(CSOUND *);
119 #endif
120
121 /* module interface function names */
122
123 static const char *opcode_init_Name = "csound_opcode_init";
124 static const char *fgen_init_Name = "csound_fgen_init";
125
126 static const char *PreInitFunc_Name = "csoundModuleCreate";
127 static const char *InitFunc_Name = "csoundModuleInit";
128 static const char *DestFunc_Name = "csoundModuleDestroy";
129 static const char *ErrCodeToStr_Name = "csoundModuleErrorCodeToString";
130
131 static const char *InfoFunc_Name = "csoundModuleInfo";
132
133 /* environment variable storing path to plugin libraries */
134 static const char *plugindir_envvar = "OPCODE6DIR";
135 static const char *plugindir64_envvar = "OPCODE6DIR64";
136
137 /* default directory to load plugins from if environment variable is not set */
138 #if !(defined (NACL))
139 #ifdef __HAIKU__
140 # ifndef USE_DOUBLE
141 static char haikudirs[] = "/boot/system/lib/csound6/plugins:"
142 "/boot/home/config/lib/csound6/plugins:"
143 "/boot/system/non-packaged/lib/csound6/plugins:"
144 "/boot/home/config/non-packaged/lib/csound6/plugins";
145 # else
146 static char haikudirs[] = "/boot/system/lib/csound6/plugins64:"
147 "/boot/home/config/lib/csound6/plugins64:"
148 "/boot/system/non-packaged/lib/csound6/plugins64:"
149 "/boot/home/config/non-packaged/lib/csound6/plugins64";
150 # endif
151 # define CS_DEFAULT_PLUGINDIR haikudirs
152 #elif !(defined(_CSOUND_RELEASE_) && (defined(LINUX) || defined(__MACH__)))
153 # define ENABLE_OPCODEDIR_WARNINGS 1
154 # ifdef CS_DEFAULT_PLUGINDIR
155 # undef CS_DEFAULT_PLUGINDIR
156 # endif
157 # define CS_DEFAULT_PLUGINDIR "."
158 #else
159 # define ENABLE_OPCODEDIR_WARNINGS 0
160 # ifndef CS_DEFAULT_PLUGINDIR
161 # ifndef USE_DOUBLE
162 # define CS_DEFAULT_PLUGINDIR "/usr/local/lib/csound/plugins"
163 # else
164 # define CS_DEFAULT_PLUGINDIR "/usr/local/lib/csound/plugins64"
165 # endif
166 # endif
167 #endif
168 #endif
169
170 #if (TARGET_OS_IPHONE != 0) && (TARGET_IPHONE_SIMULATOR != 0)
171 # define ENABLE_OPCODEDIR_WARNINGS 0
172 #endif
173
174 typedef struct opcodeLibFunc_s {
175 long (*opcode_init)(CSOUND *, OENTRY **); /* list of opcode entries */
176 NGFENS *(*fgen_init)(CSOUND *); /* list of named GEN routines */
177 void (*dummy)(void); /* unused */
178 } opcodeLibFunc_t;
179
180 typedef struct pluginLibFunc_s {
181 int (*InitFunc)(CSOUND *); /* initialisation routine */
182 int (*DestFunc)(CSOUND *); /* destructor routine */
183 const char *(*ErrCodeToStr)(int); /* convert error code to string */
184 } pluginLibFunc_t;
185
186 typedef struct csoundModule_s {
187 struct csoundModule_s *nxt; /* pointer to next link in chain */
188 void *h; /* library handle */
189 int (*PreInitFunc)(CSOUND *); /* pre-initialisation routine */
190 /* (always NULL if opcode lib) */
191 union {
192 pluginLibFunc_t p; /* generic plugin interface */
193 opcodeLibFunc_t o; /* opcode library interface */
194 } fn;
195 char name[1]; /* name of the module */
196 } csoundModule_t;
197
print_module_error(CSOUND * csound,const char * fmt,const char * fname,const csoundModule_t * m,int err)198 static CS_NOINLINE void print_module_error(CSOUND *csound,
199 const char *fmt, const char *fname,
200 const csoundModule_t *m, int err)
201 {
202 csoundMessageS(csound, CSOUNDMSG_ERROR, Str(fmt), fname);
203 if (m != NULL && m->fn.p.ErrCodeToStr != NULL)
204 csoundMessageS(csound, CSOUNDMSG_ERROR,
205 ": %s\n", Str(m->fn.p.ErrCodeToStr(err)));
206 else
207 csoundMessageS(csound, CSOUNDMSG_ERROR, "\n");
208 }
209
check_plugin_compatibility(CSOUND * csound,const char * fname,int n)210 static int check_plugin_compatibility(CSOUND *csound, const char *fname, int n)
211 {
212 int myfltSize, minorVersion, majorVersion;
213
214 myfltSize = n & 0xFF;
215 if (UNLIKELY(myfltSize != 0 && myfltSize != (int) sizeof(MYFLT))) {
216 csoundWarning(csound, Str("not loading '%s' (uses incompatible "
217 "floating point type)"), fname);
218 return -1;
219 }
220 if (UNLIKELY(n & (~0xFF))) {
221 minorVersion = (n & 0xFF00) >> 8;
222 majorVersion = (n & (~0xFFFF)) >> 16;
223 if (majorVersion != (int) CS_APIVERSION ||
224 (minorVersion > (int) CS_APISUBVER)) { /* NOTE **** REFACTOR *** */
225 csoundWarning(csound, Str("not loading '%s' (incompatible "
226 "with this version of Csound (%d.%d/%d.%d)"),
227 fname, majorVersion,minorVersion,
228 CS_APIVERSION,CS_APISUBVER);
229 return -1;
230 }
231 }
232 return 0;
233 }
234
235 /* load a single plugin library, and run csoundModuleCreate() if present */
236 /* returns zero on success */
237
csoundLoadExternal(CSOUND * csound,const char * libraryPath)238 static CS_NOINLINE int csoundLoadExternal(CSOUND *csound,
239 const char *libraryPath)
240 {
241 csoundModule_t m;
242 volatile jmp_buf tmpExitJmp;
243 csoundModule_t *mp;
244 char *fname;
245 void *h, *p;
246 int (*infoFunc)(void);
247 int err;
248
249 /* check for a valid name */
250 if (UNLIKELY(libraryPath == NULL || libraryPath[0] == '\0'))
251 return CSOUND_ERROR;
252 /* remove leading directory components from name */
253 fname = (char*) libraryPath + (int) strlen(libraryPath);
254 for ( ; fname[0] != DIRSEP && fname != (char*) libraryPath; fname--)
255 ;
256 if (fname[0] == DIRSEP)
257 fname++;
258 if (UNLIKELY(fname[0] == '\0'))
259 return CSOUND_ERROR;
260 /* load library */
261 /* #if defined(LINUX) */
262 //printf("About to open library '%s'\n", libraryPath);
263 /* #endif */
264 err = csoundOpenLibrary(&h, libraryPath);
265 if (UNLIKELY(err)) {
266 char ERRSTR[256];
267 #if !(defined(NACL)) && (defined(LINUX) || defined(__HAIKU__))
268 snprintf(ERRSTR, 256, Str("could not open library '%s' (%s)"),
269 libraryPath, dlerror());
270 #else
271 snprintf(ERRSTR, 256, Str("could not open library '%s' (%d)"),
272 libraryPath, err);
273 #endif
274 if (csound->delayederrormessages == NULL) {
275 csound->delayederrormessages = csound->Malloc(csound, strlen(ERRSTR)+1);
276 strcpy(csound->delayederrormessages, ERRSTR);
277 }
278 else {
279 char *new =
280 csound->ReAlloc(csound, csound->delayederrormessages,
281 strlen(csound->delayederrormessages)+strlen(ERRSTR)+11);
282 if (UNLIKELY(new==NULL)) {
283 csound->Free(csound, csound->delayederrormessages);
284 return CSOUND_ERROR;
285 }
286 csound->delayederrormessages = new;
287 strcat(csound->delayederrormessages, "\nWARNING: ");
288 strcat(csound->delayederrormessages, ERRSTR);
289 }
290 return CSOUND_ERROR;
291 }
292 /* check if the library is compatible with this version of Csound */
293 infoFunc = (int (*)(void)) csoundGetLibrarySymbol(h, InfoFunc_Name);
294 if (infoFunc != NULL) {
295 if (UNLIKELY(check_plugin_compatibility(csound, fname, infoFunc()) != 0)) {
296 csoundCloseLibrary(h);
297 return CSOUND_ERROR;
298 }
299 }
300 /* was this plugin already loaded ? */
301 for (mp = (csoundModule_t*) csound->csmodule_db; mp != NULL; mp = mp->nxt) {
302 if (UNLIKELY(mp->h == h)) {
303 csoundCloseLibrary(h);
304 return CSOUND_SUCCESS;
305 }
306 }
307 /* find out if it is a Csound plugin */
308 memset(&m, 0, sizeof(csoundModule_t));
309 m.h = h;
310 m.PreInitFunc =
311 (int (*)(CSOUND *)) csoundGetLibrarySymbol(h, PreInitFunc_Name);
312 if (m.PreInitFunc != NULL) {
313 /* generic plugin library */
314 m.fn.p.InitFunc =
315 (int (*)(CSOUND *)) csoundGetLibrarySymbol(h, InitFunc_Name);
316 m.fn.p.DestFunc =
317 (int (*)(CSOUND *)) csoundGetLibrarySymbol(h, DestFunc_Name);
318 m.fn.p.ErrCodeToStr =
319 (const char *(*)(int)) csoundGetLibrarySymbol(h, ErrCodeToStr_Name);
320 }
321 else {
322 /* opcode library */
323 m.fn.o.opcode_init =
324 (long (*)(CSOUND *, OENTRY **))
325 csoundGetLibrarySymbol(h, opcode_init_Name);
326 m.fn.o.fgen_init =
327 (NGFENS *(*)(CSOUND *)) csoundGetLibrarySymbol(h, fgen_init_Name);
328 if (UNLIKELY(m.fn.o.opcode_init == NULL && m.fn.o.fgen_init == NULL)) {
329 /* must have csound_opcode_init() or csound_fgen_init() */
330 csoundCloseLibrary(h);
331 if (UNLIKELY(csound->oparms->msglevel & 0x400))
332 csound->Warning(csound, Str("'%s' is not a Csound plugin library"),
333 libraryPath);
334 return CSOUND_ERROR;
335 }
336 }
337 /* set up module info structure */
338 /* (note: space for NUL character is already included in size of struct) */
339 p = (void*) csound->Malloc(csound,
340 sizeof(csoundModule_t) + (size_t) strlen(fname));
341 if (UNLIKELY(p == NULL)) {
342 csoundCloseLibrary(h);
343 csound->ErrorMsg(csound,
344 Str("csoundLoadExternal(): memory allocation failure"));
345 return CSOUND_MEMORY;
346 }
347 mp = (csoundModule_t*) p;
348 memcpy(mp, &m, sizeof(csoundModule_t));
349 strcpy(&(mp->name[0]), fname);
350 /* link into database */
351 mp->nxt = (csoundModule_t*) csound->csmodule_db;
352 csound->csmodule_db = (void*) mp;
353 /* call csoundModuleCreate() if available */
354 if (m.PreInitFunc != NULL) {
355 memcpy((void*) &tmpExitJmp, (void*) &csound->exitjmp, sizeof(jmp_buf));
356 if ((err = setjmp(csound->exitjmp)) != 0) {
357 memcpy((void*) &csound->exitjmp, (void*) &tmpExitJmp, sizeof(jmp_buf));
358 print_module_error(csound, Str("Error in pre-initialisation function "
359 "of module '%s'"), fname, NULL, 0);
360 return (err == (CSOUND_EXITJMP_SUCCESS + CSOUND_MEMORY) ?
361 CSOUND_MEMORY : CSOUND_INITIALIZATION);
362 }
363 err = m.PreInitFunc(csound);
364 memcpy((void*) &csound->exitjmp, (void*) &tmpExitJmp, sizeof(jmp_buf));
365 if (UNLIKELY(err != 0)) {
366 print_module_error(csound, Str("Error in pre-initialisation function "
367 "of module '%s'"), fname, &m, err);
368 return CSOUND_INITIALIZATION;
369 }
370 }
371 /* plugin was loaded successfully */
372 return CSOUND_SUCCESS;
373 }
374
csoundCheckOpcodeDeny(CSOUND * csound,const char * fname)375 static int csoundCheckOpcodeDeny(CSOUND * csound, const char *fname)
376 {
377 /* Check to see if the fname is on the do-not-load list */
378 char buff[256];
379 char *th;
380 char *p, *deny;
381 char *list = getenv("CS_OMIT_LIBS");
382 /* printf("DEBUG %s(%d): check fname=%s\n", __FILE__, __LINE__, fname); */
383 /* printf("DEBUG %s(%d): list %s\n", __FILE__, __LINE__, list); */
384 if (list==NULL) return 0;
385 strNcpy(buff, fname, 255); //buff[255]='\0';
386 strrchr(buff, '.')[0] = '\0'; /* Remove .so etc */
387 p = cs_strdup(csound, list);
388 deny = cs_strtok_r(p, ",", &th);
389 /* printf("DEBUG %s(%d): check buff=%s\n", __FILE__, __LINE__, deny); */
390 while (deny) {
391 /* printf("DEBUG %s(%d): deny=%s\n", __FILE__, __LINE__, deny); */
392 if (strcmp(deny, buff)==0) {
393 csound->Free(csound, p);
394 /* printf("DEBUG %s(%d): found\n", __FILE__, __LINE__); */
395 return 1;
396 }
397 deny = cs_strtok_r(NULL, ",", &th);
398 }
399 csound->Free(csound, p);
400 /* printf("DEBUG %s(%d): not found\n", __FILE__, __LINE__); */
401 return 0;
402 }
403
404 /**
405 * Load plugin libraries for Csound instance 'csound', and call
406 * pre-initialisation functions.
407 * Return value is CSOUND_SUCCESS if there was no error, CSOUND_ERROR if
408 * some modules could not be loaded or initialised, and CSOUND_MEMORY
409 * if a memory allocation failure has occured.
410 */
csoundLoadModules(CSOUND * csound)411 int csoundLoadModules(CSOUND *csound)
412 {
413 #if (defined(HAVE_DIRENT_H) && (TARGET_OS_IPHONE == 0))
414 DIR *dir;
415 struct dirent *f;
416 const char *dname, *fname;
417 char buf[1024];
418 int i, n, len, err = CSOUND_SUCCESS;
419 char *dname1, *end;
420 int read_directory = 1;
421 char sep =
422 #ifdef WIN32
423 ';';
424 #else
425 ':';
426 #endif
427 #ifdef __HAIKU__
428 int dfltdir = 0;
429 #endif
430
431 if (UNLIKELY(csound->csmodule_db != NULL))
432 return CSOUND_ERROR;
433
434 /* open plugin directory */
435 dname = csoundGetEnv(csound, (sizeof(MYFLT) == sizeof(float) ?
436 plugindir_envvar : plugindir64_envvar));
437 if (dname == NULL) {
438 #if ENABLE_OPCODEDIR_WARNINGS
439 csound->opcodedirWasOK = 0;
440 # ifdef USE_DOUBLE
441 dname = csoundGetEnv(csound, plugindir_envvar);
442 if (dname == NULL)
443 # endif
444 #endif
445 #ifdef CS_DEFAULT_PLUGINDIR
446 dname = CS_DEFAULT_PLUGINDIR;
447 #ifdef __HAIKU__
448 dfltdir = 1;
449 #endif
450 #else
451 dname = "";
452 #endif
453 }
454 /* opcodedir GLOBAL override **experimental** */
455 if (csound->opcodedir != NULL) {
456 dname = csound->opcodedir;
457 csound->Message(csound, "OPCODEDIR overriden to %s \n", dname);
458 }
459
460 /* We now loop through the directory list */
461 while(read_directory) {
462 /* find separator */
463 if((end = strchr(dname, sep)) != NULL) {
464 *end = '\0';
465 /* copy directory name */
466 dname1 = cs_strdup(csound, (char *) dname);
467 *end = sep; /* restore for re-execution */
468 /* move to next directory name */
469 dname = end + 1;
470 } else {
471 /* copy last directory name) */
472 dname1 = cs_strdup(csound, (char *) dname);
473 read_directory = 0;
474 }
475
476 /* protect for the case where there is an
477 extra separator at the end */
478 if(*dname1 == '\0') {
479 csound->Free(csound, dname1);
480 break;
481 }
482
483 dir = opendir(dname1);
484 if (UNLIKELY(dir == (DIR*) NULL)) {
485 #if defined(__HAIKU__)
486 if(!dfltdir)
487 #endif
488 csound->Warning(csound, Str("Error opening plugin directory '%s': %s"),
489 dname1, strerror(errno));
490 csound->Free(csound, dname1);
491 continue;
492 }
493
494 if(UNLIKELY(csound->oparms->odebug))
495 csound->Message(csound, "Opening plugin directory: %s\n", dname1);
496 /* load database for deferred plugin loading */
497 /* n = csoundLoadOpcodeDB(csound, dname); */
498 /* if (n != 0) */
499 /* return n; */
500 /* scan all files in directory */
501 while ((f = readdir(dir)) != NULL) {
502 fname = &(f->d_name[0]);
503 if (UNLIKELY(fname[0]=='_')) continue;
504 n = len = (int) strlen(fname);
505 if (UNLIKELY(fname[0]=='_')) continue;
506 #if defined(WIN32)
507 strcpy(buf, "dll");
508 n -= 4;
509 #elif defined(__MACH__)
510 strcpy(buf, "dylib");
511 n -= 6;
512 #else
513 strcpy(buf, "so");
514 n -= 3;
515 #endif
516 if (n <= 0 || fname[n] != '.')
517 continue;
518 i = 0;
519 do {
520 if (UNLIKELY((fname[++n] | (char) 0x20) != buf[i]))
521 break;
522 } while (buf[++i] != '\0');
523 if (buf[i] != '\0')
524 continue;
525 /* found a dynamic library, attempt to open it */
526 if (UNLIKELY(((int) strlen(dname) + len + 2) > 1024)) {
527 csound->Warning(csound, Str("path name too long, skipping '%s'"),
528 fname);
529 continue;
530 }
531 /* printf("DEBUG %s(%d): possibly deny %s\n", __FILE__, __LINE__,fname); */
532 if (UNLIKELY(csoundCheckOpcodeDeny(csound, fname))) {
533 csoundWarning(csound, Str("Library %s omitted\n"), fname);
534 continue;
535 }
536 snprintf(buf, 1024, "%s%c%s", dname1, DIRSEP, fname);
537 if (UNLIKELY(csound->oparms->odebug)) {
538 csoundMessage(csound, Str("Loading '%s'\n"), buf);
539 }
540 n = csoundLoadExternal(csound, buf);
541 if (UNLIKELY(UNLIKELY(n == CSOUND_ERROR)))
542 continue; /* ignore non-plugin files */
543 if (UNLIKELY(n < err))
544 err = n; /* record serious errors */
545 }
546 closedir(dir);
547 csound->Free(csound, dname1);
548 }
549 return (err == CSOUND_INITIALIZATION ? CSOUND_ERROR : err);
550 #else
551 return CSOUND_SUCCESS;
552 #endif /* HAVE_DIRENT_H */
553 }
554
555
cmp_func(const void * p1,const void * p2)556 static int cmp_func(const void *p1, const void *p2)
557 {
558 return (strcmp(*((const char**) p1), *((const char**) p2)));
559 }
560
csoundLoadExternals(CSOUND * csound)561 int csoundLoadExternals(CSOUND *csound)
562 {
563 char *s, **lst;
564 int i, cnt, err;
565
566 s = csound->dl_opcodes_oplibs;
567 if (UNLIKELY(s == NULL || s[0] == '\0'))
568 return 0;
569 /* IV - Feb 19 2005 */
570 csound->dl_opcodes_oplibs = NULL;
571 csoundMessage(csound, Str("Loading command-line libraries:\n"));
572 cnt = 1;
573 i = 0;
574 do {
575 if (s[i] == ',')
576 cnt++;
577 } while (s[++i] != '\0');
578 lst = (char**) csound->Malloc(csound, sizeof(char*) * cnt);
579 i = cnt = 0;
580 lst[cnt++] = s;
581 do {
582 if (s[i] == ',') {
583 lst[cnt++] = &(s[i + 1]);
584 s[i] = '\0';
585 }
586 } while (s[++i] != '\0');
587 qsort((void*) lst, (size_t) cnt, sizeof(char*), cmp_func);
588 i = 0;
589 do {
590 char *fname = lst[i];
591 if (fname[0] != '\0' && !(i && strcmp(fname, lst[i - 1]) == 0)) {
592 err = csoundLoadExternal(csound, fname);
593 if (UNLIKELY(err == CSOUND_INITIALIZATION || err == CSOUND_MEMORY))
594 csoundDie(csound, Str(" *** error loading '%s'"), fname);
595 else if (!err)
596 csoundMessage(csound, " %s\n", fname);
597 }
598 } while (++i < cnt);
599 /* file list is no longer needed */
600 csound->Free(csound, lst);
601 csound->Free(csound, s);
602 return 0;
603 }
604
605 /**
606 * Initialise a single module.
607 * Return value is CSOUND_SUCCESS if there was no error.
608 */
csoundInitModule(CSOUND * csound,csoundModule_t * m)609 static CS_NOINLINE int csoundInitModule(CSOUND *csound, csoundModule_t *m)
610 {
611 int i;
612
613 if (m->PreInitFunc != NULL) {
614 if (m->fn.p.InitFunc != NULL) {
615 i = m->fn.p.InitFunc(csound);
616 if (UNLIKELY(i != 0)) {
617 print_module_error(csound, Str("Error starting module '%s'"),
618 &(m->name[0]), m, i);
619 return CSOUND_ERROR;
620 }
621 }
622 }
623 else {
624 /* deal with fgens if there are any */
625 if (m->fn.o.fgen_init != NULL) {
626 NGFENS *names = m->fn.o.fgen_init(csound);
627 for (i = 0; names[i].name != NULL; i++)
628 allocgen(csound, names[i].name, names[i].fn);
629 }
630 if (m->fn.o.opcode_init != NULL) {
631 OENTRY *opcodlst_n;
632 long length;
633 /* load opcodes */
634 if (UNLIKELY((length = m->fn.o.opcode_init(csound, &opcodlst_n)) < 0L))
635 return CSOUND_ERROR;
636 else {
637 length /= (long) sizeof(OENTRY);
638 if (length) {
639 if (UNLIKELY(csoundAppendOpcodes(csound, opcodlst_n,
640 (int) length) != 0))
641 return CSOUND_ERROR;
642 }
643 }
644 }
645 }
646 return CSOUND_SUCCESS;
647 }
648
649 /**
650 * Call initialisation functions of all loaded modules that have a
651 * csoundModuleInit symbol, for Csound instance 'csound'.
652 * Return value is CSOUND_SUCCESS if there was no error, and CSOUND_ERROR if
653 * some modules could not be initialised.
654 */
655
csoundInitModules(CSOUND * csound)656 int csoundInitModules(CSOUND *csound)
657 {
658 csoundModule_t *m;
659 int i, retval = CSOUND_SUCCESS;
660 /* For regular Csound, init_static_modules is not compiled or called.
661 * For some builds of Csound, e.g. for PNaCl, init_static_modules is
662 * compiled and called to initialize statically linked opcodes and other
663 * plugins that are dynamically loaded on other platforms.
664 */
665 #if defined(INIT_STATIC_MODULES)
666 retval = init_static_modules(csound);
667 #endif
668 /* call init functions */
669 for (m = (csoundModule_t*) csound->csmodule_db; m != NULL; m = m->nxt) {
670 i = csoundInitModule(csound, m);
671 if (UNLIKELY(i != CSOUND_SUCCESS && i < retval))
672 retval = i;
673 }
674 /* return with error code */
675 return retval;
676 }
677
678 /* load a plugin library and also initialise it */
679 /* called on deferred loading of opcode plugins */
680
csoundLoadAndInitModule(CSOUND * csound,const char * fname)681 int csoundLoadAndInitModule(CSOUND *csound, const char *fname)
682 {
683 volatile jmp_buf tmpExitJmp;
684 volatile int err;
685
686 err = csoundLoadExternal(csound, fname);
687 if (UNLIKELY(err != 0))
688 return err;
689 memcpy((void*) &tmpExitJmp, (void*) &csound->exitjmp, sizeof(jmp_buf));
690 if (UNLIKELY((err = setjmp(csound->exitjmp)) != 0)) {
691 memcpy((void*) &csound->exitjmp, (void*) &tmpExitJmp, sizeof(jmp_buf));
692 return (err == (CSOUND_EXITJMP_SUCCESS + CSOUND_MEMORY) ?
693 CSOUND_MEMORY : CSOUND_INITIALIZATION);
694 }
695 /* NOTE: this depends on csound->csmodule_db being the most recently */
696 /* loaded plugin library */
697 err = csoundInitModule(csound, (csoundModule_t*) csound->csmodule_db);
698 memcpy((void*) &csound->exitjmp, (void*) &tmpExitJmp, sizeof(jmp_buf));
699
700 return err;
701 }
702
csoundLoadAndInitModules(CSOUND * csound,const char * opdir)703 int csoundLoadAndInitModules(CSOUND *csound, const char *opdir)
704 {
705 #if (defined(HAVE_DIRENT_H) && (TARGET_OS_IPHONE == 0))
706 DIR *dir;
707 struct dirent *f;
708 const char *dname, *fname;
709 char buf[1024];
710 int i, n, len, err = CSOUND_SUCCESS;
711 char *dname1, *end;
712 int read_directory = 1;
713 char sep =
714 #ifdef WIN32
715 ';';
716 #else
717 ':';
718 #endif
719 #ifdef __HAIKU__
720 int dfltdir = 0;
721 #endif
722
723 if (UNLIKELY(csound->csmodule_db != NULL))
724 return CSOUND_ERROR;
725
726 /* open plugin directory */
727 dname = csoundGetEnv(csound, (sizeof(MYFLT) == sizeof(float) ?
728 plugindir_envvar : plugindir64_envvar));
729 if (dname == NULL) {
730 #if ENABLE_OPCODEDIR_WARNINGS
731 csound->opcodedirWasOK = 0;
732 # ifdef USE_DOUBLE
733 dname = csoundGetEnv(csound, plugindir_envvar);
734 if (dname == NULL)
735 # endif
736 #endif
737 #ifdef CS_DEFAULT_PLUGINDIR
738 dname = CS_DEFAULT_PLUGINDIR;
739 #ifdef __HAIKU__
740 dfltdir = 1;
741 #endif
742 #else
743 dname = "";
744 #endif
745 }
746
747 if (opdir != NULL) {
748 dname = opdir;
749 }
750
751 /* We now loop through the directory list */
752 while(read_directory) {
753 /* find separator */
754 if((end = strchr(dname, sep)) != NULL) {
755 *end = '\0';
756 /* copy directory name */
757 dname1 = cs_strdup(csound, (char *) dname);
758 *end = sep; /* restore for re-execution */
759 /* move to next directory name */
760 dname = end + 1;
761 } else {
762 /* copy last directory name) */
763 dname1 = cs_strdup(csound, (char *) dname);
764 read_directory = 0;
765 }
766
767 /* protect for the case where there is an
768 extra separator at the end */
769 if(*dname1 == '\0') {
770 csound->Free(csound, dname1);
771 break;
772 }
773
774 dir = opendir(dname1);
775 if (UNLIKELY(dir == (DIR*) NULL)) {
776 #if defined(__HAIKU__)
777 if(!dfltdir)
778 #endif
779 csound->Warning(csound, Str("Error opening plugin directory '%s': %s"),
780 dname1, strerror(errno));
781 csound->Free(csound, dname1);
782 continue;
783 }
784
785 if(UNLIKELY(csound->oparms->odebug))
786 csound->Message(csound, "Opening plugin directory: %s\n", dname1);
787 /* load database for deferred plugin loading */
788 /* n = csoundLoadOpcodeDB(csound, dname); */
789 /* if (n != 0) */
790 /* return n; */
791 /* scan all files in directory */
792 while ((f = readdir(dir)) != NULL) {
793 fname = &(f->d_name[0]);
794 if (UNLIKELY(fname[0]=='_')) continue;
795 n = len = (int) strlen(fname);
796 if (UNLIKELY(fname[0]=='_')) continue;
797 #if defined(WIN32)
798 strcpy(buf, "dll");
799 n -= 4;
800 #elif defined(__MACH__)
801 strcpy(buf, "dylib");
802 n -= 6;
803 #else
804 strcpy(buf, "so");
805 n -= 3;
806 #endif
807 if (n <= 0 || fname[n] != '.')
808 continue;
809 i = 0;
810 do {
811 if (UNLIKELY((fname[++n] | (char) 0x20) != buf[i]))
812 break;
813 } while (buf[++i] != '\0');
814 if (buf[i] != '\0')
815 continue;
816 /* found a dynamic library, attempt to open it */
817 if (UNLIKELY(((int) strlen(dname) + len + 2) > 1024)) {
818 csound->Warning(csound, Str("path name too long, skipping '%s'"),
819 fname);
820 continue;
821 }
822 /* printf("DEBUG %s(%d): possibly deny %s\n", __FILE__, __LINE__,fname); */
823 if (UNLIKELY(csoundCheckOpcodeDeny(csound, fname))) {
824 csoundWarning(csound, Str("Library %s omitted\n"), fname);
825 continue;
826 }
827 snprintf(buf, 1024, "%s%c%s", dname1, DIRSEP, fname);
828 if (UNLIKELY(csound->oparms->odebug)) {
829 csoundMessage(csound, Str("Loading '%s'\n"), buf);
830 }
831 n = csoundLoadAndInitModule(csound, buf);
832 if (UNLIKELY(UNLIKELY(n == CSOUND_ERROR)))
833 continue; /* ignore non-plugin files */
834 if (UNLIKELY(n < err))
835 err = n; /* record serious errors */
836 }
837 closedir(dir);
838 csound->Free(csound, dname1);
839 }
840 return (err == CSOUND_INITIALIZATION ? CSOUND_ERROR : err);
841 #else
842 return CSOUND_SUCCESS;
843 #endif /* HAVE_DIRENT_H */
844 }
845
846 /**
847 * Call destructor functions of all loaded modules that have a
848 * csoundModuleDestroy symbol, for Csound instance 'csound'.
849 * Return value is CSOUND_SUCCESS if there was no error, and
850 * CSOUND_ERROR if some modules could not be de-initialised.
851 */
852 extern int sfont_ModuleDestroy(CSOUND *csound);
csoundDestroyModules(CSOUND * csound)853 int csoundDestroyModules(CSOUND *csound)
854 {
855 csoundModule_t *m;
856 int i, retval;
857
858 retval = CSOUND_SUCCESS;
859 while (csound->csmodule_db != NULL) {
860
861 m = (csoundModule_t*) csound->csmodule_db;
862 /* call destructor functions */
863 if (m->PreInitFunc != NULL && m->fn.p.DestFunc != NULL) {
864 i = m->fn.p.DestFunc(csound);
865 if (UNLIKELY(i != 0)) {
866 print_module_error(csound, Str("Error de-initialising module '%s'"),
867 &(m->name[0]), m, i);
868 retval = CSOUND_ERROR;
869 }
870 }
871 /* unload library */
872 csoundCloseLibrary(m->h);
873 csound->csmodule_db = (void*) m->nxt;
874 /* free memory used by database */
875 csound->Free(csound, (void*) m);
876
877 }
878 sfont_ModuleDestroy(csound);
879 /* return with error code */
880 return retval;
881 }
882
883 /* ------------------------------------------------------------------------ */
884
885 #if defined(WIN32)
886
csoundOpenLibrary(void ** library,const char * libraryPath)887 PUBLIC int csoundOpenLibrary(void **library, const char *libraryPath)
888 {
889 *library = (void*) LoadLibrary(libraryPath);
890 return (*library != NULL ? 0 : -1);
891 }
892
csoundCloseLibrary(void * library)893 PUBLIC int csoundCloseLibrary(void *library)
894 {
895 return (int) (FreeLibrary((HMODULE) library) == FALSE ? -1 : 0);
896 }
897
csoundGetLibrarySymbol(void * library,const char * procedureName)898 PUBLIC void *csoundGetLibrarySymbol(void *library, const char *procedureName)
899 {
900 return (void*) GetProcAddress((HMODULE) library, procedureName);
901 }
902
903 #elif !(defined(NACL)) && (defined(LINUX) || defined(NEW_MACH_CODE) || defined(__HAIKU__))
904
csoundOpenLibrary(void ** library,const char * libraryPath)905 PUBLIC int csoundOpenLibrary(void **library, const char *libraryPath)
906 {
907 int flg = RTLD_NOW;
908 if (libraryPath != NULL) {
909 int len = (int) strlen(libraryPath);
910 /* ugly hack to fix importing modules in Python opcodes */
911 if (len >= 9 && strcmp(&(libraryPath[len - 9]), "/libpy.so") == 0)
912 flg |= RTLD_GLOBAL;
913 if (len >= 12 && strcmp(&(libraryPath[len - 12]), "/libpy.dylib") == 0)
914 flg |= RTLD_GLOBAL;
915 }
916 *library = (void*) dlopen(libraryPath, flg);
917 return (*library != NULL ? 0 : -1);
918 }
919
csoundCloseLibrary(void * library)920 PUBLIC int csoundCloseLibrary(void *library)
921 {
922 return (int) dlclose(library);
923 }
924
csoundGetLibrarySymbol(void * library,const char * procedureName)925 PUBLIC void *csoundGetLibrarySymbol(void *library, const char *procedureName)
926 {
927 return (void*) dlsym(library, procedureName);
928 }
929
930 #else /* case for platforms without shared libraries -- added 062404, akozar */
931
csoundOpenLibrary(void ** library,const char * libraryPath)932 int csoundOpenLibrary(void **library, const char *libraryPath)
933 {
934 *library = NULL;
935 return -1;
936 }
937
csoundCloseLibrary(void * library)938 int csoundCloseLibrary(void *library)
939 {
940 return 0;
941 }
942
csoundGetLibrarySymbol(void * library,const char * procedureName)943 void *csoundGetLibrarySymbol(void *library, const char *procedureName)
944 {
945 return NULL;
946 }
947
948 #endif
949
950 #if ENABLE_OPCODEDIR_WARNINGS
951 static const char *opcodedirWarnMsg[] = {
952 "################################################################",
953 #ifndef USE_DOUBLE
954 "# WARNING: OPCODE6DIR IS NOT SET ! #",
955 #else
956 "# WARNING: OPCODE6DIR64 IS NOT SET ! #",
957 #endif
958 "# Csound requires this environment variable to be set to find #",
959 "# its plugin libraries. If it is not set, you may experience #",
960 "# missing opcodes, audio/MIDI drivers, or utilities. #",
961 "################################################################",
962 NULL
963 };
964 #endif
965
print_opcodedir_warning(CSOUND * p)966 void print_opcodedir_warning(CSOUND *p)
967 {
968 #if ENABLE_OPCODEDIR_WARNINGS
969 if (!p->opcodedirWasOK) {
970 const char **sp;
971 for (sp = &(opcodedirWarnMsg[0]); *sp != NULL; sp++)
972 p->MessageS(p, CSOUNDMSG_WARNING, " %s\n", Str(*sp));
973 }
974 #else
975 (void) p;
976 #endif
977 }
978
979 typedef long (*INITFN)(CSOUND *, void *);
980
981 extern long babo_localops_init(CSOUND *, void *);
982 extern long bilbar_localops_init(CSOUND *, void *);
983 extern long compress_localops_init(CSOUND *, void *);
984 extern long pvsbuffer_localops_init(CSOUND *, void *);
985 extern long vosim_localops_init(CSOUND *, void *);
986 extern long eqfil_localops_init(CSOUND *, void *);
987 extern long modal4_localops_init(CSOUND *, void *);
988 extern long scoreline_localops_init(CSOUND *, void *);
989 extern long physmod_localops_init(CSOUND *, void *);
990 extern long modmatrix_localops_init(CSOUND *, void *);
991 extern long spectra_localops_init(CSOUND *, void *);
992 extern long ambicode1_localops_init(CSOUND *, void *);
993 extern long grain4_localops_init(CSOUND *, void *);
994 extern long hrtferX_localops_init(CSOUND *, void *);
995 extern long loscilx_localops_init(CSOUND *, void *);
996 extern long pan2_localops_init(CSOUND *, void *);
997 extern long arrayvars_localops_init(CSOUND *, void *);
998 extern long phisem_localops_init(CSOUND *, void *);
999 extern long pvoc_localops_init(CSOUND *, void *);
1000 extern long hrtfopcodes_localops_init(CSOUND *, void *);
1001 extern long hrtfreverb_localops_init(CSOUND *, void *);
1002 extern long hrtfearly_localops_init(CSOUND *, void *);
1003 extern long minmax_localops_init(CSOUND *, void *);
1004 extern long gendy_localops_init(CSOUND *, void *);
1005 //extern long stackops_localops_init(CSOUND *, void *);
1006 extern long vbap_localops_init(CSOUND *, void *);
1007 extern long vaops_localops_init(CSOUND *, void*);
1008 extern long ugakbari_localops_init(CSOUND *, void *);
1009 extern long harmon_localops_init(CSOUND *, void *);
1010 extern long pitchtrack_localops_init(CSOUND *, void *);
1011 extern long squinewave_localops_init(CSOUND *, void *);
1012
1013 extern long partikkel_localops_init(CSOUND *, void *);
1014 extern long shape_localops_init(CSOUND *, void *);
1015 extern long tabaudio_localops_init(CSOUND *, void *);
1016 extern long tabsum_localops_init(CSOUND *, void *);
1017 extern long crossfm_localops_init(CSOUND *, void *);
1018 extern long pvlock_localops_init(CSOUND *, void *);
1019 extern long fareyseq_localops_init(CSOUND *, void *);
1020 extern long cpumeter_localops_init(CSOUND *, void *);
1021 extern long scnoise_localops_init(CSOUND *, void *);
1022 #ifndef NACL
1023 extern long socksend_localops_init(CSOUND *, void *);
1024 extern long mp3in_localops_init(CSOUND *, void *);
1025 extern long sockrecv_localops_init(CSOUND *, void *);
1026 #endif
1027 extern long afilts_localops_init(CSOUND *, void *);
1028 extern long pinker_localops_init(CSOUND *, void *);
1029 extern long paulstretch_localops_init(CSOUND *, void *);
1030 extern long wpfilters_localops_init(CSOUND *, void *);
1031 extern long zak_localops_init(CSOUND *, void *);
1032 extern long lufs_localops_init(CSOUND *, void *);
1033
1034 extern int stdopc_ModuleInit(CSOUND *csound);
1035 extern int pvsopc_ModuleInit(CSOUND *csound);
1036 extern int sfont_ModuleInit(CSOUND *csound);
1037 extern int sfont_ModuleCreate(CSOUND *csound);
1038 extern int newgabopc_ModuleInit(CSOUND *csound);
1039
1040 const INITFN staticmodules[] = { hrtfopcodes_localops_init, babo_localops_init,
1041 bilbar_localops_init, vosim_localops_init,
1042 compress_localops_init, pvsbuffer_localops_init,
1043 eqfil_localops_init, modal4_localops_init,
1044 scoreline_localops_init, physmod_localops_init,
1045 modmatrix_localops_init, spectra_localops_init,
1046 ambicode1_localops_init, grain4_localops_init,
1047 hrtferX_localops_init, loscilx_localops_init,
1048 pan2_localops_init, arrayvars_localops_init,
1049 phisem_localops_init, pvoc_localops_init,
1050 vbap_localops_init,
1051 ugakbari_localops_init, harmon_localops_init,
1052 pitchtrack_localops_init, partikkel_localops_init,
1053 shape_localops_init, tabsum_localops_init,
1054 crossfm_localops_init, pvlock_localops_init,
1055 fareyseq_localops_init, hrtfearly_localops_init,
1056 hrtfreverb_localops_init, minmax_localops_init,
1057 vaops_localops_init, paulstretch_localops_init,
1058 squinewave_localops_init, tabaudio_localops_init,
1059 #ifdef LINUX
1060 cpumeter_localops_init,
1061 #endif
1062 #ifndef NACL
1063 mp3in_localops_init,
1064 sockrecv_localops_init,
1065 socksend_localops_init,
1066 #endif
1067 scnoise_localops_init, afilts_localops_init,
1068 pinker_localops_init, gendy_localops_init,
1069 wpfilters_localops_init, zak_localops_init,
1070 lufs_localops_init,
1071 NULL };
1072
1073 typedef NGFENS* (*FGINITFN)(CSOUND *);
1074
1075 NGFENS *ftest_fgens_init(CSOUND *);
1076
1077 const FGINITFN fgentab[] = { ftest_fgens_init, NULL };
1078
csoundInitStaticModules(CSOUND * csound)1079 CS_NOINLINE int csoundInitStaticModules(CSOUND *csound)
1080 {
1081 int i;
1082 OENTRY *opcodlst_n;
1083 long length;
1084
1085 for (i=0; staticmodules[i]!=NULL; i++) {
1086 length = (staticmodules[i])(csound, &opcodlst_n);
1087
1088 if (UNLIKELY(length <= 0L)) return CSOUND_ERROR;
1089 length /= (long) sizeof(OENTRY);
1090 if (length) {
1091 if (UNLIKELY(csoundAppendOpcodes(csound, opcodlst_n,
1092 (int) length) != 0))
1093 return CSOUND_ERROR;
1094 }
1095 }
1096 /* stdopc module */
1097 if (UNLIKELY(stdopc_ModuleInit(csound))) return CSOUND_ERROR;
1098
1099 /* pvs module */
1100 if (UNLIKELY(pvsopc_ModuleInit(csound))) return CSOUND_ERROR;
1101
1102 /* sfont module */
1103 sfont_ModuleCreate(csound);
1104 if (UNLIKELY(sfont_ModuleInit(csound))) return CSOUND_ERROR;
1105
1106 /* newgabopc */
1107 if (UNLIKELY(newgabopc_ModuleInit(csound))) return CSOUND_ERROR;
1108
1109 /* modules were initialised successfully */
1110 /* Now fgens */
1111 for (i = 0; fgentab[i]!=NULL; i++) {
1112 int j;
1113 NGFENS *names = (fgentab[i])(csound);
1114 for (j = 0; names[j].name != NULL; j++)
1115 allocgen(csound, names[j].name, names[j].fn);
1116 }
1117 return CSOUND_SUCCESS;
1118 }
1119