/* This file is part of the Q programming system.
The Q programming system is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
The Q programming system is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if defined (HAVE_CONFIG_H)
# include "config.h"
#endif
/* system headers */
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <math.h>
/* check for standard C headers */
#if STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr (), *strrchr ();
#endif
#ifdef HAVE_MALLOC_H
#include <stdlib.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include <sys/types.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef WIN32
#include <windows.h>
#endif
#include <dxl.h>
#include <libq.h>
#ifdef DMALLOC
#include <dmalloc.h>
#endif
MODULE(dxl)
#ifndef HAVE_STRDUP
static char *strdup(char *s)
{
char *t;
return ((t=malloc(strlen(s)+1))?strcpy(t, s):NULL);
}
#endif
/* handle SIGINT and SIGTERM */
#if RETSIGTYPE == void
#define SIGHANDLER_RETURN(status) return
#else
#define SIGHANDLER_RETURN(status) return status
#endif
#ifdef MUST_REINSTALL_SIGHANDLERS
#define SIGHANDLER_RESTORE(sig,handler) syssignal(sig,handler)
#else
#define SIGHANDLER_RESTORE(sig,handler) /* nop */
#endif
typedef RETSIGTYPE (*sighandler_t)(int);
static sighandler_t syssignal(sig, handler)
int sig;
sighandler_t handler;
{
#ifdef HAVE_POSIX_SIGNALS
struct sigaction new_action, old_action;
new_action.sa_handler = handler;
sigemptyset(&new_action.sa_mask);
sigemptyset(&old_action.sa_mask);
new_action.sa_flags = 0;
sigaction(sig, &new_action, &old_action);
return old_action.sa_handler;
#else
return signal(sig, handler);
#endif
}
static volatile int brkflag = 0;
static sighandler_t int_handler = NULL, term_handler = NULL,
hup_handler = NULL;
static RETSIGTYPE break_handler(int sig)
{
if (sig == SIGINT && int_handler) int_handler(sig);
if (sig == SIGTERM && term_handler) term_handler(sig);
#ifdef SIGHUP
if (sig == SIGHUP && hup_handler) hup_handler(sig);
#endif
SIGHANDLER_RESTORE(sig, break_handler);
brkflag = 1;
SIGHANDLER_RETURN(0);
}
/* take a short sleep (approx 1/100 secs) */
static void sleep_some(void)
{
#ifdef WIN32
Sleep(10);
#else
#ifdef HAVE_NANOSLEEP
struct timespec req;
req.tv_sec = 0; req.tv_nsec = 10000000;
nanosleep(&req, NULL);
#else
#ifdef HAVE_USLEEP
usleep(10000);
#else
sleep(1);
#endif
#endif
#endif
}
/* DXHandle struct */
typedef struct qentry {
char *s, *t;
struct qentry *next;
} qentry;
typedef struct {
volatile int rdy; /* lost connection indicator */
DXLConnection *conn; /* DXLink connection */
qentry *head, *tail; /* message queue */
} DXLHandle;
/* message queue operations */
static void initqueue(DXLHandle *h)
{
h->head = h->tail = NULL;
}
static void freequeue(DXLHandle *h)
{
qentry *head, *next;
for (head = h->head; head; head = next) {
next = head->next;
if (head->s) free(head->s);
if (head->t) free(head->t);
free(head);
}
h->head = h->tail = NULL;
}
static int emptyqueue(DXLHandle *h)
{
return h->head == NULL;
}
static char *head_s(DXLHandle *h)
{
if (h->head)
return h->head->s;
else
return NULL;
}
static char *head_t(DXLHandle *h)
{
if (h->head)
return h->head->t;
else
return NULL;
}
static void enqueue(DXLHandle *h, char *s, char *t)
{
qentry *next = malloc(sizeof(qentry));
if (!next) {
/* FIXME: do some more appropriate error handling here */
h->rdy = 0;
return;
}
next->s = s;
next->t = t;
next->next = NULL;
if (h->head) {
h->tail->next = next;
h->tail = next;
} else
h->head = h->tail = next;
}
static void dequeue(DXLHandle *h)
{
qentry *next;
if (!h->head) return;
next = h->head->next;
free(h->head);
if (next)
h->head = next;
else
h->head = h->tail = NULL;
}
/* check handle for validity */
static int valid(DXLHandle *h)
{
if (h->rdy)
if (h->conn)
return 1;
else
return (h->rdy = 0);
else if (h->conn) {
/* close the connection on our side */
DXLCloseConnection(h->conn);
h->conn = NULL;
freequeue(h);
return 0;
} else {
freequeue(h);
return 0;
}
}
/* close a DXLHandle structure */
static void close_handle(DXLHandle *h)
{
h->rdy = 0;
valid(h);
}
/* message handlers */
static void conn_lost(DXLConnection *conn, void *data)
{
DXLHandle *h = data;
h->rdy = 0;
}
static void err_handler(DXLConnection *conn, const char *msg, void *data)
{
DXLHandle *h = data;
enqueue(h, NULL, strdup(msg));
}
static void val_handler(DXLConnection *conn, const char *label,
const char *value, void *data)
{
DXLHandle *h = data;
char *s = strdup(label), *t = strdup(value);
if (s && t)
enqueue(h, s, t);
else {
if (s) {
free(s); h->head->s = NULL;
}
if (t) {
free(t); h->head->t = NULL;
}
}
}
DESTRUCTOR(dxl,DXLHandle,v)
{
DXLHandle *h = v;
close_handle(h);
free(h);
}
FUNCTION(dxl,dxl_start,argc,argv)
{
char *s;
if (argc == 1 && isstr(argv[0], &s)) {
DXLHandle *h;
if ((h = (DXLHandle*)malloc(sizeof(DXLHandle)))) {
h->conn = DXLStartDX(s, NULL);
if (h->conn) {
h->rdy = 1;
initqueue(h);
DXLSetBrokenConnectionCallback(h->conn, conn_lost, h);
DXLSetErrorHandler(h->conn, err_handler, h);
return mkobj(type(DXLHandle), h);
} else {
free(h);
return __FAIL;
}
} else
return __ERROR;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_close,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
close_handle(h);
return mkvoid;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_exit,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = DXLExitDX(h->conn);
h->conn = NULL;
close_handle(h);
return (res == OK)?mkvoid:__FAIL;
} else {
return __FAIL;
}
} else
return __FAIL;
}
FUNCTION(dxl,dxl_load,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = DXLLoadVisualProgram(h->conn, s);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_load_macro,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = DXLLoadMacroFile(h->conn, s);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_load_script,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = exDXLLoadScript(h->conn, s);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_load_config,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = uiDXLLoadConfig(h->conn, s);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = DXLSend(h->conn, s);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_begin_macro,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = exDXLBeginMacroDefinition(h->conn, s);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_end_macro,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = exDXLEndMacroDefinition(h->conn);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_exec_once,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = DXLExecuteOnce(h->conn);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_exec_on_change,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = DXLExecuteOnChange(h->conn);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_exec_once_named,argc,argv)
{
DXLHandle *h;
char *s, *t;
if (argc == 3 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
expr x, x1, x2;
long i;
int n;
for (n = 0, x = argv[2]; iscons(x, &x1, &x2) && isstr(x1, &t);
x = x2, n++)
if (n == INT_MAX-1) {
return __ERROR;
}
if (isnil(x)) {
char **a = (char**)malloc((n+1)*sizeof(char*));
if (a) {
int res;
for (n = 0, x = argv[2]; iscons(x, &x1, &x2) && isstr(x1, &t);
x = x2, n++)
a[n] = t;
a[n] = NULL;
res = exDXLExecuteOnceNamedWithArgsV(h->conn, s, a);
free(a);
return (res == OK)?mkvoid:__FAIL;
} else {
return __ERROR;
}
} else
return __FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_exec_on_change_named,argc,argv)
{
DXLHandle *h;
char *s, *t;
if (argc == 3 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
expr x, x1, x2;
long i;
int n;
for (n = 0, x = argv[2]; iscons(x, &x1, &x2) && isstr(x1, &t);
x = x2, n++)
if (n == INT_MAX-1) {
return __ERROR;
}
if (isnil(x)) {
char **a = (char**)malloc((n+1)*sizeof(char*));
if (a) {
int res;
for (n = 0, x = argv[2]; iscons(x, &x1, &x2) && isstr(x1, &t);
x = x2, n++)
a[n] = t;
a[n] = NULL;
res = exDXLExecuteOnChangeNamedWithArgsV(h->conn, s, a);
free(a);
return (res == OK)?mkvoid:__FAIL;
} else {
return __ERROR;
}
} else
return __FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_end_exec,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = DXLEndExecution(h->conn);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_end_exec_on_change,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = DXLEndExecuteOnChange(h->conn);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_seq_ctl,argc,argv)
{
static int seq_loop_off, seq_loop_on, seq_palindrome_off,
seq_palindrome_on, seq_play_backward, seq_play_forward, seq_step,
seq_pause, seq_stop;
static int init = 0;
DXLHandle *h;
if (!init) {
init = 1;
seq_loop_off = sym(seq_loop_off);
seq_loop_on = sym(seq_loop_on);
seq_palindrome_off = sym(seq_palindrome_off);
seq_palindrome_on = sym(seq_palindrome_on);
seq_play_backward = sym(seq_play_backward);
seq_play_forward = sym(seq_play_forward);
seq_step = sym(seq_step);
seq_pause = sym(seq_pause);
seq_stop = sym(seq_stop);
}
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res;
if (exprsym(argv[1]) == seq_step)
res = DXLSequencerCtl(h->conn, SeqStep);
else if (exprsym(argv[1]) == seq_pause)
res = DXLSequencerCtl(h->conn, SeqPause);
else if (exprsym(argv[1]) == seq_stop)
res = DXLSequencerCtl(h->conn, SeqStop);
else if (exprsym(argv[1]) == seq_loop_off)
res = DXLSequencerCtl(h->conn, SeqLoopOff);
else if (exprsym(argv[1]) == seq_loop_on)
res = DXLSequencerCtl(h->conn, SeqLoopOn);
else if (exprsym(argv[1]) == seq_palindrome_off)
res = DXLSequencerCtl(h->conn, SeqPalindromeOff);
else if (exprsym(argv[1]) == seq_palindrome_on)
res = DXLSequencerCtl(h->conn, SeqPalindromeOn);
else if (exprsym(argv[1]) == seq_play_backward)
res = DXLSequencerCtl(h->conn, SeqPlayBackward);
else if (exprsym(argv[1]) == seq_play_forward)
res = DXLSequencerCtl(h->conn, SeqPlayForward);
else
return __FAIL;
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_render_mode,argc,argv)
{
DXLHandle *h;
char *s;
long n;
if (argc == 3 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s) && isint(argv[2], &n) && n >= 0 && n <= 1) {
if (valid(h)) {
DXLError res = uiDXLSetRenderMode(h->conn, s, n);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_reset,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (valid(h)) {
DXLError res = uiDXLResetServer(h->conn);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
static int chk(DXLHandle *h)
{
brkflag = 0;
while (!brkflag && valid(h) && DXLIsMessagePending(h->conn))
DXLHandlePendingMessages(h->conn);
return !brkflag && valid(h);
}
FUNCTION(dxl,dxl_ready,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
chk(h);
if (brkflag)
return __FAIL;
else {
int res = valid(h);
return res?mktrue:mkfalse;
}
} else
return __FAIL;
}
FUNCTION(dxl,dxl_busy,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (chk(h)) {
int status;
if (DXLGetExecutionStatus(h->conn, &status) == OK) {
return status?mktrue:mkfalse;
} else
return __FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_wait,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
int status;
while (chk(h) && DXLGetExecutionStatus(h->conn, &status) == OK &&
status) {
release_lock();
sleep_some();
acquire_lock();
}
if (brkflag)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_check,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
if (chk(h)) {
int res = emptyqueue(h);
return res?mkfalse:mktrue;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_input,argc,argv)
{
DXLHandle *h;
char *s, *t;
if (argc == 3 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s) && isstr(argv[2], &t)) {
if (valid(h)) {
DXLError res = DXLSetValue(h->conn, s, t);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_output,argc,argv)
{
DXLHandle *h;
char *s;
if (argc == 2 && isobj(argv[0], type(DXLHandle), (void**)&h) &&
isstr(argv[1], &s)) {
if (valid(h)) {
DXLError res = DXLSetValueHandler(h->conn, s, val_handler, h);
return (res == OK)?mkvoid:__FAIL;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(dxl,dxl_read,argc,argv)
{
DXLHandle *h;
if (argc == 1 && isobj(argv[0], type(DXLHandle), (void**)&h)) {
while (chk(h) && emptyqueue(h)) {
release_lock();
sleep_some();
acquire_lock();
}
if (emptyqueue(h))
return __FAIL;
else if (!head_s(h) && !head_t(h)) {
dequeue(h);
return __ERROR;
} else {
expr x;
if (head_s(h))
x = mktuplel(2, mkstr(head_s(h)), mkstr(head_t(h)));
else
x = mkapp(mksym(sym(dxl_error)), mkstr(head_t(h)));
dequeue(h);
if (x)
return x;
else
return __ERROR;
}
} else
return __FAIL;
}
INIT(dxl)
{
int_handler = syssignal(SIGINT, break_handler);
term_handler = syssignal(SIGTERM, break_handler);
#ifdef SIGHUP
hup_handler = syssignal(SIGHUP, break_handler);
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1