Jack2 1.9.8

JackDriverLoader.cpp

00001 /*
00002 Copyright (C) 2001-2005 Paul Davis
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019 */
00020 
00021 #include "JackSystemDeps.h"
00022 #include "JackDriverLoader.h"
00023 #include "JackConstants.h"
00024 #include "JackError.h"
00025 #include <getopt.h>
00026 #include <stdio.h>
00027 #include <errno.h>
00028 #include <string.h>
00029 
00030 #ifndef WIN32
00031 #include <dirent.h>
00032 #endif
00033 
00034 jack_driver_desc_t* jackctl_driver_get_desc(jackctl_driver_t * driver);
00035 
00036 SERVER_EXPORT void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file)
00037 {
00038     unsigned long i;
00039     char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
00040 
00041     for (i = 0; i < desc->nparams; i++) {
00042         switch (desc->params[i].type) {
00043             case JackDriverParamInt:
00044                 sprintf (arg_default, "%" "i", desc->params[i].value.i);
00045                 break;
00046             case JackDriverParamUInt:
00047                 sprintf (arg_default, "%" "u", desc->params[i].value.ui);
00048                 break;
00049             case JackDriverParamChar:
00050                 sprintf (arg_default, "%c", desc->params[i].value.c);
00051                 break;
00052             case JackDriverParamString:
00053                 if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0) {
00054                     sprintf (arg_default, "%s", desc->params[i].value.str);
00055                 } else {
00056                     sprintf (arg_default, "none");
00057                 }
00058                 break;
00059             case JackDriverParamBool:
00060                 sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
00061                 break;
00062         }
00063 
00064         fprintf(file, "\t-%c, --%s \t%s (default: %s)\n",
00065                  desc->params[i].character,
00066                  desc->params[i].name,
00067                  desc->params[i].long_desc,
00068                  arg_default);
00069     }
00070 }
00071 
00072 static void
00073 jack_print_driver_param_usage (jack_driver_desc_t* desc, unsigned long param, FILE *file)
00074 {
00075     fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
00076              desc->params[param].name, desc->name);
00077     fprintf (file, "%s\n", desc->params[param].long_desc);
00078 }
00079 
00080 SERVER_EXPORT void jack_free_driver_params(JSList * driver_params)
00081 {
00082     JSList*node_ptr = driver_params;
00083     JSList*next_node_ptr;
00084 
00085     while (node_ptr) {
00086         next_node_ptr = node_ptr->next;
00087         free(node_ptr->data);
00088         free(node_ptr);
00089         node_ptr = next_node_ptr;
00090     }
00091 }
00092 
00093 SERVER_EXPORT int
00094 jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSList** param_ptr)
00095 {
00096     struct option * long_options;
00097     char* options, * options_ptr;
00098     unsigned long i;
00099     int opt;
00100     unsigned int param_index;
00101     JSList* params = NULL;
00102     jack_driver_param_t * driver_param;
00103 
00104     if (argc <= 1) {
00105         *param_ptr = NULL;
00106         return 0;
00107     }
00108 
00109     /* check for help */
00110     if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
00111         if (argc > 2) {
00112             for (i = 0; i < desc->nparams; i++) {
00113                 if (strcmp (desc->params[i].name, argv[2]) == 0) {
00114                     jack_print_driver_param_usage (desc, i, stdout);
00115                     return 1;
00116                 }
00117             }
00118 
00119             fprintf (stderr, "jackd: unknown option '%s' "
00120                      "for driver '%s'\n", argv[2],
00121                      desc->name);
00122         }
00123 
00124         jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
00125         jack_print_driver_options (desc, stdout);
00126         return 1;
00127     }
00128 
00129     /* set up the stuff for getopt */
00130     options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
00131     long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
00132 
00133     options_ptr = options;
00134     for (i = 0; i < desc->nparams; i++) {
00135         sprintf (options_ptr, "%c::", desc->params[i].character);
00136         options_ptr += 3;
00137         long_options[i].name = desc->params[i].name;
00138         long_options[i].flag = NULL;
00139         long_options[i].val = desc->params[i].character;
00140         long_options[i].has_arg = optional_argument;
00141     }
00142 
00143     /* create the params */
00144     optind = 0;
00145     opterr = 0;
00146     while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
00147 
00148         if (opt == ':' || opt == '?') {
00149             if (opt == ':') {
00150                 fprintf (stderr, "Missing option to argument '%c'\n", optopt);
00151             } else {
00152                 fprintf (stderr, "Unknownage with option '%c'\n", optopt);
00153             }
00154 
00155             fprintf (stderr, "Options for driver '%s':\n", desc->name);
00156             jack_print_driver_options (desc, stderr);
00157             return 1;
00158         }
00159 
00160         for (param_index = 0; param_index < desc->nparams; param_index++) {
00161             if (opt == desc->params[param_index].character) {
00162                 break;
00163             }
00164         }
00165 
00166         driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
00167         driver_param->character = desc->params[param_index].character;
00168 
00169         if (!optarg && optind < argc &&
00170                 strlen(argv[optind]) &&
00171                 argv[optind][0] != '-') {
00172             optarg = argv[optind];
00173         }
00174 
00175         if (optarg) {
00176             switch (desc->params[param_index].type) {
00177                 case JackDriverParamInt:
00178                     driver_param->value.i = atoi(optarg);
00179                     break;
00180                 case JackDriverParamUInt:
00181                     driver_param->value.ui = strtoul(optarg, NULL, 10);
00182                     break;
00183                 case JackDriverParamChar:
00184                     driver_param->value.c = optarg[0];
00185                     break;
00186                 case JackDriverParamString:
00187                     strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
00188                     break;
00189                 case JackDriverParamBool:
00190                     if (strcasecmp("false", optarg) == 0 ||
00191                         strcasecmp("off", optarg) == 0 ||
00192                         strcasecmp("no", optarg) == 0 ||
00193                         strcasecmp("0", optarg) == 0 ||
00194                         strcasecmp("(null)", optarg) == 0 ) {
00195                         driver_param->value.i = false;
00196                     } else {
00197                         driver_param->value.i = true;
00198                     }
00199                     break;
00200             }
00201         } else {
00202             if (desc->params[param_index].type == JackDriverParamBool) {
00203                 driver_param->value.i = true;
00204             } else {
00205                 driver_param->value = desc->params[param_index].value;
00206             }
00207         }
00208 
00209         params = jack_slist_append (params, driver_param);
00210     }
00211 
00212     free (options);
00213     free (long_options);
00214 
00215     if (param_ptr) {
00216         *param_ptr = params;
00217     }
00218     return 0;
00219 }
00220 
00221 SERVER_EXPORT int
00222 jackctl_parse_driver_params(jackctl_driver *driver_ptr, int argc, char* argv[])
00223 {
00224     struct option* long_options;
00225     char* options, * options_ptr;
00226     unsigned long i;
00227     int opt;
00228     JSList* node_ptr;
00229     jackctl_parameter_t * param = NULL;
00230     union jackctl_parameter_value value;
00231 
00232     if (argc <= 1) {
00233         return 0;
00234     }
00235 
00236     const JSList* driver_params = jackctl_driver_get_parameters(driver_ptr);
00237     if (driver_params == NULL) {
00238         return 1;
00239     }
00240 
00241     jack_driver_desc_t* desc = jackctl_driver_get_desc(driver_ptr);
00242 
00243     /* check for help */
00244     if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
00245         if (argc > 2) {
00246             for (i = 0; i < desc->nparams; i++) {
00247                 if (strcmp (desc->params[i].name, argv[2]) == 0) {
00248                     jack_print_driver_param_usage (desc, i, stdout);
00249                     return 1;
00250                 }
00251             }
00252 
00253             fprintf (stderr, "jackd: unknown option '%s' "
00254                      "for driver '%s'\n", argv[2],
00255                      desc->name);
00256         }
00257 
00258         jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
00259         jack_print_driver_options (desc, stdout);
00260         return 1;
00261     }
00262 
00263    /* set up the stuff for getopt */
00264     options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
00265     long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
00266 
00267     options_ptr = options;
00268     for (i = 0; i < desc->nparams; i++) {
00269         sprintf(options_ptr, "%c::", desc->params[i].character);
00270         options_ptr += 3;
00271         long_options[i].name = desc->params[i].name;
00272         long_options[i].flag = NULL;
00273         long_options[i].val = desc->params[i].character;
00274         long_options[i].has_arg = optional_argument;
00275     }
00276 
00277     /* create the params */
00278     optind = 0;
00279     opterr = 0;
00280     while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
00281 
00282         if (opt == ':' || opt == '?') {
00283             if (opt == ':') {
00284                 fprintf (stderr, "Missing option to argument '%c'\n", optopt);
00285             } else {
00286                 fprintf (stderr, "Unknownage with option '%c'\n", optopt);
00287             }
00288 
00289             fprintf (stderr, "Options for driver '%s':\n", desc->name);
00290             jack_print_driver_options(desc, stderr);
00291             return 1;
00292         }
00293 
00294         node_ptr = (JSList *)driver_params;
00295         while (node_ptr) {
00296             param = (jackctl_parameter_t*)node_ptr->data;
00297             if (opt == jackctl_parameter_get_id(param)) {
00298                 break;
00299             }
00300             node_ptr = node_ptr->next;
00301         }
00302 
00303         if (!optarg && optind < argc &&
00304             strlen(argv[optind]) &&
00305             argv[optind][0] != '-') {
00306             optarg = argv[optind];
00307         }
00308 
00309         if (optarg) {
00310             switch (jackctl_parameter_get_type(param)) {
00311                 case JackDriverParamInt:
00312                     value.i = atoi(optarg);
00313                     jackctl_parameter_set_value(param, &value);
00314                     break;
00315                 case JackDriverParamUInt:
00316                     value.ui = strtoul(optarg, NULL, 10);
00317                     jackctl_parameter_set_value(param, &value);
00318                     break;
00319                 case JackDriverParamChar:
00320                     value.c = optarg[0];
00321                     jackctl_parameter_set_value(param, &value);
00322                     break;
00323                 case JackDriverParamString:
00324                     strncpy(value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
00325                     jackctl_parameter_set_value(param, &value);
00326                     break;
00327                 case JackDriverParamBool:
00328                     if (strcasecmp("false", optarg) == 0 ||
00329                         strcasecmp("off", optarg) == 0 ||
00330                         strcasecmp("no", optarg) == 0 ||
00331                         strcasecmp("0", optarg) == 0 ||
00332                         strcasecmp("(null)", optarg) == 0 ) {
00333                         value.i = false;
00334                     } else {
00335                         value.i = true;
00336                     }
00337                     jackctl_parameter_set_value(param, &value);
00338                     break;
00339             }
00340         } else {
00341             if (jackctl_parameter_get_type(param) == JackParamBool) {
00342                 value.i = true;
00343             } else {
00344                 value = jackctl_parameter_get_default_value(param);
00345             }
00346             jackctl_parameter_set_value(param, &value);
00347         }
00348     }
00349 
00350     free(options);
00351     free(long_options);
00352     return 0;
00353 }
00354 
00355 jack_driver_desc_t*
00356 jack_find_driver_descriptor (JSList * drivers, const char* name)
00357 {
00358     jack_driver_desc_t* desc = 0;
00359     JSList* node;
00360 
00361     for (node = drivers; node; node = jack_slist_next (node)) {
00362         desc = (jack_driver_desc_t*) node->data;
00363 
00364         if (strcmp (desc->name, name) != 0) {
00365             desc = NULL;
00366         } else {
00367             break;
00368         }
00369     }
00370 
00371     return desc;
00372 }
00373 
00374 static jack_driver_desc_t*
00375 jack_get_descriptor (JSList * drivers, const char* sofile, const char* symbol)
00376 {
00377     jack_driver_desc_t* descriptor, * other_descriptor;
00378     JackDriverDescFunction so_get_descriptor = NULL;
00379     JSList* node;
00380     void * dlhandle;
00381     char* filename;
00382 #ifdef WIN32
00383     int dlerr;
00384 #else
00385     const char* dlerr;
00386 #endif
00387 
00388     int err;
00389     const char* driver_dir;
00390 
00391     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00392         // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
00393         // for posix systems, it is absolute path of default driver dir
00394 #ifdef WIN32
00395         char temp_driver_dir1[512];
00396         char temp_driver_dir2[512];
00397         if (3 < GetModuleFileName(NULL, temp_driver_dir1, 512)) {
00398             char *p = strrchr(temp_driver_dir1, '\\');
00399             if (p && (p != temp_driver_dir1))
00400                 *p = 0;
00401             else
00402                 GetCurrentDirectory(512, temp_driver_dir1);
00403         } else {
00404             GetCurrentDirectory(512, temp_driver_dir1);
00405         }
00406         sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
00407         driver_dir = temp_driver_dir2;
00408 #else
00409         driver_dir = ADDON_DIR;
00410 #endif
00411     }
00412 
00413     int len = strlen(driver_dir) + 1 + strlen(sofile) + 1;
00414     filename = (char*)malloc(len);
00415     snprintf(filename, len, "%s/%s", driver_dir, sofile);
00416 
00417     if ((dlhandle = LoadDriverModule(filename)) == NULL) {
00418 #ifdef WIN32
00419         jack_error ("could not open driver .dll '%s': %ld", filename, GetLastError());
00420 #else
00421         jack_error ("could not open driver .so '%s': %s", filename, dlerror());
00422 #endif
00423 
00424         free(filename);
00425         return NULL;
00426     }
00427 
00428     so_get_descriptor = (JackDriverDescFunction)GetDriverProc(dlhandle, symbol);
00429 
00430 #ifdef WIN32
00431     if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
00432         jack_error("jack_get_descriptor : dll is not a driver, err = %ld", dlerr);
00433 #else
00434     if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
00435         jack_error("jack_get_descriptor err = %s", dlerr);
00436 #endif
00437 
00438         UnloadDriverModule(dlhandle);
00439         free(filename);
00440         return NULL;
00441     }
00442 
00443     if ((descriptor = so_get_descriptor ()) == NULL) {
00444         jack_error("driver from '%s' returned NULL descriptor", filename);
00445         UnloadDriverModule(dlhandle);
00446         free(filename);
00447         return NULL;
00448     }
00449 
00450 #ifdef WIN32
00451     if ((err = UnloadDriverModule(dlhandle)) == 0) {
00452         jack_error ("error closing driver .so '%s': %ld", filename, GetLastError ());
00453     }
00454 #else
00455     if ((err = UnloadDriverModule(dlhandle)) != 0) {
00456         jack_error ("error closing driver .so '%s': %s", filename, dlerror ());
00457     }
00458 #endif
00459 
00460     /* check it doesn't exist already */
00461     for (node = drivers; node; node = jack_slist_next (node)) {
00462         other_descriptor = (jack_driver_desc_t*) node->data;
00463 
00464         if (strcmp(descriptor->name, other_descriptor->name) == 0) {
00465             jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first",
00466                        other_descriptor->file, filename, other_descriptor->name);
00467             /* FIXME: delete the descriptor */
00468             free(filename);
00469             return NULL;
00470         }
00471     }
00472 
00473     strncpy(descriptor->file, filename, JACK_PATH_MAX);
00474     free(filename);
00475     return descriptor;
00476 }
00477 
00478 static bool check_symbol(const char* sofile, const char* symbol)
00479 {
00480     void * dlhandle;
00481     bool res = false;
00482     const char* driver_dir;
00483 
00484     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00485         // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
00486         // for posix systems, it is absolute path of default driver dir
00487 #ifdef WIN32
00488         char temp_driver_dir1[512];
00489         char temp_driver_dir2[512];
00490         if (3 < GetModuleFileName(NULL, temp_driver_dir1, 512)) {
00491             char *p = strrchr(temp_driver_dir1, '\\');
00492             if (p && (p != temp_driver_dir1))
00493                 *p = 0;
00494             else
00495                 GetCurrentDirectory(512, temp_driver_dir1);
00496         } else {
00497             GetCurrentDirectory(512, temp_driver_dir1);
00498         }
00499         snprintf(temp_driver_dir2, sizeof(temp_driver_dir2), "%s/%s", temp_driver_dir1, ADDON_DIR);
00500         driver_dir = temp_driver_dir2;
00501 #else
00502         driver_dir = ADDON_DIR;
00503 #endif
00504     }
00505 
00506     int len = strlen(driver_dir) + 1 + strlen(sofile) + 1;
00507     char* filename = (char*)malloc(len);
00508     snprintf(filename, len, "%s/%s", driver_dir, sofile);
00509 
00510     if ((dlhandle = LoadDriverModule(filename)) == NULL) {
00511 #ifdef WIN32
00512         jack_error ("could not open component .dll '%s': %ld", filename, GetLastError());
00513 #else
00514         jack_error ("could not open component .so '%s': %s", filename, dlerror());
00515 #endif
00516      } else {
00517         res = (GetDriverProc(dlhandle, symbol)) ? true : false;
00518         UnloadDriverModule(dlhandle);
00519     }
00520 
00521     free(filename);
00522     return res;
00523 }
00524 
00525 #ifdef WIN32
00526 
00527 JSList *
00528 jack_drivers_load (JSList * drivers) {
00529     char* driver_dir;
00530     char driver_dir_storage[512];
00531     char dll_filename[512];
00532     WIN32_FIND_DATA filedata;
00533     HANDLE file;
00534     const char* ptr = NULL;
00535     JSList* driver_list = NULL;
00536     jack_driver_desc_t* desc = NULL;
00537 
00538     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00539         // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
00540         if (3 < GetModuleFileName(NULL, driver_dir_storage, 512)) {
00541             char *p = strrchr(driver_dir_storage, '\\');
00542             if (p && (p != driver_dir_storage))
00543                 *p = 0;
00544             else
00545                 GetCurrentDirectory(512, driver_dir_storage);
00546         } else {
00547             GetCurrentDirectory(512, driver_dir_storage);
00548         }
00549         strcat(driver_dir_storage, "/");
00550         strcat(driver_dir_storage, ADDON_DIR);
00551         driver_dir = driver_dir_storage;
00552     }
00553 
00554     snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir);
00555 
00556     file = (HANDLE )FindFirstFile(dll_filename, &filedata);
00557 
00558     if (file == INVALID_HANDLE_VALUE) {
00559         jack_error("error invalid handle");
00560         return NULL;
00561     }
00562 
00563     do {
00564         /* check the filename is of the right format */
00565         if (strncmp ("jack_", filedata.cFileName, 5) != 0) {
00566             continue;
00567         }
00568 
00569         ptr = strrchr (filedata.cFileName, '.');
00570         if (!ptr) {
00571             continue;
00572         }
00573         ptr++;
00574         if (strncmp ("dll", ptr, 3) != 0) {
00575             continue;
00576         }
00577 
00578         /* check if dll is an internal client */
00579         if (check_symbol(filedata.cFileName, "jack_internal_initialize")) {
00580              continue;
00581         }
00582 
00583         desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor");
00584         if (desc) {
00585             driver_list = jack_slist_append (driver_list, desc);
00586         } else {
00587             jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
00588         }
00589 
00590     } while (FindNextFile(file, &filedata));
00591 
00592     if (!driver_list) {
00593         jack_error ("could not find any drivers in %s!", driver_dir);
00594         return NULL;
00595     }
00596 
00597     return driver_list;
00598 }
00599 
00600 #else
00601 
00602 JSList *
00603 jack_drivers_load (JSList * drivers) {
00604     struct dirent * dir_entry;
00605     DIR * dir_stream;
00606     const char* ptr;
00607     int err;
00608     JSList* driver_list = NULL;
00609     jack_driver_desc_t* desc = NULL;
00610 
00611     const char* driver_dir;
00612     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00613         driver_dir = ADDON_DIR;
00614     }
00615 
00616     /* search through the driver_dir and add get descriptors
00617     from the .so files in it */
00618     dir_stream = opendir (driver_dir);
00619     if (!dir_stream) {
00620         jack_error ("could not open driver directory %s: %s",
00621                     driver_dir, strerror (errno));
00622         return NULL;
00623     }
00624 
00625     while ((dir_entry = readdir(dir_stream))) {
00626 
00627         /* check the filename is of the right format */
00628         if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
00629             continue;
00630         }
00631 
00632         ptr = strrchr (dir_entry->d_name, '.');
00633         if (!ptr) {
00634             continue;
00635         }
00636         ptr++;
00637         if (strncmp ("so", ptr, 2) != 0) {
00638             continue;
00639         }
00640 
00641         /* check if dll is an internal client */
00642         if (check_symbol(dir_entry->d_name, "jack_internal_initialize")) {
00643              continue;
00644         }
00645 
00646         desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor");
00647         if (desc) {
00648             driver_list = jack_slist_append (driver_list, desc);
00649         } else {
00650             jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
00651         }
00652     }
00653 
00654     err = closedir (dir_stream);
00655     if (err) {
00656         jack_error ("error closing driver directory %s: %s",
00657                     driver_dir, strerror (errno));
00658     }
00659 
00660     if (!driver_list) {
00661         jack_error ("could not find any drivers in %s!", driver_dir);
00662         return NULL;
00663     }
00664 
00665     return driver_list;
00666 }
00667 
00668 #endif
00669 
00670 #ifdef WIN32
00671 
00672 JSList *
00673 jack_internals_load (JSList * internals) {
00674     char* driver_dir;
00675     char driver_dir_storage[512];
00676     char dll_filename[512];
00677     WIN32_FIND_DATA filedata;
00678     HANDLE file;
00679     const char* ptr = NULL;
00680     JSList* driver_list = NULL;
00681     jack_driver_desc_t* desc;
00682 
00683     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00684         // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
00685         if (3 < GetModuleFileName(NULL, driver_dir_storage, 512)) {
00686             char *p = strrchr(driver_dir_storage, '\\');
00687             if (p && (p != driver_dir_storage))
00688                 *p = 0;
00689             else
00690                 GetCurrentDirectory(512, driver_dir_storage);
00691         } else {
00692             GetCurrentDirectory(512, driver_dir_storage);
00693         }
00694         strcat(driver_dir_storage, "/");
00695         strcat(driver_dir_storage, ADDON_DIR);
00696         driver_dir = driver_dir_storage;
00697     }
00698 
00699     snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir);
00700 
00701     file = (HANDLE )FindFirstFile(dll_filename, &filedata);
00702 
00703     if (file == INVALID_HANDLE_VALUE) {
00704         jack_error("could not open driver directory %s", driver_dir);
00705         return NULL;
00706     }
00707 
00708     do {
00709 
00710         ptr = strrchr (filedata.cFileName, '.');
00711         if (!ptr) {
00712             continue;
00713         }
00714         ptr++;
00715         if (strncmp ("dll", ptr, 3) != 0) {
00716             continue;
00717         }
00718 
00719         /* check if dll is an internal client */
00720         if (!check_symbol(filedata.cFileName, "jack_internal_initialize")) {
00721              continue;
00722         }
00723 
00724         desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor");
00725         if (desc) {
00726             driver_list = jack_slist_append (driver_list, desc);
00727         } else {
00728             jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
00729         }
00730 
00731     } while (FindNextFile(file, &filedata));
00732 
00733     if (!driver_list) {
00734         jack_error ("could not find any internals in %s!", driver_dir);
00735         return NULL;
00736     }
00737 
00738     return driver_list;
00739 }
00740 
00741 #else
00742 
00743 JSList *
00744 jack_internals_load (JSList * internals) {
00745     struct dirent * dir_entry;
00746     DIR * dir_stream;
00747     const char* ptr;
00748     int err;
00749     JSList* driver_list = NULL;
00750     jack_driver_desc_t* desc;
00751 
00752     const char* driver_dir;
00753     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00754         driver_dir = ADDON_DIR;
00755     }
00756 
00757     /* search through the driver_dir and add get descriptors
00758     from the .so files in it */
00759     dir_stream = opendir (driver_dir);
00760     if (!dir_stream) {
00761         jack_error ("could not open driver directory %s: %s\n",
00762                     driver_dir, strerror (errno));
00763         return NULL;
00764     }
00765 
00766     while ((dir_entry = readdir(dir_stream))) {
00767 
00768         ptr = strrchr (dir_entry->d_name, '.');
00769         if (!ptr) {
00770             continue;
00771         }
00772         ptr++;
00773         if (strncmp ("so", ptr, 2) != 0) {
00774             continue;
00775         }
00776 
00777         /* check if dll is an internal client */
00778         if (!check_symbol(dir_entry->d_name, "jack_internal_initialize")) {
00779              continue;
00780         }
00781 
00782         desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor");
00783         if (desc) {
00784             driver_list = jack_slist_append (driver_list, desc);
00785         } else {
00786             jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
00787         }
00788     }
00789 
00790     err = closedir (dir_stream);
00791     if (err) {
00792         jack_error ("error closing internal directory %s: %s\n",
00793                     driver_dir, strerror (errno));
00794     }
00795 
00796     if (!driver_list) {
00797         jack_error ("could not find any internals in %s!", driver_dir);
00798         return NULL;
00799     }
00800 
00801     return driver_list;
00802 }
00803 
00804 #endif
00805 
00806 Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc,
00807                                                     Jack::JackLockedEngine* engine,
00808                                                     Jack::JackSynchro* synchro,
00809                                                     const JSList* params)
00810 {
00811 #ifdef WIN32
00812     int errstr;
00813 #else
00814     const char* errstr;
00815 #endif
00816 
00817     fHandle = LoadDriverModule (driver_desc->file);
00818 
00819     if (fHandle == NULL) {
00820 #ifdef WIN32
00821         if ((errstr = GetLastError ()) != 0) {
00822             jack_error ("can't load \"%s\": %ld", driver_desc->file, errstr);
00823 #else
00824         if ((errstr = dlerror ()) != 0) {
00825             jack_error ("can't load \"%s\": %s", driver_desc->file, errstr);
00826 #endif
00827 
00828         } else {
00829             jack_error ("bizarre error loading driver shared object %s", driver_desc->file);
00830         }
00831         return NULL;
00832     }
00833 
00834     fInitialize = (driverInitialize)GetDriverProc(fHandle, "driver_initialize");
00835 
00836 #ifdef WIN32
00837     if ((fInitialize == NULL) && (errstr = GetLastError ()) != 0) {
00838 #else
00839     if ((fInitialize == NULL) && (errstr = dlerror ()) != 0) {
00840 #endif
00841         jack_error("no initialize function in shared object %s\n", driver_desc->file);
00842         return NULL;
00843     }
00844 
00845     fBackend = fInitialize(engine, synchro, params);
00846     return fBackend;
00847 }
00848 
00849 JackDriverInfo::~JackDriverInfo()
00850 {
00851     delete fBackend;
00852     if (fHandle)
00853         UnloadDriverModule(fHandle);
00854 }
00855 
00856 SERVER_EXPORT
00857 jack_driver_desc_t*
00858 jack_driver_descriptor_construct(
00859     const char * name,
00860     jack_driver_type_t type,
00861     const char * description,
00862     jack_driver_desc_filler_t * filler_ptr)
00863 {
00864     size_t name_len;
00865     size_t description_len;
00866     jack_driver_desc_t* desc_ptr;
00867 
00868     name_len = strlen(name);
00869     description_len = strlen(description);
00870 
00871     if (name_len > sizeof(desc_ptr->name) - 1 ||
00872         description_len > sizeof(desc_ptr->desc) - 1) {
00873         assert(false);
00874         return 0;
00875     }
00876 
00877     desc_ptr = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
00878     if (desc_ptr == NULL) {
00879         jack_error("calloc() failed to allocate memory for driver descriptor struct");
00880         return 0;
00881     }
00882 
00883     memcpy(desc_ptr->name, name, name_len + 1);
00884     memcpy(desc_ptr->desc, description, description_len + 1);
00885 
00886     desc_ptr->nparams = 0;
00887     desc_ptr->type = type;
00888 
00889     if (filler_ptr != NULL) {
00890         filler_ptr->size = 0;
00891     }
00892 
00893     return desc_ptr;
00894 }
00895 
00896 SERVER_EXPORT
00897 int
00898 jack_driver_descriptor_add_parameter(
00899     jack_driver_desc_t* desc_ptr,
00900     jack_driver_desc_filler_t * filler_ptr,
00901     const char* name,
00902     char character,
00903     jack_driver_param_type_t type,
00904     const jack_driver_param_value_t * value_ptr,
00905     jack_driver_param_constraint_desc_t * constraint,
00906     const char* short_desc,
00907     const char* long_desc)
00908 {
00909     size_t name_len;
00910     size_t short_desc_len;
00911     size_t long_desc_len;
00912     jack_driver_param_desc_t * param_ptr;
00913     size_t newsize;
00914 
00915     name_len = strlen(name);
00916     short_desc_len = strlen(short_desc);
00917 
00918     if (long_desc != NULL) {
00919         long_desc_len = strlen(long_desc);
00920     } else {
00921         long_desc = short_desc;
00922         long_desc_len = short_desc_len;
00923     }
00924 
00925     if (name_len > sizeof(param_ptr->name) - 1 ||
00926         short_desc_len > sizeof(param_ptr->short_desc) - 1 ||
00927         long_desc_len > sizeof(param_ptr->long_desc) - 1) {
00928         assert(false);
00929         return 0;
00930     }
00931 
00932     if (desc_ptr->nparams == filler_ptr->size) {
00933         newsize = filler_ptr->size + 20; // most drivers have less than 20 parameters
00934         param_ptr = (jack_driver_param_desc_t*)realloc (desc_ptr->params, newsize * sizeof (jack_driver_param_desc_t));
00935         if (param_ptr == NULL) {
00936             jack_error("realloc() failed for parameter array of %zu elements", newsize);
00937             return false;
00938         }
00939         filler_ptr->size = newsize;
00940         desc_ptr->params = param_ptr;
00941     }
00942 
00943     assert(desc_ptr->nparams < filler_ptr->size);
00944     param_ptr = desc_ptr->params + desc_ptr->nparams;
00945 
00946     memcpy(param_ptr->name, name, name_len + 1);
00947     param_ptr->character = character;
00948     param_ptr->type = type;
00949     param_ptr->value = *value_ptr;
00950     param_ptr->constraint = constraint;
00951     memcpy(param_ptr->short_desc, short_desc, short_desc_len + 1);
00952     memcpy(param_ptr->long_desc, long_desc, long_desc_len + 1);
00953 
00954     desc_ptr->nparams++;
00955 
00956     return true;
00957 }