summaryrefslogtreecommitdiff
path: root/sys/win/msvc/winstuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/win/msvc/winstuff.c')
-rw-r--r--sys/win/msvc/winstuff.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/sys/win/msvc/winstuff.c b/sys/win/msvc/winstuff.c
new file mode 100644
index 0000000..6670014
--- /dev/null
+++ b/sys/win/msvc/winstuff.c
@@ -0,0 +1,398 @@
+/* winstuff.c - windows interface routines for xlisp */
+/* Written by Chris Tchou. */
+/* This file contains the stuff that the other xlisp files call directly. */
+
+/* Changes by Roger Dannenberg, Jan 2006:
+Previously, the input thread would block on input, so if a command line
+instantiation of Nyquist called (EXIT), the process would still block
+in getchar() until the user typed a newline. Now, I only start the
+input thread if ostgetc is called (input is really needed). This will
+still read ahead and block, but only in cases where you are already
+interactive.
+
+/* Changes by Roger Dannenberg, April 2004:
+To support interrupts to Lisp processing, XLISP call oscheck frequently to
+test for an abort or break condition. This condition can be activated by
+special handlers, e.g. if a software interrupt is generated by Ctrl-C.
+Alternatively, the application can read ahead and look for break characters
+in the input stream. A third approach, implemented by Ning Hu for her
+Delphi-based IDE, is to send a Windows message to the process. Unfortunately,
+the Java IDE does not support sending a Windows message, nor can console
+IO be used to read ahead (console IO does not work because, when started by
+Java, Nyquist standard IO is redirected through pipes). The two solutions
+to enable break character prcessing seem to be:
+ 1) extend Java with C code to find the process and send Windows messages
+ 2) add a thread to perform read ahead and break character processing
+Option 2 contains the ugliness to Nyquist IO, which is already big and ugly,
+and leaves Java alone, which is something I don't know much about anyway,
+so I have chosen option 2: create a thread and read ahead. This uses only
+about 50 lines of code.
+
+A shortcoming of this approach is that, except for Ctrl-C, break characters
+like ^P, ^B, and ^U require the user to type RETURN to end the input line
+and allow the character to be processed.
+
+The thread will set a signal whenever a line of input is delivered so that
+Nyquist can block waiting for input. The signal will also be set when a
+^C or ^G is detected.
+
+For flexibility, compatibility with the Delphi IDE (NyqIDE) is retained by
+continuing to check for Windows process messages.
+*/
+
+#include <windows.h> /* Added by Ning Hu Apr.2001 */
+#include <process.h> /* Added by Dannenberg Apr 2004 */
+#include <signal.h> /* Added by Dannneberg, Apr 2004 */
+#include "exitpa.h" /* Added by Dannneberg, Apr 2004 */
+
+
+const char os_pathchar = '\\';
+const char os_sepchar = ',';
+
+
+#undef ERROR
+#include <stdio.h>
+//#include <QuickDraw.h> /* for Random */
+#include <memory.h> /* for DisposPtr */
+#include <string.h>
+//#include <SegLoad.h> /* for ExitToShell */
+#include "xlisp.h"
+#include "cext.h"
+#include "userio.h"
+#include "sliders.h"
+#include "sound.h" /* define nosc_enabled */
+
+/* externals */
+extern FILE *tfp; /* transcript file pointer */
+extern int cursorPos;
+extern char *macgets (void);
+//Added by Ning Hu Apr.2001
+extern int _isatty(int);
+extern int redirect_flag;
+//Add end
+
+/* local variables */
+int lposition;
+static char *linebuf = NULL, *lineptr;
+static int numChars;
+
+/* input thread */
+unsigned long input_thread_handle = -1;
+#define NEED_INPUT if (input_thread_handle == -1) start_input_thread();
+#define input_buffer_max 1024
+#define input_buffer_mask (input_buffer_max - 1)
+char input_buffer[1024];
+volatile int input_buffer_head = 0;
+volatile int input_buffer_tail = 0;
+volatile int buffer_eof = 0;
+HANDLE input_buffer_ready = NULL;
+
+BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType)
+{
+ if (dwCtrlType == CTRL_C_EVENT) {
+ abort_flag = ABORT_LEVEL;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#ifdef DEBUG_INPUT
+extern FILE *to_input_buffer;
+#endif
+
+void input_thread_run(void *args)
+{
+ int c;
+ /* this gets called, possible later, in io_init() in userio.c, but
+ * that doesn't seem to prevent this thread from being killed by
+ * CTRL-C, so call it here to be safe.
+ */
+ SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
+ /* printf("input_thread_run\n"); */
+
+ while (!buffer_eof) {
+ int head;
+ c = getchar();
+ if (c == EOF && abort_flag) {
+ // when user types ^C, an EOF is generated for some reason.
+ // Ignore it...
+ if (abort_flag == ABORT_LEVEL) c = ABORT_CHAR;
+ else c = BREAK_CHAR;
+ } else if (c == ABORT_CHAR) {
+ abort_flag = ABORT_LEVEL;
+ } else if (!abort_flag && c == BREAK_CHAR) {
+ // notice that a break will be ignored until XLISP
+ // handles the ABORT_LEVEL
+ abort_flag = BREAK_LEVEL;
+ } else if (c == BREAK_CHAR) {
+ ; // ignore this because abort_flag is set to ABORT_LEVEL
+ } else if (c == '\005' || c == '\006') { // control-e or control-f
+ ; // ignore these. IDE will send control-f to turn off echo, but
+ // under Windows, echo is already turned off. We filter control-f
+ // here to avoid generating an error message. Maybe the IDE should
+ // not send control-f in the first place, but the IDE is cross-platform
+ // and does not know it's running under Windows, whereas this file
+ // is platform dependent.
+ } else if (c == '\016') { // begin hidden message
+#define MSGBUF_MAX 64
+ char msgbuf[MSGBUF_MAX];
+ int msgbufx = 0;
+ char type_char = getchar(); // read message type character
+ printf("begin hidden message: %c\n", type_char);
+ if (type_char == EOF) buffer_eof = TRUE;
+ else {
+ // message is terminated by '\021'
+ while ((c = getchar()) != '\021' &&
+ c != EOF &&
+ msgbufx < MSGBUF_MAX - 1) {
+ msgbuf[msgbufx++] = c;
+ }
+ msgbuf[msgbufx++] = 0;
+ printf("message: %s\n", msgbuf);
+ if (c == EOF) buffer_eof = TRUE;
+ else if (msgbufx < MSGBUF_MAX) {
+ if (type_char == 'S') { // slider change message
+ // message format is index<space>value
+ int index;
+ float value;
+ if (sscanf(msgbuf, "%d %g", &index, &value) == 2) {
+ set_slider(index, value);
+ printf("set_slider %d %g\n", index, value);
+ }
+ }
+ }
+ }
+ } else if (c == EOF) {
+ buffer_eof = TRUE;
+ } else {
+ // insert character into the FIFO
+ head = (input_buffer_head + 1) & input_buffer_mask;
+ while (head == input_buffer_tail) Sleep(100);
+ input_buffer[input_buffer_head] = c;
+#ifdef DEBUG_INPUT
+ if (to_input_buffer) putc(c, to_input_buffer);
+#endif
+ input_buffer_head = head;
+ }
+ if (c == '\n' || abort_flag || buffer_eof) {
+ SetEvent(input_buffer_ready);
+ // wake up Nyquist if it is waiting for input
+ }
+ }
+ // printf("Input thread exiting\n");
+}
+
+//int isascii (char c) { return 1; } /* every char is an ascii char, isn't it? */
+
+void start_input_thread()
+{
+ // create thread to process input
+ input_thread_handle = _beginthread(input_thread_run, 0, NULL);
+ if (input_thread_handle == -1) {
+ printf("Unable to create input thread, errno = %d\n", errno);
+ EXIT(1);
+ }
+}
+
+void osinit (char *banner)
+{
+ printf("%s\n", banner);
+ if (_isatty( _fileno( stdin ) ) ){
+ redirect_flag = 0;
+#ifdef DEBUG
+ printf( "stdout has not been redirected to a file\n" ); //for debugging use
+#endif
+ } else {
+ redirect_flag = 1;
+#ifdef DEBUG
+ printf( "stdout has been redirected to a file\n"); //for debugging use
+#endif
+ }
+ // signal when input is ready
+ input_buffer_ready = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (input_buffer_ready == NULL) {
+ printf("Unable to create Event object\n");
+ EXIT(1);
+ }
+}
+
+FILE *osaopen (char *name, char *mode) {
+ return fopen (name, mode);
+}
+
+FILE *osbopen (char *name, char *mode) {
+ char nmode[4];
+ strcpy (nmode, mode); strcat (nmode, "b");
+ return (fopen (name, nmode));
+}
+
+int osclose (FILE *fp) { return (fclose (fp)); }
+int osaputc (int ch, FILE *fp) { return (putc (ch, fp)); }
+int osbputc (int ch, FILE *fp) { return (putc (ch, fp)); }
+void osoutflush(FILE *fp) { fflush(fp); }
+
+/* osagetc - get a character from an ascii file */
+int osagetc(fp)
+ FILE *fp;
+{
+ return (getc(fp));
+}
+
+extern int abort_flag;
+extern int redirect_flag; //Added by Ning Hu Apr.2001
+int ostgetc (void)
+{
+ int c;
+ NEED_INPUT;
+ while (!buffer_eof && (input_buffer_tail == input_buffer_head)) {
+ oscheck();
+ WaitForSingleObject(input_buffer_ready, INFINITE);
+ }
+ if (buffer_eof) c = EOF;
+ else {
+ c = input_buffer[input_buffer_tail];
+ input_buffer_tail = (input_buffer_tail + 1) & input_buffer_mask;
+ }
+ if (c == '\025') { // control-u
+ xlcleanup();
+ } else if (c == '\020') { // control-p
+ xlcontinue();
+ } else if (c == '\024') { // control-t
+ xinfo();
+ }
+ return c;
+}
+
+
+void ostputc (int ch) {
+// macputc (ch);
+ putchar(ch); // console
+
+ if (tfp) osaputc (ch, tfp);
+}
+
+void ostoutflush()
+{
+ if (tfp) fflush(tfp);
+ fflush(stdout);
+}
+
+
+void osflush (void) {
+ lineptr = linebuf;
+ numChars = 0;
+ lposition = 0;
+}
+
+
+void oscheck (void) {
+ MSG lpMsg;
+
+#if OSC
+ if (nosc_enabled) nosc_poll();
+#endif
+
+ // check_aborted(); -- call to userio.c superceded by code here in winstuff.c
+// printf("Current Thread: %d\n", GetCurrentThreadId()); //for debugging use
+ // look for Windows messages from NyqIDE (a Delphi program)
+ if ((redirect_flag) && (PeekMessage(&lpMsg, NULL, 0, 0, PM_REMOVE)!=0)) {
+ if (lpMsg.message == WM_CHAR) {
+ switch (lpMsg.wParam) {
+ case ABORT_CHAR: abort_flag = ABORT_LEVEL;
+ break;
+ case BREAK_CHAR: // for nyquist, defined to be 2
+ case 7: // NyqIDE sends 7 (BEL) as break character
+ abort_flag = BREAK_LEVEL;
+ break;
+ }
+ // printf("Get message: %d %d %d\n", lpMsg.wParam, BREAK_CHAR, abort_flag); //for debugging use
+ }
+ }
+ if (abort_flag == ABORT_LEVEL) {
+ abort_flag = 0;
+ osflush();
+ xltoplevel();
+ } else if (abort_flag == BREAK_LEVEL) {
+ abort_flag = 0;
+ osflush();
+ xlbreak("BREAK", s_unbound);
+ }
+}
+//Update end
+
+void oserror (char *msg) {
+ char line[100], *p;
+ sprintf (line,"error: %s\n",msg);
+ for (p = line; *p != '\0'; ++p) ostputc (*p);
+}
+
+void osfinish(void) {
+ portaudio_exit();
+ /* dispose of everything... */
+// if (linebuf) DisposPtr (linebuf);
+// MacWrapUp ();
+// ExitToShell ();
+}
+
+int renamebackup (char *filename) { return 0; }
+
+
+
+
+static WIN32_FIND_DATA FindFileData;
+static HANDLE hFind = INVALID_HANDLE_VALUE;
+#define OSDIR_LIST_READY 0
+#define OSDIR_LIST_STARTED 1
+#define OSDIR_LIST_DONE 2
+static int osdir_list_status = OSDIR_LIST_READY;
+#define OSDIR_MAX_PATH 256
+static char osdir_path[OSDIR_MAX_PATH];
+
+// osdir_list_start -- prepare to list a directory
+int osdir_list_start(char *path)
+{
+ if (strlen(path) >= OSDIR_MAX_PATH - 2) {
+ xlcerror("LISTDIR path too big", "return nil", NULL);
+ return FALSE;
+ }
+ strcpy(osdir_path, path);
+ strcat(osdir_path, "/*"); // make a pattern to match all files
+ if (osdir_list_status != OSDIR_LIST_READY) {
+ osdir_list_finish(); // close previously interrupted listing
+ }
+ hFind = FindFirstFile(osdir_path, &FindFileData); // get the "."
+ if (hFind == INVALID_HANDLE_VALUE) return FALSE;
+ if (FindNextFile(hFind, &FindFileData) == 0) return FALSE; // get the ".."
+ osdir_list_status = OSDIR_LIST_STARTED;
+ return TRUE;
+}
+
+
+char *osdir_list_next()
+{
+ if (FindNextFile(hFind, &FindFileData) == 0) {
+ osdir_list_status = OSDIR_LIST_DONE;
+ return NULL;
+ }
+ return FindFileData.cFileName;
+}
+
+void osdir_list_finish()
+{
+ if (osdir_list_status != OSDIR_LIST_READY) {
+ FindClose(hFind);
+ }
+ osdir_list_status = OSDIR_LIST_READY;
+}
+
+
+/* xechoenabled -- set/clear echo_enabled flag (unix only) */
+LVAL xechoenabled()
+{
+ int flag = (xlgetarg() != NULL);
+ xllastarg();
+ // echo_enabled = flag; -- do nothing in Windows
+ return NULL;
+}
+
+