source: roaraudio/libroaross/libroaross.c @ 3667:cfe93dbf0bdb

Last change on this file since 3667:cfe93dbf0bdb was 3667:cfe93dbf0bdb, checked in by phi, 14 years ago

support static files with fopen()

File size: 37.4 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
62#if defined(RTLD_NEXT)
63#define REAL_LIBC RTLD_NEXT
64#else
65#define REAL_LIBC ((void *) -1L)
66#endif
67
68#ifndef ENOTSUP
69#define ENOTSUP ENOSYS
70#endif
71
72#if defined(ROAR_OS_NETBSD) && defined(ioctl)
73#define IOCTL_IS_ALIAS
74#endif
75
76#ifdef ROAR_OS_FREEBSD
77#define mode_t int
78#endif
79
80#ifdef ROAR_OS_NETBSD
81#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
82#define map_args int __fd = fd; unsigned long int __request = com
83#elif defined(ROAR_TARGET_CYGWIN)
84#define IOCTL() int ioctl (int __fd, int __cmd, ...)
85#define map_args unsigned long int __request = __cmd; void * argp
86#define va_argp
87#define ioctl_lastarg __cmd
88#else
89#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
90#define map_args void * argp
91#define va_argp
92#define ioctl_lastarg __request
93#endif
94
95#define OSS_VOLUME_SCALE 100
96
97#define _MAX_POINTER  8
98
99// handle type:
100#define HT_NONE       0 /* Unused object */
101#define HT_STREAM     1 /* Stream with no specal handling needed */
102#define HT_MIXER      2 /* Mixer device */
103#define HT_WAVEFORM   3 /* Waveform device */
104#define HT_MIDI       4 /* MIDI device */
105#define HT_DMX        5 /* DMX512/DMX4Linux device */
106#define HT_VIO        6 /* General VIO object */
107#define HT_STATIC     7 /* Static file */
108
109struct session {
110 int refc;
111 struct roar_connection con;
112};
113
114static struct session _session = {.refc = 0};
115
116struct handle {
117 int refc; // refrence counter
118 struct session * session;
119 int type;
120 struct roar_stream    stream;
121 struct roar_vio_calls stream_vio;
122 int                   stream_dir;
123 int                   stream_opened;
124 size_t                stream_buffersize;
125 size_t                readc, writec;
126 size_t                pos;
127 union {
128  struct {
129   char * data;
130   size_t len;
131  } sf;
132 } userdata;
133};
134
135static struct {
136 int     (*open)(const char *pathname, int flags, mode_t mode);
137 int     (*close)(int fd);
138 ssize_t (*write)(int fd, const void *buf, size_t count);
139 ssize_t (*read)(int fd, void *buf, size_t count);
140#ifndef IOCTL_IS_ALIAS
141 int     (*ioctl)(int d, int request, ...);
142#endif
143 off_t   (*lseek)(int fildes, off_t offset, int whence);
144 FILE   *(*fopen)(const char *path, const char *mode);
145 int     (*dup)(int oldfd);
146 int     (*dup2)(int oldfd, int newfd);
147} _os;
148
149static struct {
150 struct {
151  int volume;
152  int pcm;
153  int line;
154  int line1;
155  int line2;
156  int line3;
157  int digital1;
158  int digital2;
159  int digital3;
160 } sid;
161} _mix_settings = {
162                   .sid = {
163                           .volume   = -1,
164                           .pcm      = -1,
165                           .line     =  0,
166                           .line1    =  1,
167                           .line2    =  2,
168                           .line3    =  3,
169                           .digital1 =  1,
170                           .digital2 =  2,
171                           .digital3 =  3
172                          }
173                  };
174
175static struct pointer {
176 int fh;
177 struct handle * handle;
178} _ptr[_MAX_POINTER];
179
180
181static char _sf__dev_sndstat[] =
182 "Sound Driver:RoarAudio\n"
183 "Config options: 0\n"
184 "\n"
185 "Installed drivers:\n"
186 "Type 10: RoarAudio emulation\n"
187 "\n"
188 "Card config:\n"
189 "\n"
190 "Audio devices:\n"
191 "0: RoarAudio OSS emulation (DUPLEX)\n"
192 "\n"
193 "Midi devices:\n"
194 "0: RoarAudio OSS emulation MIDI\n"
195 "\n"
196 "Timers:\n"
197 "\n"
198 "Mixers:\n"
199 "0: RoarAudio OSS emulation Mixer\n"
200;
201
202static struct devices {
203  char * prefix;
204  int type;
205  size_t len;
206  void * userdata;
207} _device_list[] = {
208 {"/dev/dsp",           HT_WAVEFORM,  0, NULL},
209 {"/dev/audio",         HT_WAVEFORM,  0, NULL},
210 {"/dev/sound/dsp",     HT_WAVEFORM,  0, NULL},
211 {"/dev/sound/audio",   HT_WAVEFORM,  0, NULL},
212 {"/dev/mixer",         HT_MIXER,     0, NULL},
213 {"/dev/sound/mixer",   HT_MIXER,     0, NULL},
214 {"/dev/midi",          HT_MIDI,      0, NULL},
215 {"/dev/rmidi",         HT_MIDI,      0, NULL},
216 {"/dev/sound/midi",    HT_MIDI,      0, NULL},
217 {"/dev/sound/rmidi",   HT_MIDI,      0, NULL},
218 {"/dev/dmx",           HT_DMX,       0, NULL},
219 {"/dev/misc/dmx",      HT_DMX,       0, NULL},
220 {"/dev/dmxin",         HT_DMX,       0, NULL},
221 {"/dev/misc/dmxin",    HT_DMX,       0, NULL},
222 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat},
223#ifdef ROAR_DEFAULT_OSS_DEV
224 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL},
225#endif
226 {NULL, HT_NONE, 0, NULL},
227};
228
229static void _init_os (void) {
230 memset(&_os, 0, sizeof(_os));
231
232 _os.open  = dlsym(REAL_LIBC, "open");
233 _os.close = dlsym(REAL_LIBC, "close");
234 _os.write = dlsym(REAL_LIBC, "write");
235 _os.read  = dlsym(REAL_LIBC, "read");
236#ifndef IOCTL_IS_ALIAS
237 _os.ioctl = dlsym(REAL_LIBC, "ioctl");
238#endif
239 _os.lseek = dlsym(REAL_LIBC, "lseek");
240 _os.fopen = dlsym(REAL_LIBC, "fopen");
241 _os.dup   = dlsym(REAL_LIBC, "dup");
242 _os.dup2  = dlsym(REAL_LIBC, "dup2");
243}
244
245static void _init_ptr (void) {
246 int i;
247
248 for (i = 0; i < _MAX_POINTER; i++) {
249  _ptr[i].fh = -1;
250 }
251}
252
253static void _init (void) {
254 static int inited = 0;
255
256 if ( !inited ) {
257  _init_os();
258  _init_ptr();
259  inited++;
260 }
261}
262
263static void _find_volume_sid (struct session * session) {
264 int i;
265 int num;
266 int id[ROAR_STREAMS_MAX];
267 struct roar_stream s;
268 char name[1024];
269
270 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
271
272 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
273  return;
274 }
275
276 for (i = 0; i < num; i++) {
277  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
278   continue;
279
280  if ( s.dir != ROAR_DIR_MIXING )
281   continue;
282
283  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
284   continue;
285
286  if ( !strcasecmp(name, "Waveform Mixer") ) {
287   _mix_settings.sid.volume = id[i];
288   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
289   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
290   return;
291  }
292 }
293}
294
295static int _open_dummy (void) {
296 int p[2];
297
298 if ( pipe(p) == -1 )
299  return -1;
300
301 close(p[1]);
302
303 return p[0];
304}
305
306static struct session * _open_session (char * server, char * name) {
307 struct session * ses = &_session;
308 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
309
310 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
311 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
312
313 if ( new_session ) {
314  ses = malloc(sizeof(struct session));
315  if ( ses == NULL )
316   return NULL;
317
318  memset(ses, 0, sizeof(struct session));
319 }
320
321 if ( ses->refc == 0 ) {
322
323  if ( name == NULL )
324   name = getenv("ROAR_OSS_CLIENT_NAME");
325
326  if ( name == NULL )
327   name = "libroaross client";
328
329  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
330   if ( new_session )
331    free(ses);
332
333   return NULL;
334  }
335
336  _find_volume_sid(ses);
337
338  if ( !new_session ) {
339   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
340    ses->refc++;
341  }
342 }
343
344 ses->refc++;
345
346 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
347 return ses;
348}
349
350static void _close_session(struct session * session) {
351 if ( session == NULL )
352  return;
353
354 session->refc--;
355
356 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
357
358 if ( session->refc == 0 ) {
359  roar_disconnect(&(session->con));
360 }
361
362 if ( session != &_session )
363  free(session);
364}
365
366static struct handle * _open_handle(struct session * session) {
367 struct handle * handle;
368
369 ROAR_DBG("_open_handle(session=%p) = ?", session);
370
371 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
372  return NULL;
373
374 memset(handle, 0, sizeof(struct handle));
375
376 handle->refc = 1;
377 handle->session = session;
378
379 if ( session != NULL )
380  session->refc++; // TODO: better warp this
381
382 handle->type = HT_NONE;
383 handle->stream_dir = ROAR_DIR_PLAY;
384 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
385
386 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
387 return handle;
388}
389
390static void _close_handle(struct handle * handle) {
391 int need_close = 0;
392
393 if (handle == NULL)
394  return;
395
396 handle->refc--;
397
398 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
399
400 if ( handle->refc == 0 ) {
401  switch (handle->type) {
402   case HT_VIO:
403     need_close = 1;
404    break;
405   case HT_STREAM:
406     if ( handle->stream_opened )
407      need_close = 1;
408    break;
409  }
410
411  if ( need_close )
412   roar_vio_close(&(handle->stream_vio));
413
414  if ( handle->session != NULL ) {
415   handle->session->refc--;
416
417   _close_session(handle->session);
418  }
419
420  roar_mm_free(handle);
421 }
422}
423
424static struct pointer * _get_pointer_by_fh (int fh) {
425 int i;
426
427 for (i = 0; i < _MAX_POINTER; i++) {
428  if ( _ptr[i].fh == fh )
429   return &(_ptr[i]);
430 }
431
432 return NULL;
433}
434
435static struct pointer * _open_pointer(struct handle * handle) {
436 struct pointer * ret = _get_pointer_by_fh(-1);
437
438 if ( ret == NULL )
439  return NULL;
440
441 if ( (ret->fh = _open_dummy()) == -1 )
442  return NULL;
443
444 ret->handle = handle;
445
446 return ret;
447}
448
449static struct pointer * _attach_pointer(struct handle * handle, int fh) {
450 struct pointer * ret = _get_pointer_by_fh(-1);
451
452 if ( ret == NULL )
453  return NULL;
454
455 if ( (ret->fh = fh) == -1 )
456  return NULL;
457
458 ret->handle = handle;
459
460 handle->refc++;
461
462 return ret;
463}
464
465static void _close_pointer(struct pointer * pointer) {
466 if ( pointer == NULL )
467  return;
468
469 _os.close(pointer->fh);
470
471 pointer->fh = -1;
472
473 _close_handle(pointer->handle);
474}
475
476// -------------------------------------
477// central open function:
478// -------------------------------------
479
480static int _open_file (const char *pathname, int flags) {
481 struct session * session;
482 struct handle  * handle;
483 struct pointer * pointer;
484 struct devices * ptr = NULL;
485 int i;
486
487 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
488
489 for (i = 0; _device_list[i].prefix != NULL; i++) {
490  if ( !strcmp(pathname, _device_list[i].prefix) ) {
491   ptr = &(_device_list[i]);
492  }
493 }
494
495 if ( ptr == NULL )
496  return -2;
497
498 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
499  session = NULL;
500 } else {
501  if ( (session = _open_session(NULL, NULL)) == NULL ) {
502   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
503   return -1;
504  }
505 }
506
507 if ( (handle = _open_handle(session)) == NULL ) {
508  _close_session(session);
509  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
510  return -1;
511 }
512
513 handle->type       = ptr->type;
514 handle->stream_dir = -1;
515
516 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
517  case O_RDONLY:
518    switch (ptr->type) {
519     case HT_WAVEFORM:
520       handle->stream_dir = ROAR_DIR_MONITOR;
521      break;
522     case HT_MIDI:
523       handle->stream_dir = ROAR_DIR_MIDI_OUT;
524      break;
525     case HT_DMX:
526       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
527      break;
528     case HT_MIXER:
529     case HT_STATIC:
530      break;
531     default:
532       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
533       return -1;
534    }
535   break;
536  case O_WRONLY:
537    switch (ptr->type) {
538     case HT_WAVEFORM:
539       handle->stream_dir = ROAR_DIR_PLAY;
540      break;
541     case HT_MIDI:
542       handle->stream_dir = ROAR_DIR_MIDI_IN;
543      break;
544     case HT_DMX:
545       handle->stream_dir = ROAR_DIR_LIGHT_IN;
546      break;
547     case HT_MIXER:
548     case HT_STATIC:
549      break;
550     default:
551       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
552       return -1;
553    }
554   break;
555  case O_RDWR:
556    switch (ptr->type) {
557     case HT_WAVEFORM:
558       handle->stream_dir = ROAR_DIR_BIDIR;
559      break;
560     case HT_MIXER:
561     case HT_STATIC:
562      break;
563     default:
564       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
565       return -1;
566    }
567   break;
568 }
569
570 switch (handle->type) {
571  case HT_WAVEFORM:
572    handle->type = HT_STREAM;
573   break;
574  case HT_MIDI:
575    handle->type = HT_STREAM;
576    handle->stream.info.rate     = 0;
577    handle->stream.info.bits     = ROAR_MIDI_BITS;
578    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
579    handle->stream.info.codec    = ROAR_CODEC_MIDI;
580   break;
581  case HT_DMX:
582    handle->stream.info.rate     = 0;
583    handle->stream.info.bits     = ROAR_LIGHT_BITS;
584    handle->stream.info.channels = 512;
585    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
586   break;
587  case HT_STATIC:
588    handle->userdata.sf.len      = ptr->len;
589    handle->userdata.sf.data     = ptr->userdata;
590   break;
591 }
592
593 if ( (pointer = _open_pointer(handle)) == NULL ) {
594  _close_handle(handle);
595  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
596  return -1;
597 }
598
599 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
600
601 return pointer->fh;
602}
603
604// -------------------------------------
605// open function for streams:
606// -------------------------------------
607
608static int _open_stream (struct handle * handle) {
609  // FIXME: this should be re-written much more cleanly:
610
611 if ( handle == NULL )
612  return -1;
613
614 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
615                                     &(handle->session->con), &(handle->stream),
616                                     handle->stream.info.rate,
617                                     handle->stream.info.channels,
618                                     handle->stream.info.bits,
619                                     handle->stream.info.codec,
620                                     handle->stream_dir
621                                    ) == -1 )
622  return -1;
623
624 handle->stream_opened++;
625
626 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
627
628 return 0;
629}
630
631// -------------------------------------
632// function to parse format:
633// -------------------------------------
634
635static int _ioctl_stream_format (struct handle * handle, int format) {
636 struct roar_audio_info * info = &(handle->stream.info);
637
638 switch (format) {
639  case AFMT_S8:
640    info->bits  = 8;
641    info->codec = ROAR_CODEC_PCM_S_LE;
642   break;
643  case AFMT_U8:
644    info->bits  = 8;
645    info->codec = ROAR_CODEC_PCM_U_LE;
646   break;
647  case AFMT_S16_BE:
648    info->bits  = 16;
649    info->codec = ROAR_CODEC_PCM_S_BE;
650   break;
651  case AFMT_S16_LE:
652    info->bits  = 16;
653    info->codec = ROAR_CODEC_PCM_S_LE;
654   break;
655  case AFMT_U16_BE:
656    info->bits  = 16;
657    info->codec = ROAR_CODEC_PCM_U_BE;
658   break;
659  case AFMT_U16_LE:
660    info->bits  = 16;
661    info->codec = ROAR_CODEC_PCM_U_LE;
662   break;
663#ifdef AFMT_S32_BE
664  case AFMT_S32_BE:
665    info->bits  = 32;
666    info->codec = ROAR_CODEC_PCM_S_BE;
667   break;
668#endif
669#ifdef AFMT_S32_LE
670  case AFMT_S32_LE:
671    info->bits  = 32;
672    info->codec = ROAR_CODEC_PCM_S_LE;
673   break;
674#endif
675  case AFMT_A_LAW:
676    info->bits  = 8;
677    info->codec = ROAR_CODEC_ALAW;
678   break;
679  case AFMT_MU_LAW:
680    info->bits  = 8;
681    info->codec = ROAR_CODEC_MULAW;
682   break;
683#ifdef AFMT_VORBIS
684  case AFMT_VORBIS:
685    info->codec = ROAR_CODEC_OGG_VORBIS;
686   break;
687#endif
688  default:
689    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
690    errno = ENOSYS;
691    return -1;
692   break;
693 }
694
695 return 0;
696}
697
698static inline int _ioctl_stream_format_list (void) {
699 int format = 0;
700
701 format |= AFMT_S8;
702 format |= AFMT_U8;
703
704 format |= AFMT_S16_BE;
705 format |= AFMT_S16_LE;
706
707 format |= AFMT_U16_BE;
708 format |= AFMT_U16_LE;
709
710#ifdef AFMT_S32_BE
711 format |= AFMT_S32_BE;
712#endif
713#ifdef AFMT_S32_LE
714 format |= AFMT_S32_LE;
715#endif
716
717 format |= AFMT_A_LAW;
718 format |= AFMT_MU_LAW;
719
720#ifdef AFMT_VORBIS
721 format |= AFMT_VORBIS;
722#endif
723
724 return format;
725}
726
727// -------------------------------------
728// mixer ioctls:
729// -------------------------------------
730
731static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
732 mixer_info * info;
733 int channels;
734 struct roar_mixer_settings mixer;
735 int o_w    =  0;
736 int o_sid  = -1;
737 int * ip   = vp;
738#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
739 char * name = NULL;
740#endif
741
742#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
743 switch (req) {
744#if 0
745  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
746  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
747  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
748  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
749  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
750  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
751  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
752#endif
753//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
754  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
755  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
756  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
757  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
758  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
759  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
760  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
761  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
762  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
763  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
764  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
765  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
766//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
767  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
768/*
769  case :     name = "";     break;
770  case :     name = "";     break;
771*/
772 }
773 if ( name != NULL ) {
774  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
775  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
776  errno = ENOSYS;
777  return -1;
778 }
779#endif
780
781 switch (req) {
782  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
783  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
784  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
785  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
786  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
787#if 0
788  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
789  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
790  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
791#endif
792  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
793  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
794  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
795  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
796  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
797#if 0
798  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
799  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
800  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
801#endif
802  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
803  case SOUND_MIXER_READ_PCM:
804    o_w = 0;
805    if ( handle->type == HT_STREAM ) {
806     o_sid = roar_stream_get_id(&(handle->stream));
807    } else {
808     o_sid = _mix_settings.sid.pcm;
809    }
810   break;
811  case SOUND_MIXER_WRITE_PCM:
812    o_w = 1;
813    if ( handle->type == HT_STREAM ) {
814     o_sid = roar_stream_get_id(&(handle->stream));
815    } else {
816     o_sid = _mix_settings.sid.pcm;
817    }
818   break;
819 }
820 if ( o_sid != -1 ) {
821  // set/get volume
822  if ( o_w ) {
823   mixer.scale    = OSS_VOLUME_SCALE;
824   mixer.mixer[0] = ( *ip       & 0xFF);
825   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
826   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
827    errno = EIO;
828    return -1;
829   }
830   return 0;
831  } else {
832   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
833    errno = EIO;
834    return -1;
835   }
836   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
837   return 0;
838  }
839 }
840
841 switch (req) {
842  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
843  case SOUND_MIXER_READ_DEVMASK:
844    *ip = 0;
845
846    if ( _mix_settings.sid.volume != -1 )
847     *ip |= SOUND_MASK_VOLUME;
848    if ( _mix_settings.sid.pcm != -1 )
849     *ip |= SOUND_MASK_PCM;
850    if ( _mix_settings.sid.line != -1 )
851     *ip |= SOUND_MASK_LINE;
852    if ( _mix_settings.sid.line1 != -1 )
853     *ip |= SOUND_MASK_LINE1;
854    if ( _mix_settings.sid.line2 != -1 )
855     *ip |= SOUND_MASK_LINE2;
856    if ( _mix_settings.sid.line3 != -1 )
857     *ip |= SOUND_MASK_LINE3;
858    if ( _mix_settings.sid.digital1 != -1 )
859#if 0
860     *ip |= SOUND_MASK_DIGITAL1;
861    if ( _mix_settings.sid.digital2 != -1 )
862     *ip |= SOUND_MASK_DIGITAL2;
863    if ( _mix_settings.sid.digital3 != -1 )
864     *ip |= SOUND_MASK_DIGITAL3;
865#endif
866
867    return 0;
868   break;
869  case SOUND_MIXER_READ_RECMASK:
870  case SOUND_MIXER_READ_RECSRC:
871    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
872    return 0;
873   break;
874  case SOUND_MIXER_WRITE_RECSRC:
875    if ( *ip == SOUND_MASK_VOLUME ) {
876     return  0;
877    } else {
878     errno = ENOTSUP;
879     return -1;
880    }
881   break;
882  case SOUND_MIXER_READ_CAPS:
883    *ip = 0;
884    return 0;
885   break;
886  case SOUND_MIXER_INFO:
887    info = vp;
888    memset(info, 0, sizeof(*info));
889    strcpy(info->id, "RoarAudio");
890    strcpy(info->name, "RoarAudio");
891    return 0;
892   break;
893 }
894
895 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
896// _os.ioctl(-1, req, ip);
897 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
898 errno = ENOSYS;
899 return -1;
900}
901
902// -------------------------------------
903// buffer size calculation:
904// -------------------------------------
905
906static size_t _get_stream_buffersize (struct handle * handle) {
907 if ( handle->stream_buffersize )
908  return handle->stream_buffersize;
909
910 return handle->stream_buffersize = handle->stream.info.rate     *
911                                    handle->stream.info.channels *
912                                    handle->stream.info.bits     / 800;
913}
914
915// -------------------------------------
916// emulated functions follow:
917// -------------------------------------
918
919int     open(const char *pathname, int flags, ...) {
920 int     ret;
921 mode_t  mode = 0;
922 va_list args;
923
924 _init();
925
926 if ( pathname == NULL ) {
927  errno = EFAULT;
928  return -1;
929 }
930
931 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
932 ret = _open_file(pathname, flags);
933
934 switch (ret) {
935  case -2:       // continue as normal, use _op.open()
936   break;
937  case -1:       // pass error to caller
938    return -1;
939   break;
940  default:       // return successfully opened pointer to caller
941    return ret;
942   break;
943 }
944
945 if (flags & O_CREAT) {
946  va_start(args, flags);
947  mode = va_arg(args, mode_t);
948  va_end(args);
949 }
950
951 return _os.open(pathname, flags, mode);
952}
953
954int     close(int fd) {
955 struct pointer * pointer;
956 _init();
957
958 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
959  _close_pointer(pointer);
960  return 0;
961 }
962
963 return _os.close(fd);
964}
965
966ssize_t write(int fd, const void *buf, size_t count) {
967 struct roar_roardmx_message roardmxmsg;
968 struct pointer * pointer;
969 ssize_t ret;
970 size_t i;
971
972 _init();
973
974 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
975  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
976  switch (pointer->handle->type) {
977   case HT_STREAM: // handle stream specific stuff
978     if ( pointer->handle->stream_opened == 0 ) {
979      if ( _open_stream(pointer->handle) == -1 ) {
980       errno = EIO;
981       return -1;
982      }
983     }
984   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
985     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
986     if ( ret > 0 )
987      pointer->handle->writec += ret;
988     return ret;
989    break;
990   case HT_DMX: // DMX need specal handling as we need to convert the protocol
991     if ( pointer->handle->stream_opened == 0 ) {
992      if ( _open_stream(pointer->handle) == -1 ) {
993       errno = EIO;
994       return -1;
995      }
996     }
997     if ( count > 0 ) {
998      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
999       errno = EIO;
1000       return -1;
1001      }
1002      for (i = 0; i < count; i++) {
1003       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1004#ifdef EMSGSIZE
1005        errno = EMSGSIZE;
1006#else
1007        errno = EIO;
1008#endif
1009        return -1;
1010       }
1011      }
1012      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1013       errno = EIO;
1014       return -1;
1015      }
1016     }
1017     pointer->handle->pos += count;
1018     return count;
1019    break;
1020   default: // we don't know what to do with other types
1021     errno = EINVAL;
1022     return -1;
1023    break;
1024  }
1025 }
1026
1027 return _os.write(fd, buf, count);
1028}
1029
1030ssize_t read(int fd, void *buf, size_t count) {
1031 struct pointer * pointer;
1032 ssize_t ret;
1033
1034 _init();
1035
1036 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1037  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1038
1039  switch (pointer->handle->type) {
1040   case HT_STREAM:
1041     if ( pointer->handle->stream_opened == 0 ) {
1042      if ( _open_stream(pointer->handle) == -1 ) {
1043       errno = EIO;
1044       return -1;
1045      }
1046     }
1047   case HT_VIO:
1048     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1049     if ( ret > 0 )
1050      pointer->handle->readc += ret;
1051     return ret;
1052    break;
1053   case HT_STATIC:
1054     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1055     ret = pointer->handle->pos + count; // calc the end of the read
1056
1057     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1058      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1059     }
1060
1061     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1062     pointer->handle->pos += count;
1063     return count;
1064    break;
1065   default:
1066     errno = EINVAL;
1067     return -1;
1068    break;
1069  }
1070 }
1071
1072 return _os.read(fd, buf, count);
1073}
1074
1075off_t lseek(int fildes, off_t offset, int whence) {
1076 struct pointer * pointer;
1077 ssize_t tmp;
1078
1079 _init();
1080
1081 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1082  switch (pointer->handle->type) {
1083   case HT_DMX:
1084     switch (whence) {
1085      case SEEK_SET:
1086        pointer->handle->pos  = offset;
1087       break;
1088      case SEEK_CUR:
1089        pointer->handle->pos += offset;
1090       break;
1091      case SEEK_END:
1092      default:
1093        errno = EINVAL;
1094        return -1;
1095       break;
1096     }
1097     return pointer->handle->pos;
1098    break;
1099   case HT_VIO:
1100     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1101    break;
1102   case HT_STATIC:
1103     switch (whence) {
1104      case SEEK_SET:
1105        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1106         errno = EINVAL;
1107         return -1;
1108        }
1109        pointer->handle->pos  = offset;
1110       break;
1111      case SEEK_CUR:
1112        tmp = pointer->handle->pos + offset;
1113        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1114         errno = EINVAL;
1115         return -1;
1116        }
1117        pointer->handle->pos = tmp;
1118       break;
1119      case SEEK_END:
1120        tmp = pointer->handle->userdata.sf.len + offset;
1121        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1122         errno = EINVAL;
1123         return -1;
1124        }
1125        pointer->handle->pos = tmp;
1126       break;
1127      default:
1128        errno = EINVAL;
1129        return -1;
1130       break;
1131     }
1132    break;
1133   default:
1134     errno = EINVAL;
1135     return -1;
1136    break;
1137  }
1138 }
1139
1140 return _os.lseek(fildes, offset, whence);
1141}
1142
1143IOCTL() {
1144 map_args;
1145 struct pointer * pointer;
1146 struct handle  * handle;
1147 int * ip = NULL;
1148 size_t tmp;
1149 audio_buf_info * bi;
1150 count_info     * ci;
1151#ifdef __FIXME__
1152 char * nosys_reqname = NULL;
1153#endif
1154#ifdef va_argp
1155 va_list args;
1156#endif
1157
1158 _init();
1159
1160// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1161
1162#ifdef va_argp
1163 va_start (args, ioctl_lastarg);
1164 argp = va_arg (args, void *);
1165 va_end (args);
1166#endif
1167
1168// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1169
1170 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1171  ip = argp;
1172//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1173#ifdef __FIXME__
1174  switch ((handle = pointer->handle)->type) {
1175   case SOUND_PCM_READ_RATE: nosys_reqname = "SOUND_PCM_READ_RATE"; break;
1176   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1177   case SOUND_PCM_READ_BITS: nosys_reqname = "SOUND_PCM_READ_BITS"; break;
1178   case SOUND_PCM_READ_FILTER: nosys_reqname = "SOUND_PCM_READ_FILTER"; break;
1179   case SNDCTL_COPR_RESET: nosys_reqname = "SNDCTL_COPR_RESET"; break;
1180   case SNDCTL_COPR_LOAD: nosys_reqname = "SNDCTL_COPR_LOAD"; break;
1181   case SNDCTL_COPR_HALT: nosys_reqname = "SNDCTL_COPR_HALT"; break;
1182   case SNDCTL_COPR_RDATA: nosys_reqname = "SNDCTL_COPR_RDATA"; break;
1183   case SNDCTL_COPR_RCODE: nosys_reqname = "SNDCTL_COPR_RCODE"; break;
1184   case SNDCTL_COPR_WDATA: nosys_reqname = "SNDCTL_COPR_WDATA"; break;
1185   case SNDCTL_COPR_WCODE: nosys_reqname = "SNDCTL_COPR_WCODE"; break;
1186   case SNDCTL_COPR_RUN: nosys_reqname = "SNDCTL_COPR_RUN"; break;
1187   case SNDCTL_COPR_SENDMSG: nosys_reqname = "SNDCTL_COPR_SENDMSG"; break;
1188   case SNDCTL_COPR_RCVMSG: nosys_reqname = "SNDCTL_COPR_RCVMSG"; break;
1189   case SNDCTL_DSP_GETCAPS: nosys_reqname = "SNDCTL_DSP_GETCAPS"; break;
1190   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1191/*
1192   case : nosys_reqname = ""; break;
1193   case : nosys_reqname = ""; break;
1194   case : nosys_reqname = ""; break;
1195*/
1196  }
1197#endif
1198  switch ((handle = pointer->handle)->type) {
1199   case HT_STREAM:
1200     switch (__request) {
1201      case SNDCTL_DSP_RESET:
1202      case SNDCTL_DSP_POST:
1203      case SNDCTL_DSP_SYNC: // ignore for the moment.
1204      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1205      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1206        return 0;
1207       break;
1208      case SNDCTL_DSP_SPEED:
1209        handle->stream.info.rate = *ip;
1210        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1211        return 0;
1212       break;
1213      case SNDCTL_DSP_CHANNELS:
1214        handle->stream.info.channels = *ip;
1215        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1216        return 0;
1217       break;
1218      case SNDCTL_DSP_STEREO:
1219        handle->stream.info.channels = *ip ? 2 : 1;
1220        return 0;
1221       break;
1222      case SNDCTL_DSP_GETBLKSIZE:
1223        *ip = _get_stream_buffersize(handle);
1224        return 0;
1225       break;
1226      case SNDCTL_DSP_SETFMT:
1227        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1228        return _ioctl_stream_format(handle, *ip);
1229       break;
1230      case SNDCTL_DSP_GETFMTS:
1231//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1232        *ip = _ioctl_stream_format_list();
1233        return 0;
1234       break;
1235      case SNDCTL_DSP_GETOSPACE:
1236      case SNDCTL_DSP_GETISPACE:
1237        bi = argp;
1238        memset(bi, 0, sizeof(*bi));
1239        bi->bytes      = _get_stream_buffersize(handle);
1240        bi->fragments  = 1;
1241        bi->fragsize   = bi->bytes;
1242        bi->fragstotal = 1;
1243        return 0;
1244       break;
1245      case SNDCTL_DSP_GETOPTR:
1246        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1247        ci = argp;
1248        memset(ci, 0, sizeof(*ci));
1249        ci->bytes  = handle->writec;
1250        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1251        ci->ptr    = ci->bytes % tmp;
1252        return 0;
1253       break;
1254      case SNDCTL_DSP_GETIPTR:
1255        ci = argp;
1256        memset(ci, 0, sizeof(*ci));
1257        ci->bytes  = handle->readc;
1258        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1259        ci->ptr    = ci->bytes % tmp;
1260        return 0;
1261       break;
1262#ifdef SNDCTL_DSP_GETPLAYVOL
1263      case SNDCTL_DSP_GETPLAYVOL:
1264        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1265       break;
1266#endif
1267#ifdef SNDCTL_DSP_SETPLAYVOL
1268      case SNDCTL_DSP_SETPLAYVOL:
1269        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1270       break;
1271#endif
1272      default:
1273#ifdef __FIXME__
1274        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1275#else
1276        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1277#endif
1278        errno = ENOSYS;
1279        return -1;
1280     }
1281    break;
1282   case HT_MIXER:
1283     return _ioctl_mixer(handle, __request, argp);
1284    break;
1285   default:
1286     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1287     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1288     errno = EINVAL;
1289     return -1;
1290    break;
1291  }
1292 }
1293
1294#ifdef IOCTL_IS_ALIAS
1295 errno = ENOSYS;
1296 return -1;
1297#else
1298 return _os.ioctl(__fd, __request, argp);
1299#endif
1300}
1301
1302int dup(int oldfd) {
1303 struct pointer * pointer;
1304 int ret;
1305
1306 _init();
1307
1308 ret = _os.dup(oldfd);
1309
1310 if (ret == -1)
1311  return -1;
1312
1313 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1314  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1315   _os.close(ret);
1316   return -1;
1317  }
1318 }
1319
1320 return ret;
1321}
1322
1323int dup2(int oldfd, int newfd) {
1324 struct pointer * pointer;
1325 int ret;
1326
1327 _init();
1328
1329 ret = _os.dup2(oldfd, newfd);
1330
1331 if (ret == -1)
1332  return -1;
1333
1334 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1335  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1336   _os.close(ret);
1337   return -1;
1338  }
1339 }
1340
1341 return ret;
1342}
1343
1344// -------------------------------------
1345// emulated stdio functions follow:
1346// -------------------------------------
1347
1348//roar_vio_to_stdio
1349
1350static int _vio_close    (struct roar_vio_calls * vio) {
1351 int ret = 0;
1352
1353 if ( roar_vio_get_fh(vio) != -1 )
1354  ret = close(roar_vio_get_fh(vio));
1355
1356 roar_mm_free(vio);
1357
1358 return ret;
1359}
1360
1361FILE *fopen(const char *path, const char *mode) {
1362 struct roar_vio_calls * vio;
1363 struct pointer * pointer;
1364 FILE  * fr;
1365 int     ret;
1366 int     r = 0, w = 0;
1367 int     flags = 0;
1368 int     i;
1369 register char c;
1370
1371 _init();
1372
1373 if ( path == NULL || mode == NULL ) {
1374  errno = EFAULT;
1375  return NULL;
1376 }
1377
1378 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
1379
1380 for (i = 0; (c = mode[i]) != 0; i++) {
1381  switch (c) {
1382   case 'r': r = 1; break;
1383   case 'w': w = 1; break;
1384   case 'a': w = 1; break;
1385   case '+':
1386     r = 1;
1387     w = 1;
1388    break;
1389  }
1390 }
1391
1392 if ( r && w ) {
1393  flags = O_RDWR;
1394 } else if ( r ) {
1395  flags = O_RDONLY;
1396 } else if ( w ) {
1397  flags = O_WRONLY;
1398 } else {
1399  errno = EINVAL;
1400  return NULL;
1401 }
1402
1403 ret = _open_file(path, flags);
1404
1405 switch (ret) {
1406  case -2:       // continue as normal, use _op.open()
1407   break;
1408  case -1:       // pass error to caller
1409    return NULL;
1410   break;
1411  default:       // return successfully opened pointer to caller
1412#if 0
1413    if ( (pointer = _get_pointer_by_fh(ret)) != NULL ) {
1414     if ( (fr = roar_vio_to_stdio(&(pointer->handle->stream_vio), flags)) == NULL ) {
1415      errno = EIO;
1416      return NULL;
1417     } else {
1418      return fr;
1419     }
1420    } else {
1421     errno = EIO;
1422     return NULL;
1423    }
1424#endif
1425    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
1426     return NULL; // errno should be set correctly by roar_mm_malloc().
1427    }
1428
1429    roar_vio_init_calls(vio);  // TODO: add error handling.
1430    roar_vio_set_fh(vio, ret); // TODO: add error handling.
1431    vio->close = _vio_close;
1432    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
1433     _vio_close(vio);
1434     errno = EIO;
1435     return NULL;
1436    } else {
1437     return fr;
1438    }
1439   break;
1440 }
1441
1442 return _os.fopen(path, mode);
1443}
1444
1445#endif
1446
1447//ll
Note: See TracBrowser for help on using the repository browser.