diff options
Diffstat (limited to 'sys/win/msvc/winstuff.c')
-rw-r--r-- | sys/win/msvc/winstuff.c | 398 |
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; +} + + |