The unified diff between revisions [a7f61676..] and [43bb367e..] is displayed below. It can also be downloaded as a raw diff.

#
# old_revision [a7f61676c8d04ecf082be8ae39a40b4e7bba3462]
# new_revision [43bb367e69d2a944206fd7f641ce73111e4bb780]
#
# add_file "src/lsi/cmdsocket.c"
#  content [855bbabd21448d3ac37ff460a412a951df7d226a]
# 
# add_file "src/lsi/cmdsocket.h"
#  content [dd5bddfcec81de17a358ae36f8e2626e68430728]
# 
# patch "src/lsc/codegen.c"
#  from [54841dc0395a35f38eeef2e81231366c4fed3015]
#    to [eadf986764263a936e4e1daa589e245ccee66212]
# 
# patch "src/lsc/lexer.l"
#  from [c84e522ab7268008c572c8d1670438471d7287e1]
#    to [88be4de3325822fc6a95e81cc8c615a6c70078bf]
# 
# patch "src/lsi/Makefile"
#  from [4d4540b4f92126f25999c11b07250a886256080b]
#    to [609a07c3b2f5a6dcc33cb70112821fa46ab8ade0]
# 
# patch "src/lsi/abi.h"
#  from [5baace9e64fed6a7cb0eb3af2c188604cca63811]
#    to [2f5c3543b8ced2defbc5a1bea94b29392c7ee5b1]
# 
# patch "src/lsi/abispec"
#  from [b0c3b84bd74ecfc93d8077780b8fd4e7a4bc569c]
#    to [bf8a0325aba2e8dd563c0c9dc0358989f130e20d]
# 
# patch "src/lsi/mouse.c"
#  from [9a2d9211ec57222cfa1f1d2ef9749e698445d0e7]
#    to [410738f63d15db286b591fff6040fcdfe9e1cfa6]
# 
# patch "src/lsi/plugins.c"
#  from [0f20069da015e07f58b0828acdc3644a197dc794]
#    to [d1249e7348b4b02e2405e3374b7e6609ff982875]
# 
# patch "src/lsi/vm.c"
#  from [2f4df836fac21746563e434768e4f832c1ea3e15]
#    to [f74e79e92252eafbcbc81d3ee4ca5e2e3c79f4a9]
# 
# patch "src/lsi/vm.h"
#  from [6ad84b9f243d5acff4ddeca82fc4a96caeb0930a]
#    to [4e84a410186bc2516c890aaedd6b6c3705d1f30a]
#
============================================================
--- src/lsc/codegen.c	54841dc0395a35f38eeef2e81231366c4fed3015
+++ src/lsc/codegen.c	eadf986764263a936e4e1daa589e245ccee66212
@@ -140,7 +140,7 @@ void output_functions_action(struct hash
 		pad = (4 - (len % 4)) % 4;
 		output_int(len+pad);
 		output_int(0);	/* type */
-		output_int(get_label(ptr->value) + 8);
+		output_int(get_label(ptr->value) + 28);
 		output_int(0);	/* nargs */
 		output_string(ptr->name);
 		output_byte(0);	/* terminator */
@@ -1267,6 +1267,7 @@ void output_code(void)
 		if (!lookup_constant_string(x, &abiver))	\
 			printf("%s not defined\n", x);		\
 		output_int(abiver);				\
+		printf("ABIVERSION(%s) = %x\n", x, abiver);				\
 	} while (0)
 
 	pc = (pc + 3) & ~3;	/* Align table */
============================================================
--- src/lsc/lexer.l	c84e522ab7268008c572c8d1670438471d7287e1
+++ src/lsc/lexer.l	88be4de3325822fc6a95e81cc8c615a6c70078bf
@@ -105,8 +105,10 @@ return		return TOKRETURN;
 
 [0-9]+          yylval.Tinteger = atoi(yytext); return NUMBER;
 -[0-9]+         yylval.Tinteger = atoi(yytext); return NUMBER;
-0x[0-9]+        yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER;
--0x[0-9]+       yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER;
+		/* Cater for the possibility that things might be signed or
+		   unsigned. This is horrible and ugly, but might just work. */
+0x[0-9a-fA-F]+        yylval.Tinteger = strtoul(yytext+2, (char **)NULL, 16); return NUMBER;
+-0x[0-9a-fA-F]+       yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER;
 [0-9]+\.[0-9]+	yylval.Treal = atof(yytext); return REAL;
 -[0-9]+\.[0-9]+	yylval.Treal = atof(yytext); return REAL;
 [_a-zA-Z0-9]+	yylval.Tstring = strdup(yytext); return IDENTIFIER;
