/*
 * msgq.c -- Message Queueing Routines
 *
 * Copyright 1998, John E. Stone
 *                 j.stone@acm.org
 *                 johns@cs.umr.edu
 *
 * $Id: msgq.c,v 1.12 1998/02/18 02:19:19 johns Exp $
 *
 */



#ifdef POSIXQUEUES

#define _POSIX_SOURCE 2
#define _POSIX_C_SOURCE 199506L

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <errno.h>
#include <sys/errno.h>
#include <mqueue.h>

#include "seq.h"

#define MSGQ_PRIVATE
#include "msgq.h"



static char * midiqname(int msgqtype) {
  switch(msgqtype) {
    case MIDIQ_OUT :
      return QNAME_OUT;
    case MIDIQ_IN : 
      return QNAME_IN;
  }
  return NULL;
}

QHandle midiq_create(int msgqtype) {
  msgqueue * q;
  char * qname;

  qname = midiqname(msgqtype);
  if (qname == NULL)
    return NULL;

  if ((q = (msgqueue *) malloc(sizeof(msgqueue))) == NULL)
    return NULL;

  /* Setup MIDI event queue */
  mq_unlink(qname);

  q->attr.mq_flags = 0;
  q->attr.mq_maxmsg = 256;
  q->attr.mq_msgsize = sizeof(MidiIOEvent);

  /* make the queue writable by anyone */
  umask(0000);
  if ((q->q=mq_open(qname, O_RDWR | O_CREAT, 0777, &q->attr))==(mqd_t) -1) {
    umask(0077);
    free(q);
    return NULL;
  }
  umask(0077);

  return q;
}



QHandle midiq_open(int msgqtype) {
  msgqueue * q;
  char * qname;

  qname = midiqname(msgqtype);
  if (qname == NULL)
    return NULL;

  if ((q = (msgqueue *) malloc(sizeof(msgqueue))) == NULL)
    return NULL;

  if ((q->q=mq_open(qname, O_RDWR, 0777, &q->attr))==(mqd_t) -1) {
    free(q);
    return NULL;
  }

  q->nonblock = 0;

  return q;
}


int midiq_read(QHandle voidhandle, MidiIOEvent * ev) {
  msgqueue * q = voidhandle;
  return mq_receive(q->q, (char *) ev, sizeof(MidiIOEvent), NULL);
}


int midiq_write(QHandle voidhandle, MidiIOEvent * ev, int priority) {
  msgqueue * q = voidhandle;
  int rc;

  rc = mq_send(q->q, (char *) ev, sizeof(MidiIOEvent), priority);

  while ((rc == -1) && (errno == EINTR)) { 
    rc = mq_send(q->q, (char *) ev, sizeof(MidiIOEvent), priority);
  }

  return rc;
}

void midiq_set_nonblock(QHandle voidhandle) {
  msgqueue * q = voidhandle;
  mq_getattr(q->q, &q->attr);
  q->attr.mq_flags |= O_NONBLOCK;
  mq_setattr(q->q, &q->attr, NULL);
  q->nonblock = 1;
}

void midiq_close(QHandle voidhandle) {
  msgqueue * q = voidhandle;
  mq_close(q);
  free(q);
}

void midiq_delete(QHandle voidhandle, int msgqtype) {
  msgqueue * q = voidhandle;
  char * qname;

  mq_close(q);
  free(q);

  qname = midiqname(msgqtype);
  if (qname == NULL)
    return;
  mq_unlink(qname);
}

#endif





#ifdef SYSVQUEUES

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <errno.h>
#include <sys/errno.h>
#include "seq.h"

#define MSGQ_PRIVATE
#include "msgq.h"

#ifndef MSG_R 
#define MSG_R 0400
#endif
#ifndef MSG_W 
#define MSG_W 0200
#endif

static int midiqnum(int msgqtype) {
  switch(msgqtype) {
    case MIDIQ_OUT :
      return QNUM_OUT;
    case MIDIQ_IN : 
      return QNUM_IN;
  }
  return 0;
}

QHandle midiq_create(int msgqtype) {
  msgqueue * q;
  int qnum;

  qnum = midiqnum(msgqtype);
  if (qnum == 0) 
    return NULL;

  if ((q = (msgqueue *) malloc(sizeof(msgqueue))) == NULL)
    return NULL;

  q->q = msgget(qnum, (MSG_R | MSG_W) | 
                      ((MSG_R | MSG_W) >> 3) | 
                      ((MSG_R | MSG_W) >> 6) |
                      IPC_CREAT );
  
  if (q->q == -1) {
    free(q);
    return NULL;
  } 

  return q;
}

QHandle midiq_open(int msgqtype) {
  msgqueue * q;
  int qnum;

  qnum = midiqnum(msgqtype);
  if (qnum == 0) 
    return NULL;

  if ((q = (msgqueue *) malloc(sizeof(msgqueue))) == NULL)
    return NULL;

  q->q = msgget(qnum, (MSG_R | MSG_W) | 
                      ((MSG_R | MSG_W) >> 3) | 
                      ((MSG_R | MSG_W) >> 6) );
  
  if (q->q == -1) {
    free(q);
    return NULL;
  } 

  q->nonblock = 0;

  return q;
}


int midiq_read(QHandle voidhandle, MidiIOEvent * ev) {
  msgqueue * q = voidhandle; 
  MidiIOEvent newev;
  int rc;

  /* XXX: Weird stuff happens when we receive right into ev */
  /*      Something seems to be wrong with the calculation of sizeof */
  /*      probably need to use lint on this code a bit */

  rc = msgrcv(q->q, (void *) &newev, sizeof(MidiIOEvent), 0, q->nonblock); 
  *ev = newev;
  return rc;
}

int midiq_write(QHandle voidhandle, MidiIOEvent * ev, int priority) {
  msgqueue * q = voidhandle; 
  int rc;

  ev->mtype = priority;
  rc = msgsnd(q->q, (void *) ev, sizeof(MidiIOEvent), 0); 
  while ((rc == -1) && (errno == EINTR)) { 
    rc = msgsnd(q->q, (void *) ev, sizeof(MidiIOEvent), 0); 
  }

  return rc;
}

void midiq_set_nonblock(QHandle voidhandle) {
  msgqueue * q = voidhandle;
  q->nonblock = IPC_NOWAIT;  
}

void midiq_close(QHandle voidhandle) {
  msgqueue * q = voidhandle;
  free(q);
}

void midiq_delete(QHandle voidhandle, int msgqtype) {
  msgqueue * q = voidhandle;

  msgctl(q->q, IPC_RMID, NULL);
  free(q);
}

#endif

