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 #ifdef WIN32 
00022 #pragma warning (disable : 4786)
00023 #endif
00024 
00025 #ifndef WIN32 
00026 #ifndef ADDON_DIR
00027 #include "config.h"
00028 #endif
00029 #endif
00030 
00031 #include "JackDriverLoader.h"
00032 #include "JackError.h"
00033 #include <getopt.h>
00034 
00035 #ifndef WIN32 
00036 #include <dirent.h>
00037 #endif
00038 
00039 static void
00040 jack_print_driver_options (jack_driver_desc_t * desc, FILE *file)
00041 {
00042     unsigned long i;
00043     char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
00044 
00045     for (i = 0; i < desc->nparams; i++) {
00046         switch (desc->params[i].type) {
00047             case JackDriverParamInt:
00048                 //sprintf (arg_default, "%" PRIi32, desc->params[i].value.i);
00049                 sprintf (arg_default, "%" "i", desc->params[i].value.i);
00050                 break;
00051             case JackDriverParamUInt:
00052                 //sprintf (arg_default, "%" PRIu32, desc->params[i].value.ui);
00053                 sprintf (arg_default, "%" "u", desc->params[i].value.ui);
00054                 break;
00055             case JackDriverParamChar:
00056                 sprintf (arg_default, "%c", desc->params[i].value.c);
00057                 break;
00058             case JackDriverParamString:
00059                 if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0)
00060                     sprintf (arg_default, "%s", desc->params[i].value.str);
00061                 else
00062                     sprintf (arg_default, "none");
00063                 break;
00064             case JackDriverParamBool:
00065                 sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
00066                 break;
00067         }
00068 
00069         fprintf (file, "\t-%c, --%s \t%s (default: %s)\n",
00070                  desc->params[i].character,
00071                  desc->params[i].name,
00072                  desc->params[i].short_desc,
00073                  arg_default);
00074     }
00075 }
00076 
00077 static void
00078 jack_print_driver_param_usage (jack_driver_desc_t * desc, unsigned long param, FILE *file)
00079 {
00080     fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
00081              desc->params[param].name, desc->name);
00082     fprintf (file, "%s\n", desc->params[param].long_desc);
00083 }
00084 
00085 EXPORT int
00086 jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr)
00087 {
00088     struct option * long_options;
00089     char * options, * options_ptr;
00090     unsigned long i;
00091     int opt;
00092     unsigned int param_index;
00093     JSList * params = NULL;
00094     jack_driver_param_t * driver_param;
00095 
00096     if (argc <= 1) {
00097         *param_ptr = NULL;
00098         return 0;
00099     }
00100 
00101     /* check for help */
00102     if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
00103         if (argc > 2) {
00104             for (i = 0; i < desc->nparams; i++) {
00105                 if (strcmp (desc->params[i].name, argv[2]) == 0) {
00106                     jack_print_driver_param_usage (desc, i, stdout);
00107                     return 1;
00108                 }
00109             }
00110 
00111             fprintf (stderr, "jackd: unknown option '%s' "
00112                      "for driver '%s'\n", argv[2],
00113                      desc->name);
00114         }
00115 
00116         printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name);
00117         jack_print_driver_options (desc, stdout);
00118         return 1;
00119         }
00120 
00121     /* set up the stuff for getopt */
00122     options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
00123     long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
00124 
00125     options_ptr = options;
00126     for (i = 0; i < desc->nparams; i++) {
00127         sprintf (options_ptr, "%c::", desc->params[i].character);
00128         options_ptr += 3;
00129         long_options[i].name = desc->params[i].name;
00130         long_options[i].flag = NULL;
00131         long_options[i].val = desc->params[i].character;
00132         long_options[i].has_arg = optional_argument;
00133     }
00134 
00135     /* create the params */
00136     optind = 0;
00137     opterr = 0;
00138     while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
00139 
00140         if (opt == ':' || opt == '?') {
00141             if (opt == ':') {
00142                 fprintf (stderr, "Missing option to argument '%c'\n", optopt);
00143             } else {
00144                 fprintf (stderr, "Unknownage with option '%c'\n", optopt);
00145             }
00146 
00147             fprintf (stderr, "Options for driver '%s':\n", desc->name);
00148             jack_print_driver_options (desc, stderr);
00149             exit (1);
00150         }
00151 
00152         for (param_index = 0; param_index < desc->nparams; param_index++) {
00153             if (opt == desc->params[param_index].character) {
00154                 break;
00155             }
00156         }
00157 
00158         driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
00159         driver_param->character = desc->params[param_index].character;
00160 
00161         if (!optarg && optind < argc &&
00162                 strlen(argv[optind]) &&
00163                 argv[optind][0] != '-') {
00164             optarg = argv[optind];
00165         }
00166 
00167         if (optarg) {
00168             switch (desc->params[param_index].type) {
00169                 case JackDriverParamInt:
00170                     driver_param->value.i = atoi (optarg);
00171                     break;
00172                 case JackDriverParamUInt:
00173                     driver_param->value.ui = strtoul (optarg, NULL, 10);
00174                     break;
00175                 case JackDriverParamChar:
00176                     driver_param->value.c = optarg[0];
00177                     break;
00178                 case JackDriverParamString:
00179                     strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
00180                     break;
00181                 case JackDriverParamBool:
00182 
00183                     /*
00184                                 if (strcasecmp ("false", optarg) == 0 ||
00185                                         strcasecmp ("off", optarg) == 0 ||
00186                                         strcasecmp ("no", optarg) == 0 ||
00187                                         strcasecmp ("0", optarg) == 0 ||
00188                                         strcasecmp ("(null)", optarg) == 0 ) {
00189                     */ 
00190                     // steph
00191                     if (strcmp ("false", optarg) == 0 ||
00192                             strcmp ("off", optarg) == 0 ||
00193                             strcmp ("no", optarg) == 0 ||
00194                             strcmp ("0", optarg) == 0 ||
00195                             strcmp ("(null)", optarg) == 0 ) {
00196                         driver_param->value.i = false;
00197 
00198                     } else {
00199 
00200                         driver_param->value.i = true;
00201 
00202                     }
00203                     break;
00204             }
00205         } else {
00206             if (desc->params[param_index].type == JackDriverParamBool) {
00207                 driver_param->value.i = true;
00208             } else {
00209                 driver_param->value = desc->params[param_index].value;
00210             }
00211         }
00212 
00213         params = jack_slist_append (params, driver_param);
00214     }
00215 
00216     free (options);
00217     free (long_options);
00218 
00219     if (param_ptr)
00220         *param_ptr = params;
00221 
00222     return 0;
00223 }
00224 
00225 EXPORT jack_driver_desc_t *
00226 jack_find_driver_descriptor (JSList * drivers, const char * name)
00227 {
00228     jack_driver_desc_t * desc = 0;
00229     JSList * node;
00230 
00231     for (node = drivers; node; node = jack_slist_next (node)) {
00232         desc = (jack_driver_desc_t *) node->data;
00233 
00234         if (strcmp (desc->name, name) != 0) {
00235             desc = NULL;
00236         } else {
00237             break;
00238         }
00239     }
00240 
00241     return desc;
00242 }
00243 
00244 jack_driver_desc_t *
00245 jack_drivers_get_descriptor (JSList * drivers, const char * sofile)
00246 {
00247     jack_driver_desc_t * descriptor, * other_descriptor;
00248     JackDriverDescFunction so_get_descriptor = NULL;
00249     JSList * node;
00250     void * dlhandle;
00251     char * filename;
00252 #ifdef WIN32
00253     int dlerr;
00254 #else
00255     const char * dlerr;
00256 #endif
00257 
00258     int err;
00259         /*
00260         char* driver_dir;
00261     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00262                 driver_dir = ADDON_DIR;
00263     }
00264         */
00265   
00266 #ifdef WIN32
00267         char* driver_dir = ADDON_DIR;
00268     if (strcmp(ADDON_DIR, "") == 0) {
00269         char temp_driver_dir1[512];
00270         char temp_driver_dir2[512];
00271         GetCurrentDirectory(512, temp_driver_dir1);
00272         sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
00273         driver_dir = temp_driver_dir2;
00274     }
00275 #else
00276         char driver_dir[512];
00277         snprintf(driver_dir,  sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
00278 #endif
00279 
00280     filename = (char *)malloc(strlen (driver_dir) + 1 + strlen(sofile) + 1);
00281     sprintf (filename, "%s/%s", driver_dir, sofile);
00282 
00283     if ((dlhandle = LoadDriverModule(filename)) == NULL) {
00284 #ifdef WIN32
00285         jack_error ("could not open driver .dll '%s': %ld\n", filename, GetLastError());
00286 #else
00287         jack_error ("could not open driver .so '%s': %s\n", filename, dlerror());
00288 #endif
00289 
00290         free(filename);
00291         return NULL;
00292     }
00293 
00294     so_get_descriptor = (JackDriverDescFunction)
00295                         GetProc(dlhandle, "driver_get_descriptor");
00296 
00297 #ifdef WIN32
00298     if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
00299         fprintf(stderr, "%ld\n", dlerr);
00300 #else
00301     if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
00302         fprintf(stderr, "%s\n", dlerr);
00303 #endif
00304 
00305         UnloadDriverModule(dlhandle);
00306         free(filename);
00307         return NULL;
00308     }
00309 
00310     if ((descriptor = so_get_descriptor ()) == NULL) {
00311         jack_error("driver from '%s' returned NULL descriptor\n", filename);
00312         UnloadDriverModule(dlhandle);
00313         free(filename);
00314         return NULL;
00315     }
00316 
00317 #ifdef WIN32
00318     if ((err = UnloadDriverModule(dlhandle)) == 0) {
00319         jack_error ("error closing driver .so '%s': %ld\n", filename, GetLastError ());
00320     }
00321 #else
00322     if ((err = UnloadDriverModule(dlhandle)) != 0) {
00323         jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ());
00324     }
00325 #endif
00326 
00327     /* check it doesn't exist already */
00328     for (node = drivers; node; node = jack_slist_next (node)) {
00329         other_descriptor = (jack_driver_desc_t *) node->data;
00330 
00331         if (strcmp(descriptor->name, other_descriptor->name) == 0) {
00332             jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first\n",
00333                         other_descriptor->file, filename, other_descriptor->name);
00334             /* FIXME: delete the descriptor */
00335             free(filename);
00336             return NULL;
00337         }
00338     }
00339 
00340     strncpy(descriptor->file, filename, PATH_MAX);
00341     free(filename);
00342     return descriptor;
00343 }
00344 
00345 #ifdef WIN32
00346 
00347 EXPORT JSList *
00348 jack_drivers_load (JSList * drivers) {
00349     char driver_dir[512];
00350     char dll_filename[512];
00351     WIN32_FIND_DATA filedata;
00352     HANDLE file;
00353     const char * ptr = NULL;
00354     JSList * driver_list = NULL;
00355     jack_driver_desc_t * desc;
00356 
00357     GetCurrentDirectory(512, driver_dir);
00358 
00359     sprintf(dll_filename, "%s/%s", ADDON_DIR, "*.dll");
00360     file = (HANDLE )FindFirstFile(dll_filename, &filedata);
00361 
00362     if (file == INVALID_HANDLE_VALUE) {
00363         printf("error\n");
00364         return NULL;
00365     }
00366 
00367     do {
00368         ptr = strrchr (filedata.cFileName, '.');
00369         if (!ptr) {
00370             continue;
00371         }
00372         ptr++;
00373         if (strncmp ("dll", ptr, 3) != 0) {
00374             continue;
00375         }
00376 
00377         desc = jack_drivers_get_descriptor (drivers, filedata.cFileName);
00378         if (desc) {
00379             driver_list = jack_slist_append (driver_list, desc);
00380         }
00381 
00382     } while (FindNextFile(file, &filedata));
00383 
00384     if (!driver_list) {
00385         jack_error ("could not find any drivers in %s!\n", driver_dir);
00386         return NULL;
00387     }
00388 
00389     return driver_list;
00390 }
00391 
00392 #else
00393 
00394 JSList *
00395 jack_drivers_load (JSList * drivers) {
00396     struct dirent * dir_entry;
00397     DIR * dir_stream;
00398     const char * ptr;
00399     int err;
00400     JSList * driver_list = NULL;
00401     jack_driver_desc_t * desc;
00402 
00403         /*
00404         char* driver_dir;
00405     if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
00406         driver_dir = ADDON_DIR;
00407         }
00408         */
00409         char driver_dir[512];
00410         snprintf(driver_dir,  sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
00411         
00412     /* search through the driver_dir and add get descriptors
00413     from the .so files in it */
00414     dir_stream = opendir (driver_dir);
00415     if (!dir_stream) {
00416         jack_error ("could not open driver directory %s: %s\n",
00417                     driver_dir, strerror (errno));
00418         return NULL;
00419     }
00420 
00421     while ((dir_entry = readdir(dir_stream))) {
00422 
00423         /* check the filename is of the right format */
00424         if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
00425             continue;
00426         }
00427 
00428         ptr = strrchr (dir_entry->d_name, '.');
00429         if (!ptr) {
00430             continue;
00431         }
00432         ptr++;
00433         if (strncmp ("so", ptr, 2) != 0) {
00434             continue;
00435         }
00436 
00437         desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name);
00438         if (desc) {
00439             driver_list = jack_slist_append (driver_list, desc);
00440         }
00441     }
00442 
00443     err = closedir (dir_stream);
00444     if (err) {
00445         jack_error ("error closing driver directory %s: %s\n",
00446                     driver_dir, strerror (errno));
00447     }
00448 
00449     if (!driver_list) {
00450         jack_error ("could not find any drivers in %s!\n", driver_dir);
00451         return NULL;
00452     }
00453 
00454     return driver_list;
00455 }
00456 
00457 #endif
00458 
00459 jack_driver_info_t *
00460 jack_load_driver (jack_driver_desc_t * driver_desc) {
00461 #ifdef WIN32
00462     int errstr;
00463 #else
00464     const char * errstr;
00465 #endif
00466 
00467     jack_driver_info_t *info;
00468 
00469     info = (jack_driver_info_t *) calloc (1, sizeof (*info));
00470     info->handle = LoadDriverModule (driver_desc->file);
00471 
00472     if (info->handle == NULL) {
00473 #ifdef WIN32
00474         if ((errstr = GetLastError ()) != 0) {
00475             jack_error ("can't load \"%s\": %ld", driver_desc->file,
00476                         errstr);
00477 #else
00478         if ((errstr = dlerror ()) != 0) {
00479             jack_error ("can't load \"%s\": %s", driver_desc->file,
00480                         errstr);
00481 #endif
00482 
00483         } else {
00484             jack_error ("bizarre error loading driver shared "
00485                         "object %s", driver_desc->file);
00486         }
00487         goto fail;
00488     }
00489 
00490     info->initialize = (initialize)GetProc(info->handle, "driver_initialize");
00491 
00492 #ifdef WIN32
00493     if ((info->initialize == NULL) && (errstr = GetLastError ()) != 0) {
00494 #else
00495     if ((info->initialize == NULL) && (errstr = dlerror ()) != 0) {
00496 #endif
00497         jack_error ("no initialize function in shared object %s\n",
00498                     driver_desc->file);
00499         goto fail;
00500     }
00501 
00502     return info;
00503 
00504 fail:
00505     if (info->handle) {
00506         UnloadDriverModule(info->handle);
00507     }
00508     free (info);
00509     return NULL;
00510 }
00511 

Generated on Thu Feb 14 11:16:01 2008 for Jackdmp by  doxygen 1.5.1