mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-29 00:33:48 +01:00
Move library tree where it belongs
This commit is contained in:
398
lib-src/libnyquist/nyquist/sys/win/msvc/winstuff.c
Normal file
398
lib-src/libnyquist/nyquist/sys/win/msvc/winstuff.c
Normal file
@@ -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(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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user