source: roaraudio/libroaross/libroaross.c @ 4077:5da81888d777

Last change on this file since 4077:5da81888d777 was 4077:5da81888d777, checked in by phi, 14 years ago

killed a segfault in case of ioctl() on fh=-1

File size: 53.1 KB
Line 
1//libroaross.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "roaraudio.h"
37#include "libroarlight/libroarlight.h"
38
39#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
40#if defined(__OpenBSD__) || defined(__NetBSD__)
41#include <soundcard.h>
42#else
43#include <sys/soundcard.h>
44#endif
45#include <sys/ioctl.h>
46
47#ifdef ROAR_HAVE_H_SYS_TYPES
48#include <sys/types.h>
49#endif
50
51#ifdef ROAR_HAVE_H_FCNTL
52#include <fcntl.h>
53#endif
54
55#ifdef ROAR_HAVE_H_UNISTD
56#include <unistd.h>
57#endif
58
59#include <sys/stat.h>
60#include <dlfcn.h>
61#include <stdarg.h>
62
63#if defined(RTLD_NEXT)
64#define REAL_LIBC RTLD_NEXT
65#else
66#define REAL_LIBC ((void *) -1L)
67#endif
68
69#ifndef ENOTSUP
70#define ENOTSUP ENOSYS
71#endif
72
73#ifndef O_DIRECTORY
74#define O_DIRECTORY 0
75#endif
76
77#ifndef O_DIRECT
78#define O_DIRECT 0
79#endif
80
81#ifndef O_LARGEFILE
82#define O_LARGEFILE 0
83#endif
84
85#ifndef O_NOATIME
86#define O_NOATIME 0
87#endif
88
89#define _O_PARA_DIR (O_RDONLY|O_WRONLY|O_RDWR)
90#define _O_PARA_IGN (O_DIRECT|O_APPEND|O_LARGEFILE|O_NOATIME|O_NOCTTY|O_TRUNC)
91
92#if defined(ROAR_OS_NETBSD) && defined(ioctl)
93#define IOCTL_IS_ALIAS
94#endif
95
96#ifdef ROAR_OS_FREEBSD
97#define _VA_ARGS_MODE_T int
98#else
99#define _VA_ARGS_MODE_T mode_t
100#endif
101
102#ifdef ROAR_OS_FREEBSD
103#define _CREAT_ARG_PATHNAME path
104#else
105#define _CREAT_ARG_PATHNAME pathname
106#endif
107
108#ifdef ROAR_OS_NETBSD
109#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
110#define map_args int __fd = fd; unsigned long int __request = com
111#elif defined(ROAR_TARGET_CYGWIN)
112#define IOCTL() int ioctl (int __fd, int __cmd, ...)
113#define map_args unsigned long int __request = __cmd; void * argp
114#define va_argp
115#define ioctl_lastarg __cmd
116#else
117#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
118#define map_args void * argp
119#define va_argp
120#define ioctl_lastarg __request
121#endif
122
123#define OSS_VOLUME_SCALE 100
124
125#define _MAX_POINTER  8
126
127// handle type:
128#define HT_NONE       0 /* Unused object */
129#define HT_STREAM     1 /* Stream with no specal handling needed */
130#define HT_MIXER      2 /* Mixer device */
131#define HT_WAVEFORM   3 /* Waveform device */
132#define HT_MIDI       4 /* MIDI device */
133#define HT_DMX        5 /* DMX512/DMX4Linux device */
134#define HT_VIO        6 /* General VIO object */
135#define HT_STATIC     7 /* Static file */
136
137struct session {
138 int refc;
139 struct roar_connection con;
140};
141
142static struct session _session = {.refc = 0};
143
144struct handle {
145 int refc; // refrence counter
146 struct session * session;
147 int type;
148 int sysio_flags;
149 struct roar_stream    stream;
150 struct roar_vio_calls stream_vio;
151 int                   stream_dir;
152 int                   stream_opened;
153 size_t                stream_buffersize;
154 size_t                readc, writec;
155 size_t                pos;
156 union {
157  struct {
158   char * data;
159   size_t len;
160  } sf;
161 } userdata;
162};
163
164static struct {
165 int     (*open)(const char *pathname, int flags, mode_t mode);
166 int     (*close)(int fd);
167 ssize_t (*write)(int fd, const void *buf, size_t count);
168 ssize_t (*read)(int fd, void *buf, size_t count);
169#ifndef IOCTL_IS_ALIAS
170 int     (*ioctl)(int d, int request, ...);
171#endif
172 off_t   (*lseek)(int fildes, off_t offset, int whence);
173 FILE   *(*fopen)(const char *path, const char *mode);
174 int     (*dup)(int oldfd);
175 int     (*dup2)(int oldfd, int newfd);
176 int     (*select)(int nfds, fd_set *readfds, fd_set *writefds,
177                   fd_set *exceptfds, struct timeval *timeout);
178 int     (*fcntl)(int fd, int cmd, ...);
179 int     (*access)(const char *pathname, int mode);
180 int     (*open64)(const char *__file, int __oflag, ...);
181 int     (*creat)(const char *_CREAT_ARG_PATHNAME, mode_t mode);
182 int     (*stat)(const char *path, struct stat *buf);
183 int     (*fstat)(int filedes, struct stat *buf);
184 int     (*lstat)(const char *path, struct stat *buf);
185} _os;
186
187static struct {
188 struct {
189  int volume;
190  int pcm;
191  int line;
192  int line1;
193  int line2;
194  int line3;
195  int digital1;
196  int digital2;
197  int digital3;
198 } sid;
199} _mix_settings = {
200                   .sid = {
201                           .volume   = -1,
202                           .pcm      = -1,
203                           .line     =  0,
204                           .line1    =  1,
205                           .line2    =  2,
206                           .line3    =  3,
207                           .digital1 =  1,
208                           .digital2 =  2,
209                           .digital3 =  3
210                          }
211                  };
212
213static struct pointer {
214 int fh;
215 struct handle * handle;
216} _ptr[_MAX_POINTER];
217
218
219static char _sf__dev_sndstat[] =
220 "Sound Driver:RoarAudio\n"
221 "Config options: 0\n"
222 "\n"
223 "Installed drivers:\n"
224 "Type 10: RoarAudio emulation\n"
225 "\n"
226 "Card config:\n"
227 "\n"
228 "Audio devices:\n"
229 "0: RoarAudio OSS emulation (DUPLEX)\n"
230 "\n"
231 "Midi devices:\n"
232 "0: RoarAudio OSS emulation MIDI\n"
233 "\n"
234 "Timers:\n"
235 "\n"
236 "Mixers:\n"
237 "0: RoarAudio OSS emulation Mixer\n"
238;
239
240static struct devices {
241  char * prefix;
242  int type;
243  size_t len;
244  void * userdata;
245  struct handle * (*open)(const char * file, int flags, mode_t mode, struct devices * ptr);
246} _device_list[] = {
247 {"/dev/dsp",           HT_WAVEFORM,  0, NULL, NULL},
248 {"/dev/dsp?",          HT_WAVEFORM,  0, NULL, NULL},
249 {"/dev/audio",         HT_WAVEFORM,  0, NULL, NULL},
250 {"/dev/audio?",        HT_WAVEFORM,  0, NULL, NULL},
251 {"/dev/sound/dsp",     HT_WAVEFORM,  0, NULL, NULL},
252 {"/dev/sound/dsp?",    HT_WAVEFORM,  0, NULL, NULL},
253 {"/dev/sound/audio",   HT_WAVEFORM,  0, NULL, NULL},
254 {"/dev/sound/audio?",  HT_WAVEFORM,  0, NULL, NULL},
255 {"/dev/mixer",         HT_MIXER,     0, NULL, NULL},
256 {"/dev/mixer?",        HT_MIXER,     0, NULL, NULL},
257 {"/dev/sound/mixer",   HT_MIXER,     0, NULL, NULL},
258 {"/dev/sound/mixer?",  HT_MIXER,     0, NULL, NULL},
259 {"/dev/midi",          HT_MIDI,      0, NULL, NULL},
260 {"/dev/midi?",         HT_MIDI,      0, NULL, NULL},
261 {"/dev/rmidi",         HT_MIDI,      0, NULL, NULL},
262 {"/dev/rmidi?",        HT_MIDI,      0, NULL, NULL},
263 {"/dev/sound/midi",    HT_MIDI,      0, NULL, NULL},
264 {"/dev/sound/midi?",   HT_MIDI,      0, NULL, NULL},
265 {"/dev/sound/rmidi",   HT_MIDI,      0, NULL, NULL},
266 {"/dev/sound/rmidi?",  HT_MIDI,      0, NULL, NULL},
267 {"/dev/dmx",           HT_DMX,       0, NULL, NULL},
268 {"/dev/dmx?",          HT_DMX,       0, NULL, NULL},
269 {"/dev/misc/dmx",      HT_DMX,       0, NULL, NULL},
270 {"/dev/misc/dmx?",     HT_DMX,       0, NULL, NULL},
271 {"/dev/dmxin",         HT_DMX,       0, NULL, NULL},
272 {"/dev/dmxin?",        HT_DMX,       0, NULL, NULL},
273 {"/dev/misc/dmxin",    HT_DMX,       0, NULL, NULL},
274 {"/dev/misc/dmxin?",   HT_DMX,       0, NULL, NULL},
275 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat, NULL},
276#ifdef ROAR_DEFAULT_OSS_DEV
277 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL, NULL},
278#endif
279 {NULL, HT_NONE, 0, NULL, NULL},
280};
281
282
283static int _update_nonblock (struct handle * handle);
284
285static void _init_os (void) {
286 memset(&_os, 0, sizeof(_os));
287
288 // if call roar_dl_getsym() here all applications will segfaul.
289 // why?
290
291 _os.open   = dlsym(REAL_LIBC, "open");
292 _os.close  = dlsym(REAL_LIBC, "close");
293 _os.write  = dlsym(REAL_LIBC, "write");
294 _os.read   = dlsym(REAL_LIBC, "read");
295#ifndef IOCTL_IS_ALIAS
296 _os.ioctl  = dlsym(REAL_LIBC, "ioctl");
297#endif
298 _os.lseek  = dlsym(REAL_LIBC, "lseek");
299 _os.fopen  = dlsym(REAL_LIBC, "fopen");
300 _os.dup    = dlsym(REAL_LIBC, "dup");
301 _os.dup2   = dlsym(REAL_LIBC, "dup2");
302 _os.select = dlsym(REAL_LIBC, "select");
303 _os.fcntl  = dlsym(REAL_LIBC, "fcntl");
304 _os.access = dlsym(REAL_LIBC, "access");
305 _os.open64 = dlsym(REAL_LIBC, "open64");
306 _os.creat  = dlsym(REAL_LIBC, "creat");
307 _os.stat   = dlsym(REAL_LIBC, "stat");
308 _os.fstat  = dlsym(REAL_LIBC, "fstat");
309 _os.lstat  = dlsym(REAL_LIBC, "lstat");
310}
311
312static void _init_ptr (void) {
313 int i;
314
315 for (i = 0; i < _MAX_POINTER; i++) {
316  _ptr[i].fh = -1;
317 }
318}
319
320static void _init (void) {
321 static int inited = 0;
322
323 if ( !inited ) {
324  _init_os();
325  _init_ptr();
326  roar_vio_select(NULL, 0, NULL, NULL);
327  inited++;
328 }
329}
330
331static void _find_volume_sid (struct session * session) {
332 int i;
333 int num;
334 int id[ROAR_STREAMS_MAX];
335 struct roar_stream s;
336 char name[1024];
337
338 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
339
340 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
341  return;
342 }
343
344 for (i = 0; i < num; i++) {
345  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
346   continue;
347
348  if ( s.dir != ROAR_DIR_MIXING )
349   continue;
350
351  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
352   continue;
353
354  if ( !strcasecmp(name, "Waveform Mixer") ) {
355   _mix_settings.sid.volume = id[i];
356   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
357   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
358   return;
359  }
360 }
361}
362
363static int _open_dummy (void) {
364 int p[2];
365
366 if ( pipe(p) == -1 )
367  return -1;
368
369 close(p[1]);
370
371 return p[0];
372}
373
374static struct session * _open_session (char * server, char * name) {
375 struct session * ses = &_session;
376 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
377
378 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
379 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
380
381 if ( new_session ) {
382  ses = roar_mm_malloc(sizeof(struct session));
383  if ( ses == NULL )
384   return NULL;
385
386  memset(ses, 0, sizeof(struct session));
387 }
388
389 if ( ses->refc == 0 ) {
390
391  if ( name == NULL )
392   name = getenv("ROAR_OSS_CLIENT_NAME");
393
394  if ( name == NULL )
395   name = "libroaross client";
396
397  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
398   if ( new_session )
399    roar_mm_free(ses);
400
401   return NULL;
402  }
403
404  _find_volume_sid(ses);
405
406  if ( !new_session ) {
407   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
408    ses->refc++;
409  }
410 }
411
412 ses->refc++;
413
414 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
415 return ses;
416}
417
418static void _close_session(struct session * session) {
419 if ( session == NULL )
420  return;
421
422 session->refc--;
423
424 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
425
426 if ( session->refc == 0 ) {
427  roar_disconnect(&(session->con));
428 }
429
430 if ( session != &_session )
431  roar_mm_free(session);
432}
433
434static struct handle * _open_handle(struct session * session) {
435 struct handle * handle;
436
437 ROAR_DBG("_open_handle(session=%p) = ?", session);
438
439 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
440  return NULL;
441
442 memset(handle, 0, sizeof(struct handle));
443
444 handle->refc = 1;
445 handle->session = session;
446
447 if ( session != NULL )
448  session->refc++; // TODO: better warp this
449
450 handle->type = HT_NONE;
451 handle->stream_dir = ROAR_DIR_PLAY;
452 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
453
454 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
455 return handle;
456}
457
458static void _close_handle(struct handle * handle) {
459 int need_close = 0;
460
461 if (handle == NULL)
462  return;
463
464 handle->refc--;
465
466 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
467
468 if ( handle->refc == 0 ) {
469  switch (handle->type) {
470   case HT_VIO:
471     need_close = 1;
472    break;
473   case HT_STREAM:
474     if ( handle->stream_opened )
475      need_close = 1;
476    break;
477  }
478
479  if ( need_close )
480   roar_vio_close(&(handle->stream_vio));
481
482  if ( handle->session != NULL ) {
483   handle->session->refc--;
484
485   _close_session(handle->session);
486  }
487
488  roar_mm_free(handle);
489 }
490}
491
492static struct pointer * _get_pointer_by_fh (int fh) {
493 int i;
494
495 if ( fh == -1 )
496  return NULL;
497
498 for (i = 0; i < _MAX_POINTER; i++) {
499  if ( _ptr[i].fh == fh )
500   return &(_ptr[i]);
501 }
502
503 return NULL;
504}
505
506static struct pointer * _open_pointer(struct handle * handle) {
507 struct pointer * ret = _get_pointer_by_fh(-1);
508
509 if ( ret == NULL )
510  return NULL;
511
512 if ( (ret->fh = _open_dummy()) == -1 )
513  return NULL;
514
515 ret->handle = handle;
516
517 return ret;
518}
519
520static struct pointer * _attach_pointer(struct handle * handle, int fh) {
521 struct pointer * ret = _get_pointer_by_fh(-1);
522
523 if ( ret == NULL )
524  return NULL;
525
526 if ( (ret->fh = fh) == -1 )
527  return NULL;
528
529 ret->handle = handle;
530
531 handle->refc++;
532
533 return ret;
534}
535
536static void _close_pointer(struct pointer * pointer) {
537 if ( pointer == NULL )
538  return;
539
540 _os.close(pointer->fh);
541
542 pointer->fh = -1;
543
544 _close_handle(pointer->handle);
545}
546
547// -------------------------------------
548// central function to find device:
549// -------------------------------------
550
551static struct devices * _get_device (const char * pathname) {
552 size_t len, pathlen;
553 int i;
554 int qm_match;
555
556 ROAR_DBG("_get_device(pathname='%s') = ?", pathname);
557
558 pathlen = strlen(pathname);
559
560 for (i = 0; _device_list[i].prefix != NULL; i++) {
561  len = strlen(_device_list[i].prefix);
562
563  qm_match = 0;
564
565  if ( _device_list[i].prefix[len-1] == '*' ) {
566   len--;
567  } else if ( _device_list[i].prefix[len-1] == '?' ) {
568   qm_match = 1;
569   len--;
570  } else {
571   len++;
572  }
573
574  if ( !strncmp(pathname, _device_list[i].prefix, len) ) {
575   if ( !qm_match || pathlen == (len + 1) )
576    return &(_device_list[i]);
577  }
578 }
579
580 ROAR_DBG("_get_device(pathname='%s') = NULL", pathname);
581 return NULL;
582}
583
584// -------------------------------------
585// central open function:
586// -------------------------------------
587
588static int _open_file (const char *pathname, int flags) {
589 struct session * session;
590 struct handle  * handle;
591 struct pointer * pointer;
592 struct devices * ptr = NULL;
593
594 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
595
596/*
597 * Flags we ignore:
598 * O_DIRECT, O_APPEND, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_TRUNC
599 */
600
601#ifdef O_ASYNC
602 if ( flags & O_ASYNC ) {
603  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // not supported O_ASYNC", pathname, flags);
604  errno = ENOSYS;
605  return -1;
606 }
607#endif
608
609 if ( (flags & O_DIRECTORY) || (flags & O_EXCL) ) {
610  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // invalid flags (O_DIRECTORY or O_EXCL)", pathname, flags);
611  errno = EINVAL;
612  return -1;
613 }
614
615 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
616
617 if ( (ptr = _get_device(pathname)) == NULL )
618  return -2;
619
620 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
621
622 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
623  session = NULL;
624 } else {
625  if ( (session = _open_session(NULL, NULL)) == NULL ) {
626   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
627   return -1;
628  }
629 }
630
631 if ( ptr->open != NULL ) {
632  // TODO: Add support to pass mode (perms) to open.
633  if ( (handle = ptr->open(pathname, flags, 0000, ptr)) == NULL ) {
634   _close_session(session);
635   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
636   return -1;
637  }
638 } else {
639  if ( (handle = _open_handle(session)) == NULL ) {
640   _close_session(session);
641   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
642   return -1;
643  }
644
645  handle->type        = ptr->type;
646  handle->sysio_flags = flags;
647  handle->stream_dir  = -1;
648 }
649
650 switch (flags & _O_PARA_DIR) {
651  case O_RDONLY:
652    switch (ptr->type) {
653     case HT_WAVEFORM:
654       handle->stream_dir = ROAR_DIR_MONITOR;
655      break;
656     case HT_MIDI:
657       handle->stream_dir = ROAR_DIR_MIDI_OUT;
658      break;
659     case HT_DMX:
660       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
661      break;
662     case HT_MIXER:
663     case HT_STATIC:
664      break;
665     default:
666       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
667       return -1;
668    }
669   break;
670  case O_WRONLY:
671    switch (ptr->type) {
672     case HT_WAVEFORM:
673       handle->stream_dir = ROAR_DIR_PLAY;
674      break;
675     case HT_MIDI:
676       handle->stream_dir = ROAR_DIR_MIDI_IN;
677      break;
678     case HT_DMX:
679       handle->stream_dir = ROAR_DIR_LIGHT_IN;
680      break;
681     case HT_MIXER:
682     case HT_STATIC:
683      break;
684     default:
685       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
686       return -1;
687    }
688   break;
689  case O_RDWR:
690    switch (ptr->type) {
691     case HT_WAVEFORM:
692       handle->stream_dir = ROAR_DIR_BIDIR;
693      break;
694     case HT_MIXER:
695     case HT_STATIC:
696      break;
697     default:
698       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
699       return -1;
700    }
701   break;
702 }
703
704 switch (handle->type) {
705  case HT_WAVEFORM:
706    handle->type = HT_STREAM;
707   break;
708  case HT_MIDI:
709    handle->type = HT_STREAM;
710    handle->stream.info.rate     = 0;
711    handle->stream.info.bits     = ROAR_MIDI_BITS;
712    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
713    handle->stream.info.codec    = ROAR_CODEC_MIDI;
714   break;
715  case HT_DMX:
716    handle->stream.info.rate     = 0;
717    handle->stream.info.bits     = ROAR_LIGHT_BITS;
718    handle->stream.info.channels = 512;
719    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
720   break;
721  case HT_STATIC:
722    handle->userdata.sf.len      = ptr->len;
723    handle->userdata.sf.data     = ptr->userdata;
724   break;
725 }
726
727 if ( (pointer = _open_pointer(handle)) == NULL ) {
728  _close_handle(handle);
729  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
730  return -1;
731 }
732
733 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
734
735 return pointer->fh;
736}
737
738// -------------------------------------
739// VIO open function:
740// -------------------------------------
741
742int libroaross_open_vio(struct handle ** handleret, struct roar_vio_calls ** vio, int flags) {
743 struct handle  * handle;
744 struct pointer * pointer;
745
746 _init();
747
748 if ( vio == NULL )
749  return -1;
750
751 if ( (handle = _open_handle(NULL)) == NULL ) {
752  return -1;
753 }
754
755 handle->type        = HT_VIO;
756 handle->sysio_flags = flags;
757
758 if ( roar_vio_init_calls(&(handle->stream_vio)) == -1 ) {
759  _close_handle(handle);
760  return -1;
761 }
762
763 *vio = &(handle->stream_vio);
764
765 if ( handleret != NULL )
766  *handleret = handle;
767
768 if ( (pointer = _open_pointer(handle)) == NULL ) {
769  _close_handle(handle);
770  return -1;
771 }
772
773 return pointer->fh;
774}
775
776// -------------------------------------
777// open function for streams:
778// -------------------------------------
779
780static int _open_stream (struct handle * handle) {
781  // FIXME: this should be re-written much more cleanly:
782
783 if ( handle == NULL )
784  return -1;
785
786 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
787                                     &(handle->session->con), &(handle->stream),
788                                     handle->stream.info.rate,
789                                     handle->stream.info.channels,
790                                     handle->stream.info.bits,
791                                     handle->stream.info.codec,
792                                     handle->stream_dir
793                                    ) == -1 )
794  return -1;
795
796 handle->stream_opened++;
797
798 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
799
800 _update_nonblock(handle);
801
802 return 0;
803}
804
805// -------------------------------------
806// function to update O_NONBLOCK:
807// -------------------------------------
808
809static int _update_nonblock (struct handle * handle) {
810 int opened = 0;
811 int state  = handle->sysio_flags & O_NONBLOCK ? ROAR_SOCKET_NONBLOCK : ROAR_SOCKET_BLOCK;
812
813 switch (handle->type) {
814  case HT_NONE:
815  case HT_STATIC:
816  case HT_MIXER:
817    // we can ignore setting of nonblock flag here.
818    return 0;
819   break;
820  case HT_VIO:
821    opened = 1;
822   break;
823  case HT_STREAM:
824  case HT_WAVEFORM:
825  case HT_MIDI:
826  case HT_DMX:
827    opened = handle->stream_opened;
828   break;
829 }
830
831 if ( opened ) {
832  return roar_vio_nonblock(&(handle->stream_vio), state);
833 }
834
835 return 0;
836}
837
838// -------------------------------------
839// function to parse format:
840// -------------------------------------
841
842static int _ioctl_stream_format (struct handle * handle, int format) {
843 struct roar_audio_info * info = &(handle->stream.info);
844
845 switch (format) {
846  case AFMT_S8:
847    info->bits  = 8;
848    info->codec = ROAR_CODEC_PCM_S_LE;
849   break;
850  case AFMT_U8:
851    info->bits  = 8;
852    info->codec = ROAR_CODEC_PCM_U_LE;
853   break;
854  case AFMT_S16_BE:
855    info->bits  = 16;
856    info->codec = ROAR_CODEC_PCM_S_BE;
857   break;
858  case AFMT_S16_LE:
859    info->bits  = 16;
860    info->codec = ROAR_CODEC_PCM_S_LE;
861   break;
862  case AFMT_U16_BE:
863    info->bits  = 16;
864    info->codec = ROAR_CODEC_PCM_U_BE;
865   break;
866  case AFMT_U16_LE:
867    info->bits  = 16;
868    info->codec = ROAR_CODEC_PCM_U_LE;
869   break;
870#ifdef AFMT_S32_BE
871  case AFMT_S32_BE:
872    info->bits  = 32;
873    info->codec = ROAR_CODEC_PCM_S_BE;
874   break;
875#endif
876#ifdef AFMT_S32_LE
877  case AFMT_S32_LE:
878    info->bits  = 32;
879    info->codec = ROAR_CODEC_PCM_S_LE;
880   break;
881#endif
882  case AFMT_A_LAW:
883    info->bits  = 8;
884    info->codec = ROAR_CODEC_ALAW;
885   break;
886  case AFMT_MU_LAW:
887    info->bits  = 8;
888    info->codec = ROAR_CODEC_MULAW;
889   break;
890#ifdef AFMT_VORBIS
891  case AFMT_VORBIS:
892    info->codec = ROAR_CODEC_OGG_VORBIS;
893   break;
894#endif
895  default:
896    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
897    errno = ENOSYS;
898    return -1;
899   break;
900 }
901
902 return 0;
903}
904
905static inline int _ioctl_stream_format_list (void) {
906 int format = 0;
907
908 format |= AFMT_S8;
909 format |= AFMT_U8;
910
911 format |= AFMT_S16_BE;
912 format |= AFMT_S16_LE;
913
914 format |= AFMT_U16_BE;
915 format |= AFMT_U16_LE;
916
917#ifdef AFMT_S32_BE
918 format |= AFMT_S32_BE;
919#endif
920#ifdef AFMT_S32_LE
921 format |= AFMT_S32_LE;
922#endif
923
924 format |= AFMT_A_LAW;
925 format |= AFMT_MU_LAW;
926
927#ifdef AFMT_VORBIS
928 format |= AFMT_VORBIS;
929#endif
930
931 return format;
932}
933
934// -------------------------------------
935// mixer ioctls:
936// -------------------------------------
937
938static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
939 mixer_info * info;
940 int channels;
941 struct roar_mixer_settings mixer;
942 int o_w    =  0;
943 int o_sid  = -1;
944 int * ip   = vp;
945#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
946 char * name = NULL;
947#endif
948
949#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
950 switch (req) {
951#if 0
952  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
953  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
954  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
955  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
956  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
957  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
958  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
959#endif
960//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
961  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
962  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
963  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
964  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
965  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
966  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
967  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
968  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
969  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
970  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
971  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
972  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
973//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
974  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
975/*
976  case :     name = "";     break;
977  case :     name = "";     break;
978*/
979 }
980 if ( name != NULL ) {
981  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
982  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
983  errno = ENOSYS;
984  return -1;
985 }
986#endif
987
988 switch (req) {
989  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
990  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
991  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
992  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
993  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
994#if 0
995  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
996  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
997  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
998#endif
999  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
1000  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
1001  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
1002  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
1003  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
1004#if 0
1005  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
1006  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
1007  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
1008#endif
1009  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
1010  case SOUND_MIXER_READ_PCM:
1011    o_w = 0;
1012    if ( handle->type == HT_STREAM ) {
1013     o_sid = roar_stream_get_id(&(handle->stream));
1014    } else {
1015     o_sid = _mix_settings.sid.pcm;
1016    }
1017   break;
1018  case SOUND_MIXER_WRITE_PCM:
1019    o_w = 1;
1020    if ( handle->type == HT_STREAM ) {
1021     o_sid = roar_stream_get_id(&(handle->stream));
1022    } else {
1023     o_sid = _mix_settings.sid.pcm;
1024    }
1025   break;
1026 }
1027 if ( o_sid != -1 ) {
1028  // set/get volume
1029  if ( o_w ) {
1030   mixer.scale    = OSS_VOLUME_SCALE;
1031   mixer.mixer[0] = ( *ip       & 0xFF);
1032   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
1033   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
1034    errno = EIO;
1035    return -1;
1036   }
1037   return 0;
1038  } else {
1039   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
1040    errno = EIO;
1041    return -1;
1042   }
1043   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
1044   return 0;
1045  }
1046 }
1047
1048 switch (req) {
1049  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
1050  case SOUND_MIXER_READ_DEVMASK:
1051    *ip = 0;
1052
1053    if ( _mix_settings.sid.volume != -1 )
1054     *ip |= SOUND_MASK_VOLUME;
1055    if ( _mix_settings.sid.pcm != -1 )
1056     *ip |= SOUND_MASK_PCM;
1057    if ( _mix_settings.sid.line != -1 )
1058     *ip |= SOUND_MASK_LINE;
1059    if ( _mix_settings.sid.line1 != -1 )
1060     *ip |= SOUND_MASK_LINE1;
1061    if ( _mix_settings.sid.line2 != -1 )
1062     *ip |= SOUND_MASK_LINE2;
1063    if ( _mix_settings.sid.line3 != -1 )
1064     *ip |= SOUND_MASK_LINE3;
1065    if ( _mix_settings.sid.digital1 != -1 )
1066#if 0
1067     *ip |= SOUND_MASK_DIGITAL1;
1068    if ( _mix_settings.sid.digital2 != -1 )
1069     *ip |= SOUND_MASK_DIGITAL2;
1070    if ( _mix_settings.sid.digital3 != -1 )
1071     *ip |= SOUND_MASK_DIGITAL3;
1072#endif
1073
1074    return 0;
1075   break;
1076  case SOUND_MIXER_READ_RECMASK:
1077  case SOUND_MIXER_READ_RECSRC:
1078    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
1079    return 0;
1080   break;
1081  case SOUND_MIXER_WRITE_RECSRC:
1082    if ( *ip == SOUND_MASK_VOLUME ) {
1083     return  0;
1084    } else {
1085     errno = ENOTSUP;
1086     return -1;
1087    }
1088   break;
1089  case SOUND_MIXER_READ_CAPS:
1090    *ip = 0;
1091    return 0;
1092   break;
1093  case SOUND_MIXER_INFO:
1094    info = vp;
1095    memset(info, 0, sizeof(*info));
1096    strcpy(info->id, "RoarAudio");
1097    strcpy(info->name, "RoarAudio");
1098    return 0;
1099   break;
1100 }
1101
1102 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
1103// _os.ioctl(-1, req, ip);
1104 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
1105 errno = ENOSYS;
1106 return -1;
1107}
1108
1109// -------------------------------------
1110// buffer size calculation:
1111// -------------------------------------
1112
1113static size_t _get_stream_buffersize (struct handle * handle) {
1114 if ( handle->stream_buffersize )
1115  return handle->stream_buffersize;
1116
1117 return handle->stream_buffersize = handle->stream.info.rate     *
1118                                    handle->stream.info.channels *
1119                                    handle->stream.info.bits     / 800;
1120}
1121
1122// -------------------------------------
1123// emulated functions follow:
1124// -------------------------------------
1125
1126int     open(const char *pathname, int flags, ...) {
1127 int     ret;
1128 mode_t  mode = 0;
1129 va_list args;
1130
1131 _init();
1132
1133 if ( pathname == NULL ) {
1134  errno = EFAULT;
1135  return -1;
1136 }
1137
1138 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
1139 ret = _open_file(pathname, flags);
1140
1141 switch (ret) {
1142  case -2:       // continue as normal, use _op.open()
1143   break;
1144  case -1:       // pass error to caller
1145    return -1;
1146   break;
1147  default:       // return successfully opened pointer to caller
1148    return ret;
1149   break;
1150 }
1151
1152 if (flags & O_CREAT) {
1153  va_start(args, flags);
1154  mode = va_arg(args, _VA_ARGS_MODE_T);
1155  va_end(args);
1156 }
1157
1158 return _os.open(pathname, flags, mode);
1159}
1160
1161int    open64(const char *__file, int __oflag, ...) {
1162 int     ret;
1163 mode_t  mode = 0;
1164 va_list args;
1165
1166 _init();
1167
1168 if ( __file == NULL ) {
1169  errno = EFAULT;
1170  return -1;
1171 }
1172
1173 ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = ?\n", __file, __oflag);
1174 ret = _open_file(__file, __oflag);
1175
1176 switch (ret) {
1177  case -2:       // continue as normal, use _op.open()
1178   break;
1179  case -1:       // pass error to caller
1180    return -1;
1181   break;
1182  default:       // return successfully opened pointer to caller
1183    return ret;
1184   break;
1185 }
1186
1187 if (__oflag & O_CREAT) {
1188  va_start(args, __oflag);
1189  mode = va_arg(args, _VA_ARGS_MODE_T);
1190  va_end(args);
1191 }
1192
1193 if ( _os.open64 != NULL ) {
1194  return _os.open64(__file, __oflag, mode);
1195 } else {
1196#ifdef O_LARGEFILE
1197  return _os.open(__file, __oflag | O_LARGEFILE, mode);
1198#else
1199  return _os.open(__file, __oflag, mode);
1200#endif
1201 }
1202}
1203
1204int     close(int fd) {
1205 struct pointer * pointer;
1206 _init();
1207
1208 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1209  _close_pointer(pointer);
1210  return 0;
1211 }
1212
1213 return _os.close(fd);
1214}
1215
1216ssize_t write(int fd, const void *buf, size_t count) {
1217 struct roar_roardmx_message roardmxmsg;
1218 struct pointer * pointer;
1219 ssize_t ret;
1220 size_t i;
1221
1222 _init();
1223
1224 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1225  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
1226  switch (pointer->handle->type) {
1227   case HT_STREAM: // handle stream specific stuff
1228     if ( pointer->handle->stream_opened == 0 ) {
1229      if ( _open_stream(pointer->handle) == -1 ) {
1230       errno = EIO;
1231       return -1;
1232      }
1233     }
1234   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
1235     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
1236     if ( ret > 0 )
1237      pointer->handle->writec += ret;
1238     return ret;
1239    break;
1240   case HT_DMX: // DMX need specal handling as we need to convert the protocol
1241     if ( pointer->handle->stream_opened == 0 ) {
1242      if ( _open_stream(pointer->handle) == -1 ) {
1243       errno = EIO;
1244       return -1;
1245      }
1246     }
1247     if ( count > 0 ) {
1248      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
1249       errno = EIO;
1250       return -1;
1251      }
1252      for (i = 0; i < count; i++) {
1253       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1254#ifdef EMSGSIZE
1255        errno = EMSGSIZE;
1256#else
1257        errno = EIO;
1258#endif
1259        return -1;
1260       }
1261      }
1262      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1263       errno = EIO;
1264       return -1;
1265      }
1266     }
1267     pointer->handle->pos += count;
1268     return count;
1269    break;
1270   default: // we don't know what to do with other types
1271     errno = EINVAL;
1272     return -1;
1273    break;
1274  }
1275 }
1276
1277 return _os.write(fd, buf, count);
1278}
1279
1280ssize_t read(int fd, void *buf, size_t count) {
1281 struct pointer * pointer;
1282 ssize_t ret;
1283
1284 _init();
1285
1286 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1287  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1288
1289  switch (pointer->handle->type) {
1290   case HT_STREAM:
1291     if ( pointer->handle->stream_opened == 0 ) {
1292      if ( _open_stream(pointer->handle) == -1 ) {
1293       errno = EIO;
1294       return -1;
1295      }
1296     }
1297   case HT_VIO:
1298     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1299     if ( ret > 0 )
1300      pointer->handle->readc += ret;
1301     return ret;
1302    break;
1303   case HT_STATIC:
1304     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1305     ret = pointer->handle->pos + count; // calc the end of the read
1306
1307     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1308      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1309     }
1310
1311     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1312     pointer->handle->pos += count;
1313     return count;
1314    break;
1315   default:
1316     errno = EINVAL;
1317     return -1;
1318    break;
1319  }
1320 }
1321
1322 return _os.read(fd, buf, count);
1323}
1324
1325off_t lseek(int fildes, off_t offset, int whence) {
1326 struct pointer * pointer;
1327 ssize_t tmp;
1328
1329 _init();
1330
1331 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1332  switch (pointer->handle->type) {
1333   case HT_DMX:
1334     switch (whence) {
1335      case SEEK_SET:
1336        pointer->handle->pos  = offset;
1337       break;
1338      case SEEK_CUR:
1339        pointer->handle->pos += offset;
1340       break;
1341      case SEEK_END:
1342      default:
1343        errno = EINVAL;
1344        return -1;
1345       break;
1346     }
1347     return pointer->handle->pos;
1348    break;
1349   case HT_VIO:
1350     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1351    break;
1352   case HT_STATIC:
1353     switch (whence) {
1354      case SEEK_SET:
1355        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1356         errno = EINVAL;
1357         return -1;
1358        }
1359        pointer->handle->pos  = offset;
1360       break;
1361      case SEEK_CUR:
1362        tmp = pointer->handle->pos + offset;
1363        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1364         errno = EINVAL;
1365         return -1;
1366        }
1367        pointer->handle->pos = tmp;
1368       break;
1369      case SEEK_END:
1370        tmp = pointer->handle->userdata.sf.len + offset;
1371        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1372         errno = EINVAL;
1373         return -1;
1374        }
1375        pointer->handle->pos = tmp;
1376       break;
1377      default:
1378        errno = EINVAL;
1379        return -1;
1380       break;
1381     }
1382    break;
1383   default:
1384     errno = EINVAL;
1385     return -1;
1386    break;
1387  }
1388 }
1389
1390 return _os.lseek(fildes, offset, whence);
1391}
1392
1393IOCTL() {
1394 map_args;
1395 struct pointer * pointer;
1396 struct handle  * handle;
1397 int * ip = NULL;
1398 size_t tmp;
1399 audio_buf_info * bi;
1400 count_info     * ci;
1401#ifdef __FIXME__
1402 char * nosys_reqname = NULL;
1403#endif
1404#ifdef va_argp
1405 va_list args;
1406#endif
1407
1408 _init();
1409
1410// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1411
1412#ifdef va_argp
1413 va_start (args, ioctl_lastarg);
1414 argp = va_arg (args, void *);
1415 va_end (args);
1416#endif
1417
1418 ROAR_DBG("ioctl(fh=%i, request=%i, ...) = ?", __fd, __request);
1419
1420// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1421
1422 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1423  ip = argp;
1424//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1425#ifdef __FIXME__
1426  switch ((handle = pointer->handle)->type) {
1427   case SOUND_PCM_READ_RATE: nosys_reqname     = "SOUND_PCM_READ_RATE";     break;
1428   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1429   case SOUND_PCM_READ_BITS: nosys_reqname     = "SOUND_PCM_READ_BITS";     break;
1430   case SOUND_PCM_READ_FILTER: nosys_reqname   = "SOUND_PCM_READ_FILTER";   break;
1431   case SNDCTL_COPR_RESET: nosys_reqname       = "SNDCTL_COPR_RESET";       break;
1432   case SNDCTL_COPR_LOAD: nosys_reqname        = "SNDCTL_COPR_LOAD";        break;
1433   case SNDCTL_COPR_HALT: nosys_reqname        = "SNDCTL_COPR_HALT";        break;
1434   case SNDCTL_COPR_RDATA: nosys_reqname       = "SNDCTL_COPR_RDATA";       break;
1435   case SNDCTL_COPR_RCODE: nosys_reqname       = "SNDCTL_COPR_RCODE";       break;
1436   case SNDCTL_COPR_WDATA: nosys_reqname       = "SNDCTL_COPR_WDATA";       break;
1437   case SNDCTL_COPR_WCODE: nosys_reqname       = "SNDCTL_COPR_WCODE";       break;
1438   case SNDCTL_COPR_RUN: nosys_reqname         = "SNDCTL_COPR_RUN";         break;
1439   case SNDCTL_COPR_SENDMSG: nosys_reqname     = "SNDCTL_COPR_SENDMSG";     break;
1440   case SNDCTL_COPR_RCVMSG: nosys_reqname      = "SNDCTL_COPR_RCVMSG";      break;
1441   case SNDCTL_DSP_GETCAPS: nosys_reqname      = "SNDCTL_DSP_GETCAPS";      break;
1442   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1443/*
1444   case : nosys_reqname = ""; break;
1445   case : nosys_reqname = ""; break;
1446   case : nosys_reqname = ""; break;
1447*/
1448  }
1449#endif
1450  switch ((handle = pointer->handle)->type) {
1451   case HT_STREAM:
1452     switch (__request) {
1453      case SNDCTL_DSP_RESET:
1454      case SNDCTL_DSP_POST:
1455      case SNDCTL_DSP_SYNC: // ignore for the moment.
1456      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1457      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1458        return 0;
1459       break;
1460      case SNDCTL_DSP_SPEED:
1461        handle->stream.info.rate = *ip;
1462        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1463        return 0;
1464       break;
1465      case SNDCTL_DSP_CHANNELS:
1466        handle->stream.info.channels = *ip;
1467        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1468        return 0;
1469       break;
1470      case SNDCTL_DSP_STEREO:
1471        handle->stream.info.channels = *ip ? 2 : 1;
1472        return 0;
1473       break;
1474      case SNDCTL_DSP_GETBLKSIZE:
1475        *ip = _get_stream_buffersize(handle);
1476        return 0;
1477       break;
1478      case SNDCTL_DSP_SETFMT:
1479        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1480        return _ioctl_stream_format(handle, *ip);
1481       break;
1482      case SNDCTL_DSP_GETFMTS:
1483//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1484        *ip = _ioctl_stream_format_list();
1485        return 0;
1486       break;
1487      case SNDCTL_DSP_GETOSPACE:
1488      case SNDCTL_DSP_GETISPACE:
1489        bi = argp;
1490        memset(bi, 0, sizeof(*bi));
1491        bi->bytes      = _get_stream_buffersize(handle);
1492        bi->fragments  = 1;
1493        bi->fragsize   = bi->bytes;
1494        bi->fragstotal = 1;
1495        return 0;
1496       break;
1497      case SNDCTL_DSP_GETOPTR:
1498        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1499        ci = argp;
1500        memset(ci, 0, sizeof(*ci));
1501        ci->bytes  = handle->writec;
1502        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1503        ci->ptr    = ci->bytes % tmp;
1504        return 0;
1505       break;
1506      case SNDCTL_DSP_GETIPTR:
1507        ci = argp;
1508        memset(ci, 0, sizeof(*ci));
1509        ci->bytes  = handle->readc;
1510        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1511        ci->ptr    = ci->bytes % tmp;
1512        return 0;
1513       break;
1514#ifdef SNDCTL_DSP_GETPLAYVOL
1515      case SNDCTL_DSP_GETPLAYVOL:
1516        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1517       break;
1518#endif
1519#ifdef SNDCTL_DSP_SETPLAYVOL
1520      case SNDCTL_DSP_SETPLAYVOL:
1521        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1522       break;
1523#endif
1524#ifdef SNDCTL_DSP_NONBLOCK
1525      case SNDCTL_DSP_NONBLOCK:
1526        return fcntl(__fd, F_SETFL, handle->sysio_flags|O_NONBLOCK);
1527       break;
1528#endif
1529      default:
1530#ifdef __FIXME__
1531        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1532#else
1533        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1534#endif
1535        errno = ENOSYS;
1536        return -1;
1537     }
1538    break;
1539   case HT_MIXER:
1540     return _ioctl_mixer(handle, __request, argp);
1541    break;
1542   default:
1543     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1544     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1545     errno = EINVAL;
1546     return -1;
1547    break;
1548  }
1549 }
1550
1551#ifdef IOCTL_IS_ALIAS
1552 errno = ENOSYS;
1553 return -1;
1554#else
1555 return _os.ioctl(__fd, __request, argp);
1556#endif
1557}
1558
1559int dup(int oldfd) {
1560 struct pointer * pointer;
1561 int ret;
1562
1563 _init();
1564
1565 ret = _os.dup(oldfd);
1566
1567 if (ret == -1)
1568  return -1;
1569
1570 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1571  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1572   _os.close(ret);
1573   return -1;
1574  }
1575 }
1576
1577 return ret;
1578}
1579
1580int dup2(int oldfd, int newfd) {
1581 struct pointer * pointer;
1582 int ret;
1583
1584 _init();
1585
1586 ret = _os.dup2(oldfd, newfd);
1587
1588 if (ret == -1)
1589  return -1;
1590
1591 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1592  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1593   _os.close(ret);
1594   return -1;
1595  }
1596 }
1597
1598 return ret;
1599}
1600
1601int select(int nfds, fd_set *readfds, fd_set *writefds,
1602           fd_set *exceptfds, struct timeval *timeout) {
1603 struct roar_vio_selecttv rtv;
1604 struct roar_vio_select * sv  = NULL;
1605 struct pointer * pointer;
1606 struct handle  * handle;
1607 ssize_t ret;
1608 size_t num = 0;
1609 size_t idx;
1610 int i;
1611 int i_r, i_w, i_e;
1612 int max_index = -1;
1613 static volatile int is_critical = 0;
1614
1615 _init();
1616
1617 if ( is_critical )
1618  return _os.select(nfds, readfds, writefds, exceptfds, timeout);
1619
1620 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = ?", nfds, readfds, writefds, exceptfds, timeout);
1621
1622 if ( nfds == 0 ) {
1623  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1624  return 0;
1625 }
1626
1627 if ( readfds == NULL && writefds == NULL && exceptfds == NULL ) {
1628  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1629  return 0;
1630 }
1631
1632 if ( timeout != NULL ) {
1633  rtv.sec = timeout->tv_sec;
1634  rtv.nsec = timeout->tv_usec*1000;
1635 }
1636
1637 // count number of handles:
1638 for (i = 0; i < nfds; i++) {
1639  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1640  if ( (readfds   != NULL && FD_ISSET(i, readfds  )) ||
1641       (writefds  != NULL && FD_ISSET(i, writefds )) ||
1642       (exceptfds != NULL && FD_ISSET(i, exceptfds))
1643     ) {
1644   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1645   num++;
1646   max_index = i;
1647  }
1648 }
1649
1650 if ( num == 0 ) {
1651  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1652  return 0;
1653 }
1654
1655 nfds = max_index + 1;
1656
1657 // create sv;
1658 sv = roar_mm_malloc(sizeof(struct roar_vio_select)*num);
1659 if ( sv == NULL ) {
1660  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1", nfds, readfds, writefds, exceptfds, timeout);
1661  return -1;
1662 }
1663
1664 memset(sv, 0, sizeof(struct roar_vio_select)*num);
1665
1666 for (i = 0, idx = 0; i < nfds; i++) {
1667  if ( idx >= num ) {
1668   roar_mm_free(sv);
1669   errno = EFAULT;
1670   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1 // i=%i, idx=%i, num=%i", nfds, readfds, writefds, exceptfds, timeout, i, (int)idx, (int)num);
1671   return -1;
1672  }
1673  i_r = readfds   != NULL && FD_ISSET(i, readfds);
1674  i_w = writefds  != NULL && FD_ISSET(i, writefds);
1675  i_e = exceptfds != NULL && FD_ISSET(i, exceptfds);
1676
1677  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, i_r=%i, i_w=%i, i_e=%i", nfds, readfds, writefds, exceptfds, timeout, i, i_r, i_w, i_e);
1678
1679  if ( i_r || i_w || i_e ) {
1680   // TODO: use VIO for pointers...
1681   if ( (pointer = _get_pointer_by_fh(i)) != NULL ) {
1682    handle = pointer->handle;
1683    sv[idx].vio     = NULL;
1684    sv[idx].fh      = -1;
1685    switch (handle->type) {
1686     case HT_DMX:
1687     case HT_STREAM:
1688       if ( ! handle->stream_opened ) {
1689        // implement this as statichly return OK
1690        errno = ENOSYS;
1691        return -1;
1692       }
1693     case HT_VIO:
1694       sv[idx].vio = &(handle->stream_vio);
1695      break;
1696     default: /* non supported type */
1697       errno = EINVAL;
1698       return -1;
1699      break;
1700    }
1701   } else {
1702    sv[idx].vio     = NULL;
1703    sv[idx].fh      = i;
1704   }
1705
1706   sv[idx].ud.si   = i;
1707   sv[idx].eventsq = (i_r ? ROAR_VIO_SELECT_READ   : 0) |
1708                     (i_w ? ROAR_VIO_SELECT_WRITE  : 0) |
1709                     (i_e ? ROAR_VIO_SELECT_EXCEPT : 0);
1710   idx++;
1711  }
1712 }
1713
1714 is_critical++;
1715 ret = roar_vio_select(sv, num, timeout == NULL ? NULL : &rtv, NULL);
1716 is_critical--;
1717
1718 if ( ret < 1 ) {
1719  roar_mm_free(sv);
1720  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1721  return ret;
1722 }
1723
1724 // update readfds, writefds, exceptfds:
1725 if ( readfds != NULL )
1726  FD_ZERO(readfds);
1727
1728 if ( writefds != NULL )
1729  FD_ZERO(writefds);
1730
1731 if ( exceptfds != NULL )
1732  FD_ZERO(exceptfds);
1733
1734 for (idx = 0; idx < num; idx++) {
1735  if ( sv[idx].eventsa == 0 )
1736   continue;
1737
1738  if ( sv[idx].eventsa & ROAR_VIO_SELECT_READ )
1739   if ( readfds != NULL )
1740    FD_SET(sv[idx].ud.si, readfds);
1741
1742  if ( sv[idx].eventsa & ROAR_VIO_SELECT_WRITE )
1743   if ( writefds != NULL )
1744    FD_SET(sv[idx].ud.si, writefds);
1745
1746  if ( sv[idx].eventsa & ROAR_VIO_SELECT_EXCEPT )
1747   if ( exceptfds != NULL )
1748    FD_SET(sv[idx].ud.si, exceptfds);
1749 }
1750
1751 roar_mm_free(sv);
1752
1753 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1754 return ret;
1755}
1756
1757int fcntl(int fd, int cmd, ...) {
1758 enum { NONE, UNKNOWN, LONG, POINTER } type = NONE;
1759 struct pointer * pointer;
1760 va_list ap;
1761 long argl = -1;
1762 void * vp = NULL;
1763 int ret   = -1;
1764 int diff;
1765
1766 _init();
1767
1768 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...) = ?", fd, cmd);
1769
1770 switch (cmd) {
1771  case F_DUPFD:
1772  case F_SETFD:
1773  case F_SETFL:
1774  case F_SETOWN:
1775#ifdef F_SETSIG
1776  case F_SETSIG:
1777#endif
1778#ifdef F_SETLEASE
1779  case F_SETLEASE:
1780#endif
1781#ifdef F_NOTIFY
1782  case F_NOTIFY:
1783#endif
1784    type = LONG;
1785   break;
1786  case F_GETFD:
1787  case F_GETFL:
1788  case F_GETOWN:
1789#ifdef F_GETSIG
1790  case F_GETSIG:
1791#endif
1792#ifdef F_GETLEASE
1793  case F_GETLEASE:
1794#endif
1795    type = NONE;
1796   break;
1797  case F_GETLK:
1798  case F_SETLK:
1799  case F_SETLKW:
1800    type = POINTER;
1801   break;
1802/*
1803  case F_EXLCK:
1804  case F_GETLK64:
1805  case F_SETLK64:
1806  case F_SETLKW64:
1807  case F_SHLCK:
1808  case F_LINUX_SPECIFIC_BASE:
1809  case F_INPROGRESS:
1810*/
1811  default:
1812    type = UNKNOWN;
1813 }
1814
1815 if ( type == UNKNOWN ) {
1816  errno = EINVAL;
1817  return -1;
1818 }
1819
1820 if ( type != NONE ) {
1821  va_start(ap, cmd);
1822  switch (type) {
1823   case LONG:
1824     argl = va_arg(ap, long);
1825    break;
1826   case POINTER:
1827     vp = va_arg(ap, void*);
1828    break;
1829   default: /* make compiler happy */
1830    break;
1831  }
1832  va_end(ap);
1833 }
1834
1835 if ( (pointer = _get_pointer_by_fh(fd)) == NULL ) {
1836  switch (type) {
1837   case NONE:
1838     ROAR_DBG("fcntl(fd=%i, cmd=%i): fd is true sysio, pass call to kernel", fd, cmd);
1839     return _os.fcntl(fd, cmd);
1840    break;
1841   case LONG:
1842     ROAR_DBG("fcntl(fd=%i, cmd=%i, arg=%li): fd is true sysio, pass call to kernel", fd, cmd, argl);
1843     return _os.fcntl(fd, cmd, argl);
1844    break;
1845   case POINTER:
1846     ROAR_DBG("fcntl(fd=%i, cmd=%i, lock=%p): fd is true sysio, pass call to kernel", fd, cmd, vp);
1847     return _os.fcntl(fd, cmd, vp);
1848    break;
1849   default: /* make compiler happy */
1850    break;
1851  }
1852 }
1853
1854 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...): fd is true pointer, handle internaly", fd, cmd);
1855
1856 switch (cmd) {
1857  case F_DUPFD:
1858    ret = _os.fcntl(fd, F_DUPFD, argl);
1859
1860    if ( ret != -1 ) {
1861     if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1862      _os.close(ret);
1863      ret = -1;
1864     }
1865    }
1866   break;
1867  case F_SETFD:
1868    if ( argl == 0 ) {
1869     ret = 0;
1870    } else {
1871     errno = ENOSYS;
1872     ret = -1;
1873    }
1874   break;
1875  case F_GETFD:
1876    ret = 0;
1877   break;
1878  case F_GETFL:
1879    ret = pointer->handle->sysio_flags;
1880   break;
1881  case F_SETFL:
1882    diff  = (int)argl ^ pointer->handle->sysio_flags;
1883    diff &= (int)~(int)_O_PARA_DIR;
1884    diff &= (int)~(int)_O_PARA_IGN;
1885
1886    if ( diff & O_NONBLOCK ) {
1887     diff -= O_NONBLOCK;
1888     pointer->handle->sysio_flags ^= O_NONBLOCK;
1889     if ( _update_nonblock(pointer->handle) == -1 ) {
1890      pointer->handle->sysio_flags ^= O_NONBLOCK;
1891      return -1;
1892     }
1893    }
1894
1895    if ( diff == 0 ) { // only flags changed we ignore anyway.
1896     pointer->handle->sysio_flags  = (int)argl;
1897     ret = 0;
1898    } else {
1899     errno = EINVAL;
1900     ret = -1;
1901    }
1902   break;
1903/* TODO: add support for those types:
1904  case F_SETFD:
1905  case F_SETOWN:
1906  case F_SETSIG:
1907  case F_SETLEASE:
1908  case F_NOTIFY:
1909  case F_GETOWN:
1910  case F_GETSIG:
1911  case F_GETLEASE:
1912  case F_GETLK:
1913  case F_SETLK:
1914  case F_SETLKW:
1915*/
1916  default:
1917    errno = ENOSYS;
1918    ret = -1;
1919   break;
1920 }
1921
1922 return ret;
1923}
1924
1925int access(const char *pathname, int mode) {
1926 struct devices * ptr = NULL;
1927
1928 _init();
1929
1930 if ( (ptr = _get_device(pathname)) != NULL ) {
1931  // the only flag we do not support is +x, which means
1932  // we need to reject all requets with X_OK.
1933  if ( mode & X_OK ) {
1934   errno = EACCES;
1935   return -1;
1936  }
1937
1938  // in addition HT_STATIC files do not support write (+w)
1939  // so we need to reject W_OK.
1940  if ( ptr->type == HT_STATIC && (mode & W_OK) ) {
1941   errno = EACCES;
1942   return -1;
1943  }
1944
1945  // Else the access is granted:
1946  return 0;
1947 }
1948
1949 return _os.access(pathname, mode);
1950}
1951
1952int creat(const char *_CREAT_ARG_PATHNAME, mode_t mode) {
1953 _init();
1954
1955 if ( _get_device(_CREAT_ARG_PATHNAME) != NULL ) {
1956  errno = EEXIST;
1957  return -1;
1958 }
1959
1960 return _os.creat(_CREAT_ARG_PATHNAME, mode);
1961}
1962
1963// -------------------------------------
1964// emulated *stat*() functions follow:
1965// -------------------------------------
1966
1967int stat(const char *path, struct stat *buf) {
1968 struct devices * ptr;
1969
1970 _init();
1971
1972 if ( (ptr = _get_device(path)) != NULL ) {
1973  errno = ENOSYS;
1974  return -1;
1975 }
1976
1977 return _os.stat(path, buf);
1978}
1979
1980int fstat(int filedes, struct stat *buf) {
1981 struct pointer * pointer;
1982
1983 _init();
1984
1985 if ( (pointer = _get_pointer_by_fh(filedes)) == NULL ) {
1986  return _os.fstat(filedes, buf);
1987 }
1988
1989 errno = ENOSYS;
1990 return -1;
1991}
1992
1993int lstat(const char *path, struct stat *buf) {
1994 _init();
1995
1996 if ( _get_device(path) != NULL ) {
1997  return stat(path, buf);
1998 }
1999
2000 return _os.lstat(path, buf);
2001}
2002
2003// -------------------------------------
2004// emulated stdio functions follow:
2005// -------------------------------------
2006
2007//roar_vio_to_stdio
2008
2009static int _vio_close    (struct roar_vio_calls * vio) {
2010 int ret = 0;
2011
2012 if ( roar_vio_get_fh(vio) != -1 )
2013  ret = close(roar_vio_get_fh(vio));
2014
2015 roar_mm_free(vio);
2016
2017 return ret;
2018}
2019
2020FILE *fopen(const char *path, const char *mode) {
2021 struct roar_vio_calls * vio;
2022 FILE  * fr;
2023 int     ret;
2024 int     r = 0, w = 0;
2025 int     flags = 0;
2026 int     i;
2027 register char c;
2028
2029 _init();
2030
2031 if ( path == NULL || mode == NULL ) {
2032  errno = EFAULT;
2033  return NULL;
2034 }
2035
2036 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
2037
2038 for (i = 0; (c = mode[i]) != 0; i++) {
2039  switch (c) {
2040   case 'r': r = 1; break;
2041   case 'w': w = 1; break;
2042   case 'a': w = 1; break;
2043   case '+':
2044     r = 1;
2045     w = 1;
2046    break;
2047  }
2048 }
2049
2050 if ( r && w ) {
2051  flags = O_RDWR;
2052 } else if ( r ) {
2053  flags = O_RDONLY;
2054 } else if ( w ) {
2055  flags = O_WRONLY;
2056 } else {
2057  errno = EINVAL;
2058  return NULL;
2059 }
2060
2061 ret = _open_file(path, flags);
2062
2063 switch (ret) {
2064  case -2:       // continue as normal, use _op.open()
2065   break;
2066  case -1:       // pass error to caller
2067    return NULL;
2068   break;
2069  default:       // return successfully opened pointer to caller
2070    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
2071     return NULL; // errno should be set correctly by roar_mm_malloc().
2072    }
2073
2074    roar_vio_init_calls(vio);  // TODO: add error handling.
2075    roar_vio_set_fh(vio, ret); // TODO: add error handling.
2076    vio->close = _vio_close;
2077    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
2078     _vio_close(vio);
2079     errno = EIO;
2080     return NULL;
2081    } else {
2082     return fr;
2083    }
2084   break;
2085 }
2086
2087 return _os.fopen(path, mode);
2088}
2089
2090// -------------------------------------
2091// RoarAudio plugin functions follow:
2092// -------------------------------------
2093
2094ROAR_DL_PLUGIN_START(libroaross) {
2095 (void)para;
2096 _init();
2097} ROAR_DL_PLUGIN_END
2098
2099#endif
2100
2101//ll
Note: See TracBrowser for help on using the repository browser.