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