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