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