Jack2  1.9.8
JackDriverLoader.cpp
1 /*
2 Copyright (C) 2001-2005 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include "JackSystemDeps.h"
22 #include "JackDriverLoader.h"
23 #include "JackConstants.h"
24 #include "JackError.h"
25 #include <getopt.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 
30 #ifndef WIN32
31 #include <dirent.h>
32 #endif
33 
34 jack_driver_desc_t* jackctl_driver_get_desc(jackctl_driver_t * driver);
35 
36 SERVER_EXPORT void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file)
37 {
38  unsigned long i;
39  char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
40 
41  for (i = 0; i < desc->nparams; i++) {
42  switch (desc->params[i].type) {
43  case JackDriverParamInt:
44  sprintf (arg_default, "%" "i", desc->params[i].value.i);
45  break;
46  case JackDriverParamUInt:
47  sprintf (arg_default, "%" "u", desc->params[i].value.ui);
48  break;
49  case JackDriverParamChar:
50  sprintf (arg_default, "%c", desc->params[i].value.c);
51  break;
52  case JackDriverParamString:
53  if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0) {
54  sprintf (arg_default, "%s", desc->params[i].value.str);
55  } else {
56  sprintf (arg_default, "none");
57  }
58  break;
59  case JackDriverParamBool:
60  sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
61  break;
62  }
63 
64  fprintf(file, "\t-%c, --%s \t%s (default: %s)\n",
65  desc->params[i].character,
66  desc->params[i].name,
67  desc->params[i].long_desc,
68  arg_default);
69  }
70 }
71 
72 static void
73 jack_print_driver_param_usage (jack_driver_desc_t* desc, unsigned long param, FILE *file)
74 {
75  fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
76  desc->params[param].name, desc->name);
77  fprintf (file, "%s\n", desc->params[param].long_desc);
78 }
79 
80 SERVER_EXPORT void jack_free_driver_params(JSList * driver_params)
81 {
82  JSList*node_ptr = driver_params;
83  JSList*next_node_ptr;
84 
85  while (node_ptr) {
86  next_node_ptr = node_ptr->next;
87  free(node_ptr->data);
88  free(node_ptr);
89  node_ptr = next_node_ptr;
90  }
91 }
92 
93 SERVER_EXPORT int
94 jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSList** param_ptr)
95 {
96  struct option * long_options;
97  char* options, * options_ptr;
98  unsigned long i;
99  int opt;
100  unsigned int param_index;
101  JSList* params = NULL;
102  jack_driver_param_t * driver_param;
103 
104  if (argc <= 1) {
105  *param_ptr = NULL;
106  return 0;
107  }
108 
109  /* check for help */
110  if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
111  if (argc > 2) {
112  for (i = 0; i < desc->nparams; i++) {
113  if (strcmp (desc->params[i].name, argv[2]) == 0) {
114  jack_print_driver_param_usage (desc, i, stdout);
115  return 1;
116  }
117  }
118 
119  fprintf (stderr, "jackd: unknown option '%s' "
120  "for driver '%s'\n", argv[2],
121  desc->name);
122  }
123 
124  jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
125  jack_print_driver_options (desc, stdout);
126  return 1;
127  }
128 
129  /* set up the stuff for getopt */
130  options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
131  long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
132 
133  options_ptr = options;
134  for (i = 0; i < desc->nparams; i++) {
135  sprintf (options_ptr, "%c::", desc->params[i].character);
136  options_ptr += 3;
137  long_options[i].name = desc->params[i].name;
138  long_options[i].flag = NULL;
139  long_options[i].val = desc->params[i].character;
140  long_options[i].has_arg = optional_argument;
141  }
142 
143  /* create the params */
144  optind = 0;
145  opterr = 0;
146  while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
147 
148  if (opt == ':' || opt == '?') {
149  if (opt == ':') {
150  fprintf (stderr, "Missing option to argument '%c'\n", optopt);
151  } else {
152  fprintf (stderr, "Unknownage with option '%c'\n", optopt);
153  }
154 
155  fprintf (stderr, "Options for driver '%s':\n", desc->name);
156  jack_print_driver_options (desc, stderr);
157  return 1;
158  }
159 
160  for (param_index = 0; param_index < desc->nparams; param_index++) {
161  if (opt == desc->params[param_index].character) {
162  break;
163  }
164  }
165 
166  driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
167  driver_param->character = desc->params[param_index].character;
168 
169  if (!optarg && optind < argc &&
170  strlen(argv[optind]) &&
171  argv[optind][0] != '-') {
172  optarg = argv[optind];
173  }
174 
175  if (optarg) {
176  switch (desc->params[param_index].type) {
177  case JackDriverParamInt:
178  driver_param->value.i = atoi(optarg);
179  break;
180  case JackDriverParamUInt:
181  driver_param->value.ui = strtoul(optarg, NULL, 10);
182  break;
183  case JackDriverParamChar:
184  driver_param->value.c = optarg[0];
185  break;
186  case JackDriverParamString:
187  strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
188  break;
189  case JackDriverParamBool:
190  if (strcasecmp("false", optarg) == 0 ||
191  strcasecmp("off", optarg) == 0 ||
192  strcasecmp("no", optarg) == 0 ||
193  strcasecmp("0", optarg) == 0 ||
194  strcasecmp("(null)", optarg) == 0 ) {
195  driver_param->value.i = false;
196  } else {
197  driver_param->value.i = true;
198  }
199  break;
200  }
201  } else {
202  if (desc->params[param_index].type == JackDriverParamBool) {
203  driver_param->value.i = true;
204  } else {
205  driver_param->value = desc->params[param_index].value;
206  }
207  }
208 
209  params = jack_slist_append (params, driver_param);
210  }
211 
212  free (options);
213  free (long_options);
214 
215  if (param_ptr) {
216  *param_ptr = params;
217  }
218  return 0;
219 }
220 
221 SERVER_EXPORT int
222 jackctl_parse_driver_params(jackctl_driver *driver_ptr, int argc, char* argv[])
223 {
224  struct option* long_options;
225  char* options, * options_ptr;
226  unsigned long i;
227  int opt;
228  JSList* node_ptr;
229  jackctl_parameter_t * param = NULL;
230  union jackctl_parameter_value value;
231 
232  if (argc <= 1) {
233  return 0;
234  }
235 
236  const JSList* driver_params = jackctl_driver_get_parameters(driver_ptr);
237  if (driver_params == NULL) {
238  return 1;
239  }
240 
241  jack_driver_desc_t* desc = jackctl_driver_get_desc(driver_ptr);
242 
243  /* check for help */
244  if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
245  if (argc > 2) {
246  for (i = 0; i < desc->nparams; i++) {
247  if (strcmp (desc->params[i].name, argv[2]) == 0) {
248  jack_print_driver_param_usage (desc, i, stdout);
249  return 1;
250  }
251  }
252 
253  fprintf (stderr, "jackd: unknown option '%s' "
254  "for driver '%s'\n", argv[2],
255  desc->name);
256  }
257 
258  jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
259  jack_print_driver_options (desc, stdout);
260  return 1;
261  }
262 
263  /* set up the stuff for getopt */
264  options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
265  long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
266 
267  options_ptr = options;
268  for (i = 0; i < desc->nparams; i++) {
269  sprintf(options_ptr, "%c::", desc->params[i].character);
270  options_ptr += 3;
271  long_options[i].name = desc->params[i].name;
272  long_options[i].flag = NULL;
273  long_options[i].val = desc->params[i].character;
274  long_options[i].has_arg = optional_argument;
275  }
276 
277  /* create the params */
278  optind = 0;
279  opterr = 0;
280  while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
281 
282  if (opt == ':' || opt == '?') {
283  if (opt == ':') {
284  fprintf (stderr, "Missing option to argument '%c'\n", optopt);
285  } else {
286  fprintf (stderr, "Unknownage with option '%c'\n", optopt);
287  }
288 
289  fprintf (stderr, "Options for driver '%s':\n", desc->name);
290  jack_print_driver_options(desc, stderr);
291  return 1;
292  }
293 
294  node_ptr = (JSList *)driver_params;
295  while (node_ptr) {
296  param = (jackctl_parameter_t*)node_ptr->data;
297  if (opt == jackctl_parameter_get_id(param)) {
298  break;
299  }
300  node_ptr = node_ptr->next;
301  }
302 
303  if (!optarg && optind < argc &&
304  strlen(argv[optind]) &&
305  argv[optind][0] != '-') {
306  optarg = argv[optind];
307  }
308 
309  if (optarg) {
310  switch (jackctl_parameter_get_type(param)) {
311  case JackDriverParamInt:
312  value.i = atoi(optarg);
313  jackctl_parameter_set_value(param, &value);
314  break;
315  case JackDriverParamUInt:
316  value.ui = strtoul(optarg, NULL, 10);
317  jackctl_parameter_set_value(param, &value);
318  break;
319  case JackDriverParamChar:
320  value.c = optarg[0];
321  jackctl_parameter_set_value(param, &value);
322  break;
323  case JackDriverParamString:
324  strncpy(value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
325  jackctl_parameter_set_value(param, &value);
326  break;
327  case JackDriverParamBool:
328  if (strcasecmp("false", optarg) == 0 ||
329  strcasecmp("off", optarg) == 0 ||
330  strcasecmp("no", optarg) == 0 ||
331  strcasecmp("0", optarg) == 0 ||
332  strcasecmp("(null)", optarg) == 0 ) {
333  value.i = false;
334  } else {
335  value.i = true;
336  }
337  jackctl_parameter_set_value(param, &value);
338  break;
339  }
340  } else {
342  value.i = true;
343  } else {
345  }
346  jackctl_parameter_set_value(param, &value);
347  }
348  }
349 
350  free(options);
351  free(long_options);
352  return 0;
353 }
354 
356 jack_find_driver_descriptor (JSList * drivers, const char* name)
357 {
358  jack_driver_desc_t* desc = 0;
359  JSList* node;
360 
361  for (node = drivers; node; node = jack_slist_next (node)) {
362  desc = (jack_driver_desc_t*) node->data;
363 
364  if (strcmp (desc->name, name) != 0) {
365  desc = NULL;
366  } else {
367  break;
368  }
369  }
370 
371  return desc;
372 }
373 
374 static jack_driver_desc_t*
375 jack_get_descriptor (JSList * drivers, const char* sofile, const char* symbol)
376 {
377  jack_driver_desc_t* descriptor, * other_descriptor;
378  JackDriverDescFunction so_get_descriptor = NULL;
379  JSList* node;
380  void * dlhandle;
381  char* filename;
382 #ifdef WIN32
383  int dlerr;
384 #else
385  const char* dlerr;
386 #endif
387 
388  int err;
389  const char* driver_dir;
390 
391  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
392  // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
393  // for posix systems, it is absolute path of default driver dir
394 #ifdef WIN32
395  char temp_driver_dir1[512];
396  char temp_driver_dir2[512];
397  if (3 < GetModuleFileName(NULL, temp_driver_dir1, 512)) {
398  char *p = strrchr(temp_driver_dir1, '\\');
399  if (p && (p != temp_driver_dir1))
400  *p = 0;
401  else
402  GetCurrentDirectory(512, temp_driver_dir1);
403  } else {
404  GetCurrentDirectory(512, temp_driver_dir1);
405  }
406  sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
407  driver_dir = temp_driver_dir2;
408 #else
409  driver_dir = ADDON_DIR;
410 #endif
411  }
412 
413  int len = strlen(driver_dir) + 1 + strlen(sofile) + 1;
414  filename = (char*)malloc(len);
415  snprintf(filename, len, "%s/%s", driver_dir, sofile);
416 
417  if ((dlhandle = LoadDriverModule(filename)) == NULL) {
418 #ifdef WIN32
419  jack_error ("could not open driver .dll '%s': %ld", filename, GetLastError());
420 #else
421  jack_error ("could not open driver .so '%s': %s", filename, dlerror());
422 #endif
423 
424  free(filename);
425  return NULL;
426  }
427 
428  so_get_descriptor = (JackDriverDescFunction)GetDriverProc(dlhandle, symbol);
429 
430 #ifdef WIN32
431  if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
432  jack_error("jack_get_descriptor : dll is not a driver, err = %ld", dlerr);
433 #else
434  if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
435  jack_error("jack_get_descriptor err = %s", dlerr);
436 #endif
437 
438  UnloadDriverModule(dlhandle);
439  free(filename);
440  return NULL;
441  }
442 
443  if ((descriptor = so_get_descriptor ()) == NULL) {
444  jack_error("driver from '%s' returned NULL descriptor", filename);
445  UnloadDriverModule(dlhandle);
446  free(filename);
447  return NULL;
448  }
449 
450 #ifdef WIN32
451  if ((err = UnloadDriverModule(dlhandle)) == 0) {
452  jack_error ("error closing driver .so '%s': %ld", filename, GetLastError ());
453  }
454 #else
455  if ((err = UnloadDriverModule(dlhandle)) != 0) {
456  jack_error ("error closing driver .so '%s': %s", filename, dlerror ());
457  }
458 #endif
459 
460  /* check it doesn't exist already */
461  for (node = drivers; node; node = jack_slist_next (node)) {
462  other_descriptor = (jack_driver_desc_t*) node->data;
463 
464  if (strcmp(descriptor->name, other_descriptor->name) == 0) {
465  jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first",
466  other_descriptor->file, filename, other_descriptor->name);
467  /* FIXME: delete the descriptor */
468  free(filename);
469  return NULL;
470  }
471  }
472 
473  strncpy(descriptor->file, filename, JACK_PATH_MAX);
474  free(filename);
475  return descriptor;
476 }
477 
478 static bool check_symbol(const char* sofile, const char* symbol)
479 {
480  void * dlhandle;
481  bool res = false;
482  const char* driver_dir;
483 
484  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
485  // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
486  // for posix systems, it is absolute path of default driver dir
487 #ifdef WIN32
488  char temp_driver_dir1[512];
489  char temp_driver_dir2[512];
490  if (3 < GetModuleFileName(NULL, temp_driver_dir1, 512)) {
491  char *p = strrchr(temp_driver_dir1, '\\');
492  if (p && (p != temp_driver_dir1))
493  *p = 0;
494  else
495  GetCurrentDirectory(512, temp_driver_dir1);
496  } else {
497  GetCurrentDirectory(512, temp_driver_dir1);
498  }
499  snprintf(temp_driver_dir2, sizeof(temp_driver_dir2), "%s/%s", temp_driver_dir1, ADDON_DIR);
500  driver_dir = temp_driver_dir2;
501 #else
502  driver_dir = ADDON_DIR;
503 #endif
504  }
505 
506  int len = strlen(driver_dir) + 1 + strlen(sofile) + 1;
507  char* filename = (char*)malloc(len);
508  snprintf(filename, len, "%s/%s", driver_dir, sofile);
509 
510  if ((dlhandle = LoadDriverModule(filename)) == NULL) {
511 #ifdef WIN32
512  jack_error ("could not open component .dll '%s': %ld", filename, GetLastError());
513 #else
514  jack_error ("could not open component .so '%s': %s", filename, dlerror());
515 #endif
516  } else {
517  res = (GetDriverProc(dlhandle, symbol)) ? true : false;
518  UnloadDriverModule(dlhandle);
519  }
520 
521  free(filename);
522  return res;
523 }
524 
525 #ifdef WIN32
526 
527 JSList *
528 jack_drivers_load (JSList * drivers) {
529  char* driver_dir;
530  char driver_dir_storage[512];
531  char dll_filename[512];
532  WIN32_FIND_DATA filedata;
533  HANDLE file;
534  const char* ptr = NULL;
535  JSList* driver_list = NULL;
536  jack_driver_desc_t* desc = NULL;
537 
538  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
539  // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
540  if (3 < GetModuleFileName(NULL, driver_dir_storage, 512)) {
541  char *p = strrchr(driver_dir_storage, '\\');
542  if (p && (p != driver_dir_storage))
543  *p = 0;
544  else
545  GetCurrentDirectory(512, driver_dir_storage);
546  } else {
547  GetCurrentDirectory(512, driver_dir_storage);
548  }
549  strcat(driver_dir_storage, "/");
550  strcat(driver_dir_storage, ADDON_DIR);
551  driver_dir = driver_dir_storage;
552  }
553 
554  snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir);
555 
556  file = (HANDLE )FindFirstFile(dll_filename, &filedata);
557 
558  if (file == INVALID_HANDLE_VALUE) {
559  jack_error("error invalid handle");
560  return NULL;
561  }
562 
563  do {
564  /* check the filename is of the right format */
565  if (strncmp ("jack_", filedata.cFileName, 5) != 0) {
566  continue;
567  }
568 
569  ptr = strrchr (filedata.cFileName, '.');
570  if (!ptr) {
571  continue;
572  }
573  ptr++;
574  if (strncmp ("dll", ptr, 3) != 0) {
575  continue;
576  }
577 
578  /* check if dll is an internal client */
579  if (check_symbol(filedata.cFileName, "jack_internal_initialize")) {
580  continue;
581  }
582 
583  desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor");
584  if (desc) {
585  driver_list = jack_slist_append (driver_list, desc);
586  } else {
587  jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
588  }
589 
590  } while (FindNextFile(file, &filedata));
591 
592  if (!driver_list) {
593  jack_error ("could not find any drivers in %s!", driver_dir);
594  return NULL;
595  }
596 
597  return driver_list;
598 }
599 
600 #else
601 
602 JSList *
603 jack_drivers_load (JSList * drivers) {
604  struct dirent * dir_entry;
605  DIR * dir_stream;
606  const char* ptr;
607  int err;
608  JSList* driver_list = NULL;
609  jack_driver_desc_t* desc = NULL;
610 
611  const char* driver_dir;
612  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
613  driver_dir = ADDON_DIR;
614  }
615 
616  /* search through the driver_dir and add get descriptors
617  from the .so files in it */
618  dir_stream = opendir (driver_dir);
619  if (!dir_stream) {
620  jack_error ("could not open driver directory %s: %s",
621  driver_dir, strerror (errno));
622  return NULL;
623  }
624 
625  while ((dir_entry = readdir(dir_stream))) {
626 
627  /* check the filename is of the right format */
628  if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
629  continue;
630  }
631 
632  ptr = strrchr (dir_entry->d_name, '.');
633  if (!ptr) {
634  continue;
635  }
636  ptr++;
637  if (strncmp ("so", ptr, 2) != 0) {
638  continue;
639  }
640 
641  /* check if dll is an internal client */
642  if (check_symbol(dir_entry->d_name, "jack_internal_initialize")) {
643  continue;
644  }
645 
646  desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor");
647  if (desc) {
648  driver_list = jack_slist_append (driver_list, desc);
649  } else {
650  jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
651  }
652  }
653 
654  err = closedir (dir_stream);
655  if (err) {
656  jack_error ("error closing driver directory %s: %s",
657  driver_dir, strerror (errno));
658  }
659 
660  if (!driver_list) {
661  jack_error ("could not find any drivers in %s!", driver_dir);
662  return NULL;
663  }
664 
665  return driver_list;
666 }
667 
668 #endif
669 
670 #ifdef WIN32
671 
672 JSList *
673 jack_internals_load (JSList * internals) {
674  char* driver_dir;
675  char driver_dir_storage[512];
676  char dll_filename[512];
677  WIN32_FIND_DATA filedata;
678  HANDLE file;
679  const char* ptr = NULL;
680  JSList* driver_list = NULL;
681  jack_driver_desc_t* desc;
682 
683  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
684  // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
685  if (3 < GetModuleFileName(NULL, driver_dir_storage, 512)) {
686  char *p = strrchr(driver_dir_storage, '\\');
687  if (p && (p != driver_dir_storage))
688  *p = 0;
689  else
690  GetCurrentDirectory(512, driver_dir_storage);
691  } else {
692  GetCurrentDirectory(512, driver_dir_storage);
693  }
694  strcat(driver_dir_storage, "/");
695  strcat(driver_dir_storage, ADDON_DIR);
696  driver_dir = driver_dir_storage;
697  }
698 
699  snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir);
700 
701  file = (HANDLE )FindFirstFile(dll_filename, &filedata);
702 
703  if (file == INVALID_HANDLE_VALUE) {
704  jack_error("could not open driver directory %s", driver_dir);
705  return NULL;
706  }
707 
708  do {
709 
710  ptr = strrchr (filedata.cFileName, '.');
711  if (!ptr) {
712  continue;
713  }
714  ptr++;
715  if (strncmp ("dll", ptr, 3) != 0) {
716  continue;
717  }
718 
719  /* check if dll is an internal client */
720  if (!check_symbol(filedata.cFileName, "jack_internal_initialize")) {
721  continue;
722  }
723 
724  desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor");
725  if (desc) {
726  driver_list = jack_slist_append (driver_list, desc);
727  } else {
728  jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
729  }
730 
731  } while (FindNextFile(file, &filedata));
732 
733  if (!driver_list) {
734  jack_error ("could not find any internals in %s!", driver_dir);
735  return NULL;
736  }
737 
738  return driver_list;
739 }
740 
741 #else
742 
743 JSList *
744 jack_internals_load (JSList * internals) {
745  struct dirent * dir_entry;
746  DIR * dir_stream;
747  const char* ptr;
748  int err;
749  JSList* driver_list = NULL;
750  jack_driver_desc_t* desc;
751 
752  const char* driver_dir;
753  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
754  driver_dir = ADDON_DIR;
755  }
756 
757  /* search through the driver_dir and add get descriptors
758  from the .so files in it */
759  dir_stream = opendir (driver_dir);
760  if (!dir_stream) {
761  jack_error ("could not open driver directory %s: %s\n",
762  driver_dir, strerror (errno));
763  return NULL;
764  }
765 
766  while ((dir_entry = readdir(dir_stream))) {
767 
768  ptr = strrchr (dir_entry->d_name, '.');
769  if (!ptr) {
770  continue;
771  }
772  ptr++;
773  if (strncmp ("so", ptr, 2) != 0) {
774  continue;
775  }
776 
777  /* check if dll is an internal client */
778  if (!check_symbol(dir_entry->d_name, "jack_internal_initialize")) {
779  continue;
780  }
781 
782  desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor");
783  if (desc) {
784  driver_list = jack_slist_append (driver_list, desc);
785  } else {
786  jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
787  }
788  }
789 
790  err = closedir (dir_stream);
791  if (err) {
792  jack_error ("error closing internal directory %s: %s\n",
793  driver_dir, strerror (errno));
794  }
795 
796  if (!driver_list) {
797  jack_error ("could not find any internals in %s!", driver_dir);
798  return NULL;
799  }
800 
801  return driver_list;
802 }
803 
804 #endif
805 
806 Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc,
807  Jack::JackLockedEngine* engine,
808  Jack::JackSynchro* synchro,
809  const JSList* params)
810 {
811 #ifdef WIN32
812  int errstr;
813 #else
814  const char* errstr;
815 #endif
816 
817  fHandle = LoadDriverModule (driver_desc->file);
818 
819  if (fHandle == NULL) {
820 #ifdef WIN32
821  if ((errstr = GetLastError ()) != 0) {
822  jack_error ("can't load \"%s\": %ld", driver_desc->file, errstr);
823 #else
824  if ((errstr = dlerror ()) != 0) {
825  jack_error ("can't load \"%s\": %s", driver_desc->file, errstr);
826 #endif
827 
828  } else {
829  jack_error ("bizarre error loading driver shared object %s", driver_desc->file);
830  }
831  return NULL;
832  }
833 
834  fInitialize = (driverInitialize)GetDriverProc(fHandle, "driver_initialize");
835 
836 #ifdef WIN32
837  if ((fInitialize == NULL) && (errstr = GetLastError ()) != 0) {
838 #else
839  if ((fInitialize == NULL) && (errstr = dlerror ()) != 0) {
840 #endif
841  jack_error("no initialize function in shared object %s\n", driver_desc->file);
842  return NULL;
843  }
844 
845  fBackend = fInitialize(engine, synchro, params);
846  return fBackend;
847 }
848 
849 JackDriverInfo::~JackDriverInfo()
850 {
851  delete fBackend;
852  if (fHandle)
853  UnloadDriverModule(fHandle);
854 }
855 
856 SERVER_EXPORT
858 jack_driver_descriptor_construct(
859  const char * name,
860  jack_driver_type_t type,
861  const char * description,
862  jack_driver_desc_filler_t * filler_ptr)
863 {
864  size_t name_len;
865  size_t description_len;
866  jack_driver_desc_t* desc_ptr;
867 
868  name_len = strlen(name);
869  description_len = strlen(description);
870 
871  if (name_len > sizeof(desc_ptr->name) - 1 ||
872  description_len > sizeof(desc_ptr->desc) - 1) {
873  assert(false);
874  return 0;
875  }
876 
877  desc_ptr = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
878  if (desc_ptr == NULL) {
879  jack_error("calloc() failed to allocate memory for driver descriptor struct");
880  return 0;
881  }
882 
883  memcpy(desc_ptr->name, name, name_len + 1);
884  memcpy(desc_ptr->desc, description, description_len + 1);
885 
886  desc_ptr->nparams = 0;
887  desc_ptr->type = type;
888 
889  if (filler_ptr != NULL) {
890  filler_ptr->size = 0;
891  }
892 
893  return desc_ptr;
894 }
895 
896 SERVER_EXPORT
897 int
898 jack_driver_descriptor_add_parameter(
899  jack_driver_desc_t* desc_ptr,
900  jack_driver_desc_filler_t * filler_ptr,
901  const char* name,
902  char character,
903  jack_driver_param_type_t type,
904  const jack_driver_param_value_t * value_ptr,
906  const char* short_desc,
907  const char* long_desc)
908 {
909  size_t name_len;
910  size_t short_desc_len;
911  size_t long_desc_len;
912  jack_driver_param_desc_t * param_ptr;
913  size_t newsize;
914 
915  name_len = strlen(name);
916  short_desc_len = strlen(short_desc);
917 
918  if (long_desc != NULL) {
919  long_desc_len = strlen(long_desc);
920  } else {
921  long_desc = short_desc;
922  long_desc_len = short_desc_len;
923  }
924 
925  if (name_len > sizeof(param_ptr->name) - 1 ||
926  short_desc_len > sizeof(param_ptr->short_desc) - 1 ||
927  long_desc_len > sizeof(param_ptr->long_desc) - 1) {
928  assert(false);
929  return 0;
930  }
931 
932  if (desc_ptr->nparams == filler_ptr->size) {
933  newsize = filler_ptr->size + 20; // most drivers have less than 20 parameters
934  param_ptr = (jack_driver_param_desc_t*)realloc (desc_ptr->params, newsize * sizeof (jack_driver_param_desc_t));
935  if (param_ptr == NULL) {
936  jack_error("realloc() failed for parameter array of %zu elements", newsize);
937  return false;
938  }
939  filler_ptr->size = newsize;
940  desc_ptr->params = param_ptr;
941  }
942 
943  assert(desc_ptr->nparams < filler_ptr->size);
944  param_ptr = desc_ptr->params + desc_ptr->nparams;
945 
946  memcpy(param_ptr->name, name, name_len + 1);
947  param_ptr->character = character;
948  param_ptr->type = type;
949  param_ptr->value = *value_ptr;
950  param_ptr->constraint = constraint;
951  memcpy(param_ptr->short_desc, short_desc, short_desc_len + 1);
952  memcpy(param_ptr->long_desc, long_desc, long_desc_len + 1);
953 
954  desc_ptr->nparams++;
955 
956  return true;
957 }