============================================================
--- src/lsi/Makefile	4d4540b4f92126f25999c11b07250a886256080b
+++ src/lsi/Makefile	609a07c3b2f5a6dcc33cb70112821fa46ab8ade0
@@ -2,8 +2,10 @@ PREFIX?=	/usr/local
 
 PREFIX?=	/usr/local
 
-OBJS=	main.o vm.o plugins.o dmx.o midi.o beatdetect.o fft.o map3d.o mouse.o
-SRCS=	main.c vm.c plugins.c dmx.c midi.c beatdetect.c fft.c map3d.c mouse.c
+OBJS=	main.o vm.o plugins.o dmx.o midi.o beatdetect.o fft.o map3d.o mouse.o \
+	cmdsocket.o
+SRCS=	main.c vm.c plugins.c dmx.c midi.c beatdetect.c fft.c map3d.c mouse.c \
+	cmdsocket.c
 
 OBJS+=	abi.o
 SRCS+=	abi.c
============================================================
--- src/lsi/abi.h	5baace9e64fed6a7cb0eb3af2c188604cca63811
+++ src/lsi/abi.h	2f5c3543b8ced2defbc5a1bea94b29392c7ee5b1
@@ -44,3 +44,7 @@ int vm_intfn_mouse_read(void);
 int vm_intfn_cos(void);
 int vm_intfn_random(void);
 int vm_intfn_mouse_read(void);
+int vm_intfn_cmdsocket_listen(void);
+int vm_intfn_cmdsocket_accept(void);
+int vm_intfn_cmdsocket_read(void);
+int vm_intfn_cmdsocket_prefix(void);
============================================================
--- src/lsi/abispec	b0c3b84bd74ecfc93d8077780b8fd4e7a4bc569c
+++ src/lsi/abispec	bf8a0325aba2e8dd563c0c9dc0358989f130e20d
@@ -33,6 +33,10 @@ function mouse_read
 function cos
 function random
 function mouse_read
+function cmdsocket_listen
+function cmdsocket_accept
+function cmdsocket_read
+function cmdsocket_prefix
 
 /*
  * The ABI should be identified by a SHA1 hash of this file
============================================================
--- /dev/null	
+++ src/lsi/cmdsocket.c	855bbabd21448d3ac37ff460a412a951df7d226a
@@ -0,0 +1,204 @@
+/* cmdsocket.c */
+
+#include <sys/time.h>
+#include <dev/wscons/wsconsio.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdlib.h>
+#include "vm.h"
+
+#define PORT 15674
+#define CMD_MAXSIZE 1024
+#define PREFIX_MAXSIZE 1024
+
+#define CMDSOCKET_BANNER "lightscript cmdsocket ready\r\n"
+
+int cmd_sock = 0;
+int cmd_active = 0;
+int cmd_ignore;
+int cmd_bytes;
+int cmdsocket_initialised = 0;
+char cmd_buf[CMD_MAXSIZE];
+char cmd_prefix[PREFIX_MAXSIZE];
+
+int cmdsocket_init(void)
+{
+	cmdsocket_initialised = 1;
+    	cmd_bytes = 0;
+    	cmd_ignore = 0;
+	cmd_prefix[0] = '\0';
+
+	return 1;
+}
+
+void cmdsocket_close(void)
+{
+	if (cmd_active)
+		close(cmd_active);
+	if (cmd_sock)
+		close(cmd_sock);
+	cmdsocket_initialised = 0;
+}
+
+void cmdsocket_prefix(char *prefix)
+{
+	if (!cmdsocket_initialised)
+		return;
+	if (strlen(prefix) >= PREFIX_MAXSIZE-1)
+		return;
+	strncpy(cmd_prefix, prefix, PREFIX_MAXSIZE);
+}
+
+#define ERROR(x) do { warn((x)); goto error; } while (0)
+
+#define BACKLOG 0
+
+int cmdsocket_listen(int port) {
+	int sockopt_on = 1;
+	struct sockaddr_in my_addr;
+
+	cmd_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (cmd_sock == -1)
+		ERROR("can't open socket");
+	if (setsockopt(cmd_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt_on,
+	    sizeof(int)) == -1)
+		ERROR("can't set socket options");
+	memset((char *) &my_addr, 0, sizeof(my_addr));
+	my_addr.sin_family = PF_INET;
+	my_addr.sin_port = htons(port);
+	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	if (bind(cmd_sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1)
+		ERROR("can't bind socket");
+	if (listen(cmd_sock, BACKLOG) == -1)
+		ERROR("can't listen");
+	vm_register_signal_fd(cmd_sock, VM_CMDLISTENQ);
+
+	return 1;
+
+error:
+	if (cmd_sock)
+	    close(cmd_sock);
+	cmd_sock = 0;
+	return 0;
+}
+
+
+int cmdsocket_accept(void) {
+	struct sockaddr_in client_addr;
+	socklen_t client_addr_size = sizeof(client_addr);
+	int c;
+
+	if (!cmdsocket_initialised)
+		return 0;
+	if (cmd_sock == 0)
+		return 0;
+
+	/* We only accept one active connection at a time */
+	/* XXX can't just return here */
+	if (cmd_active)
+		return 0;
+
+	c = accept(cmd_sock, (struct sockaddr *)&client_addr,
+	    &client_addr_size);
+	if (c == -1) {
+		if (errno == EAGAIN)
+			return 0;
+		warn("Error accepting connection");
+		close(cmd_sock);
+		cmd_sock = 0;
+		return 0;
+	}
+
+	cmd_active = c;
+	write(cmd_active, CMDSOCKET_BANNER, sizeof(CMDSOCKET_BANNER));
+
+	vm_register_signal_fd(cmd_active, VM_CMDREADQ);
+	vm_wakeup(VM_CMDREADQ);
+	return 1;
+}
+
+void cmd_parse(char *cmd) {
+	char *sp;
+	int arg = 0;
+	char function[CMD_MAXSIZE + PREFIX_MAXSIZE];
+
+	*strchr(cmd, '\n') = '\0';
+	printf("DEBUG: Received command: %s\n", cmd);
+	fflush(stdout);
+
+	sp = strtok(cmd, " \t\r");
+	sp = strtok(NULL, " \t\r");
+	if (sp) {
+	    arg = atoi(sp);
+	}
+
+	/* cmd_prefix is guaranteed to be terminated */
+	strcpy(function, cmd_prefix);
+	strncat(function, cmd, CMD_MAXSIZE);
+
+	printf("DEBUG: function: %s, arg %d\n", function, arg);
+	fflush(stdout);
+	if (vm_spawn_args(function, 1, arg)) {
+		/* Write an ack here, once a proper function exists */
+	} else {
+		/* Write an error, if it's possible. Don't worry about
+		   missing characters and buffering for now, but we
+		   should eventually */
+		write(cmd_active, "ERROR\n", strlen("ERROR\n"));
+	}
+
+	printf("Received command: %s\n", cmd);
+}
+
+int cmdsocket_read(void)
+{
+	if (!cmdsocket_initialised)
+		return 0;
+
+	while (1) {
+		int rv;
+		int left = sizeof(cmd_buf) - cmd_bytes;
+		char *p;
+		if (!cmd_active)
+			return 0;
+
+		rv = recv(cmd_active, ((char *)&cmd_buf) + cmd_bytes, left, 0);
+		if (rv == -1) {
+			if (errno == EAGAIN)
+				return 0;
+			printf("Error reading from socket\n");
+			vm_unregister_signal_fd(cmd_active);
+			close(cmd_active);
+			cmd_active = 0;
+			vm_wakeup(VM_CMDLISTENQ);
+			return 0;
+		}
+		if (rv == 0) {
+			vm_unregister_signal_fd(cmd_active);
+			close(cmd_active);
+			cmd_active = 0;
+			vm_wakeup(VM_CMDLISTENQ);
+			return 0;
+		}
+		cmd_bytes += rv;
+		if ((p = memchr(cmd_buf, '\n', cmd_bytes))) {
+		    if (!cmd_ignore)
+			cmd_parse(cmd_buf);
+		    memmove(cmd_buf, p+1, cmd_bytes - (p - cmd_buf - 1));
+		    cmd_bytes = 0;
+		    cmd_ignore = 0;
+		}
+		if (cmd_bytes == sizeof(cmd_buf)) {
+			cmd_bytes = 0;
+			cmd_ignore = 1;
+			/* Overflow */
+		}
+	}
+}
============================================================
--- /dev/null	
+++ src/lsi/cmdsocket.h	dd5bddfcec81de17a358ae36f8e2626e68430728
@@ -0,0 +1,8 @@
+/* cmdsocket.h */
+
+int cmdsocket_init(void);
+void cmdsocket_close(void);
+int cmdsocket_listen(int port);
+int cmdsocket_accept(void);
+int cmdsocket_read(void);
+int cmdsocket_prefix(char *);
============================================================
--- src/lsi/mouse.c	9a2d9211ec57222cfa1f1d2ef9749e698445d0e7
+++ src/lsi/mouse.c	410738f63d15db286b591fff6040fcdfe9e1cfa6
@@ -55,6 +55,7 @@ int mouse_init(void)
 	mouse_x = 0;
 	mouse_y = 0;
 	mouse_z = 0;
+	mouse_bytes = 0;
 
 	mouse_fd = open(MOUSEDEVICE, O_RDONLY);
 	if (mouse_fd < 0) {
============================================================
--- src/lsi/plugins.c	0f20069da015e07f58b0828acdc3644a197dc794
+++ src/lsi/plugins.c	d1249e7348b4b02e2405e3374b7e6609ff982875
@@ -11,12 +11,14 @@
 #include "dmx.h"
 #include "beatdetect.h"
 #include "mouse.h"
+#include "cmdsocket.h"
 
 struct plugin plugins_table[] = {
 	{"midi", midi_init, midi_close, 0},
 	{"dmx", dmx_init, dmx_close, 0},
 	{"beatdetect", beatdetect_init, beatdetect_close, 0},
 	{"mouse", mouse_init, mouse_close, 0},
+	{"cmdsocket", cmdsocket_init, cmdsocket_close, 0},
 };
 
 int nplugins = (sizeof(plugins_table) / sizeof(struct plugin));
============================================================
--- src/lsi/vm.c	2f4df836fac21746563e434768e4f832c1ea3e15
+++ src/lsi/vm.c	f74e79e92252eafbcbc81d3ee4ca5e2e3c79f4a9
@@ -11,6 +11,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <math.h>
+#include <stdarg.h>
 
 #include "vm.h"
 #include "code.h"
@@ -21,6 +22,7 @@
 #include "beatdetect.h"
 #include "map3d.h"
 #include "mouse.h"
+#include "cmdsocket.h"
 
 #define DEBUG 0
 
@@ -41,6 +43,9 @@ struct vm_thread {
 
 #define ARRAYBLOCKSIZE	512
 
+#define SLEEPTIME_SEC	60
+#define SLEEPTIME_NSEC	0
+
 struct pollfd vm_pollfd[VM_MAXPOLLFD];
 int vm_pollfdqueue[VM_MAXPOLLFD];
 
@@ -55,6 +60,7 @@ size_t vm_codesize = 0;
 
 instr *vm_codearea = NULL;
 size_t vm_codesize = 0;
+int vm_threads = 0;
 
 struct hashentry *fnhash[HASHSIZE];
 struct hashentry *globhash[HASHSIZE];
@@ -418,6 +424,46 @@ int vm_intfn_mouse_read(void)
 	return 0;
 }
 
+int vm_intfn_cmdsocket_listen(void)
+{
+	stack_poke(vm_current, 0,
+	    cmdsocket_listen(stack_get(vm_current, 1)));
+	return 1;
+}
+
+int vm_intfn_cmdsocket_prefix(void)
+{
+	char buf[VM_STRING_MAX];
+	int len = stack_get(vm_current, 1);
+
+	strncpy(buf, stack_getstr(vm_current, len, 1), len);
+	buf[len] = '\0';
+
+	cmdsocket_prefix(buf);
+
+	return 1;
+}
+
+int vm_intfn_cmdsocket_accept(void)
+{
+	if (!cmdsocket_accept()) {
+	    vm_queue(vm_current, VM_CMDLISTENQ);
+	    vm_current = NULL;
+	    return 0;
+	}
+	return 1;
+}
+
+int vm_intfn_cmdsocket_read(void)
+{
+	if (!cmdsocket_read()) {
+		vm_queue(vm_current, VM_CMDREADQ);
+		vm_current = NULL;
+		return 0;
+	}
+	return 1;
+}
+
 int vm_intfn_beatdetect_read(void)
 {
 	if (!beatdetect_read()) {
@@ -570,6 +616,7 @@ void vm_init(void)
 	vm_npollfds = 0;
 	vm_caughtsignal = 0;
 	signal(SIGIO, vm_sighandler);
+	signal(SIGPIPE, SIG_IGN);
 }
 
 void vm_load_file(char *filename)
@@ -673,10 +720,11 @@ void vm_queue(struct vm_thread *thread, 
 	vm_queues[queue] = thread;
 }
 
-int vm_spawn(char *fn)
+int vm_spawn_args(char *fn, int n, ...)
 {
 	struct vm_thread *newt;
 	struct hashentry *ptr;
+	va_list ap;
 
 	ptr = hash_lookup(fnhash, fn, 0);
 	if (ptr == NULL) {
@@ -705,6 +753,12 @@ int vm_spawn(char *fn)
 	/* Push return address here, to point to some special thread exit
 	   routine */
 
+	/* Push optional arguments */
+	va_start(ap, n);
+	while (n--)
+	    stack_push(newt, va_arg(ap, int));
+	va_end(ap);
+
 	stack_push(newt, 0); 	/* Return value */
 	stack_push(newt, 0);	/* Return address */
 
@@ -712,15 +766,26 @@ int vm_spawn(char *fn)
 	newt->prev = NULL;
 	newt->queue = VM_NOQUEUE;
 	vm_queue(newt, VM_RUNQ);
+	vm_threads++;
 
 	return 1;
 }
 
+int vm_spawn(char *fn)
+{
+	return vm_spawn_args(fn, 0);
+}
+
 void vm_destroy(struct vm_thread *thread)
 {
 	vm_unqueue(thread);
 	free(thread->stackbase);
 	free(thread);
+	vm_threads--;
+	if (vm_threads == 0) {
+		printf("No threads left\n");
+		exit(0);
+	}
 }
 
 int vm_runnable(struct vm_thread *thread)
@@ -757,18 +822,19 @@ void vm_sched(void)
 		struct timespec ts;
 		int rv;
 
-		if (vm_queues[VM_TIMEQ] == NULL) {
-			printf("No runnable thread, and no waiting thread\n");
-			exit(0);
-		}
 //		printf("No runnable thread - sleeping\n");
-		gettimeofday(&tv, NULL);
-		timersub(&vm_queues[VM_TIMEQ]->time, &tv, &tv);
-		if ((tv.tv_sec < 0) || (tv.tv_usec < 0)) {
-			tv.tv_sec = 0;
-			tv.tv_usec = 0;
+		if (vm_queues[VM_TIMEQ]) {
+		    gettimeofday(&tv, NULL);
+		    timersub(&vm_queues[VM_TIMEQ]->time, &tv, &tv);
+		    if ((tv.tv_sec < 0) || (tv.tv_usec < 0)) {
+			    tv.tv_sec = 0;
+			    tv.tv_usec = 0;
+		    }
+		    TIMEVAL_TO_TIMESPEC(&tv, &ts);
+		} else {
+		    ts.tv_sec = SLEEPTIME_SEC;
+		    ts.tv_nsec = SLEEPTIME_NSEC;
 		}
-		TIMEVAL_TO_TIMESPEC(&tv, &ts);
 //		nanosleep(&ts, NULL);
 		rv = pollts(vm_pollfd, vm_npollfds, &ts, NULL);
 		if ((rv == -1) && (errno != EINTR))
@@ -791,6 +857,20 @@ void vm_register_signal_fd(int fd, int q
 	rv = fcntl(fd, F_SETFL, O_NONBLOCK | O_ASYNC);
 }
 
+void vm_unregister_signal_fd(int fd)
+{
+	int i;
+
+	for (i = 0; i < vm_npollfds; i++) {
+	    if (fd == vm_pollfd[i].fd) {
+		memmove(&vm_pollfd[i], &vm_pollfd[i+1],
+		    sizeof(struct pollfd) * (vm_npollfds-i-1));
+		vm_npollfds--;
+		return;
+	    }
+	}
+}
+
 void stack_push(struct vm_thread *thread, stkentry e)
 {
 	thread->sp++;
============================================================
--- src/lsi/vm.h	6ad84b9f243d5acff4ddeca82fc4a96caeb0930a
+++ src/lsi/vm.h	4e84a410186bc2516c890aaedd6b6c3705d1f30a
@@ -3,8 +3,11 @@ int vm_spawn(char *);
 void vm_init(void);
 void vm_load(char *);
 int vm_spawn(char *);
+int vm_spawn_args(char *, int, ...);
 void vm_run(void);
 void vm_register_signal_fd(int /* fd */, int /* queue */);
+void vm_unregister_signal_fd(int /* fd */);
+void vm_wakeup(int queue);
 
 #define VM_MAXQUEUES    512
 #define VM_RUNQ         0
@@ -13,8 +16,9 @@ void vm_register_signal_fd(int /* fd */,
 #define VM_MOUSEQ	6
 #define VM_BEATQ	7
 #define VM_MIDIQ	8
-#define VM_SOCKQ	9
+#define VM_CMDLISTENQ	9
+#define VM_CMDREADQ	10
 
-#define VM_USERQMIN     10
+#define VM_USERQMIN     20
 #define VM_NOQUEUE      (-1)