2001-02-10 21:08:04 -04:00
|
|
|
/*
|
|
|
|
** Modified version of GUSISIOUX.cp especially for Python.
|
|
|
|
** Changes (by Jack):
|
|
|
|
** - Optionally delay the console window until something is written to it.
|
|
|
|
** - Tell the upper layers whether the last command was a read or a write.
|
|
|
|
** - Tell SIOUX not to use WaitNextEvent (both Python and SIOUX trying to be
|
|
|
|
** nice to background apps means we're yielding almost 100% of the time).
|
|
|
|
** - Make sure signals are processed when returning from read/write.
|
|
|
|
*/
|
|
|
|
#define GUSI_SOURCE
|
|
|
|
#include "GUSIInternal.h"
|
|
|
|
#include "GUSISIOUX.h"
|
|
|
|
#include "GUSIDevice.h"
|
|
|
|
#include "GUSIDescriptor.h"
|
|
|
|
#include "GUSIBasics.h"
|
|
|
|
#include "GUSIDiag.h"
|
|
|
|
//#ifndef WITHOUT_JACK_MODS
|
|
|
|
//#include "GUSIConfig.h"
|
|
|
|
//#endif
|
|
|
|
|
|
|
|
#include <LowMem.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <console.h>
|
|
|
|
|
|
|
|
#include "Python.h"
|
|
|
|
#include "macglue.h"
|
|
|
|
extern Boolean SIOUXUseWaitNextEvent;
|
|
|
|
|
2001-10-08 12:35:38 -03:00
|
|
|
static PyReadHandler sInConsole = 0L;
|
|
|
|
static PyWriteHandler sOutConsole = 0L;
|
|
|
|
static PyWriteHandler sErrConsole = 0L;
|
|
|
|
|
|
|
|
inline bool hasCustomConsole(void) { return sInConsole != 0L; }
|
|
|
|
|
2001-02-10 21:08:04 -04:00
|
|
|
class GUSISIOUXSocket : public GUSISocket {
|
|
|
|
public:
|
|
|
|
~GUSISIOUXSocket();
|
|
|
|
|
|
|
|
|
|
|
|
ssize_t read(const GUSIScatterer & buffer);
|
|
|
|
ssize_t write(const GUSIGatherer & buffer);
|
|
|
|
virtual int ioctl(unsigned int request, va_list arg);
|
|
|
|
virtual int fstat(struct stat * buf);
|
|
|
|
virtual int isatty();
|
|
|
|
bool select(bool * canRead, bool * canWrite, bool *);
|
|
|
|
|
2001-10-08 12:35:38 -03:00
|
|
|
static GUSISIOUXSocket * Instance(int fd);
|
|
|
|
private:
|
|
|
|
GUSISIOUXSocket(int fd);
|
|
|
|
static bool initialized;
|
|
|
|
static void Initialize();
|
|
|
|
int fFd;
|
2001-02-10 21:08:04 -04:00
|
|
|
};
|
|
|
|
class GUSISIOUXDevice : public GUSIDevice {
|
|
|
|
public:
|
|
|
|
static GUSISIOUXDevice * Instance();
|
|
|
|
|
|
|
|
|
|
|
|
virtual bool Want(GUSIFileToken & file);
|
|
|
|
virtual GUSISocket * open(GUSIFileToken &, int flags);
|
|
|
|
private:
|
|
|
|
GUSISIOUXDevice() {}
|
|
|
|
|
|
|
|
static GUSISIOUXDevice * sInstance;
|
|
|
|
};
|
|
|
|
|
2001-10-08 12:35:38 -03:00
|
|
|
GUSISIOUXSocket * GUSISIOUXSocket::Instance(int fd)
|
2001-02-10 21:08:04 -04:00
|
|
|
{
|
2001-10-08 12:35:38 -03:00
|
|
|
return new GUSISIOUXSocket(fd);
|
2001-02-10 21:08:04 -04:00
|
|
|
}
|
|
|
|
// This declaration lies about the return type
|
|
|
|
extern "C" void SIOUXHandleOneEvent(EventRecord *userevent);
|
|
|
|
|
2001-10-08 12:35:38 -03:00
|
|
|
bool GUSISIOUXSocket::initialized = false;
|
|
|
|
|
|
|
|
GUSISIOUXSocket::GUSISIOUXSocket(int fd) : fFd(fd)
|
2001-02-10 21:08:04 -04:00
|
|
|
{
|
2002-01-11 06:24:23 -04:00
|
|
|
if (!hasCustomConsole()) {
|
|
|
|
if (!PyMac_GetDelayConsoleFlag() && !initialized)
|
|
|
|
Initialize();
|
|
|
|
/* Tell the upper layers there's no unseen output */
|
|
|
|
PyMac_OutputSeen();
|
|
|
|
}
|
2001-02-10 21:08:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
GUSISIOUXSocket::Initialize()
|
|
|
|
{
|
2001-10-08 12:35:38 -03:00
|
|
|
if(!initialized && !hasCustomConsole())
|
|
|
|
{
|
|
|
|
initialized = true;
|
|
|
|
InstallConsole(0);
|
|
|
|
GUSISetHook(GUSI_EventHook+nullEvent, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
GUSISetHook(GUSI_EventHook+mouseDown, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
GUSISetHook(GUSI_EventHook+mouseUp, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
GUSISetHook(GUSI_EventHook+updateEvt, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
GUSISetHook(GUSI_EventHook+diskEvt, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
GUSISetHook(GUSI_EventHook+activateEvt, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
GUSISetHook(GUSI_EventHook+osEvt, (GUSIHook)SIOUXHandleOneEvent);
|
|
|
|
PyMac_InitMenuBar();
|
|
|
|
}
|
2001-02-10 21:08:04 -04:00
|
|
|
}
|
|
|
|
GUSISIOUXSocket::~GUSISIOUXSocket()
|
|
|
|
{
|
2001-10-08 12:35:38 -03:00
|
|
|
if ( !initialized || hasCustomConsole() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
initialized = false;
|
2001-02-10 21:08:04 -04:00
|
|
|
RemoveConsole();
|
|
|
|
}
|
|
|
|
ssize_t GUSISIOUXSocket::read(const GUSIScatterer & buffer)
|
|
|
|
{
|
2001-10-08 12:35:38 -03:00
|
|
|
if(hasCustomConsole())
|
|
|
|
{
|
|
|
|
if(fFd == 0)
|
|
|
|
return buffer.SetLength(
|
|
|
|
sInConsole((char *) buffer.Buffer(), (int)buffer.Length()));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-10 21:08:04 -04:00
|
|
|
if ( !initialized ) Initialize();
|
|
|
|
GUSIStdioFlush();
|
|
|
|
PyMac_OutputSeen();
|
2001-04-25 19:07:27 -03:00
|
|
|
PyMac_RaiseConsoleWindow();
|
2001-02-10 21:08:04 -04:00
|
|
|
return buffer.SetLength(
|
|
|
|
ReadCharsFromConsole((char *) buffer.Buffer(), (int)buffer.Length()));
|
|
|
|
GUSIContext::Yield(kGUSIPoll);
|
|
|
|
}
|
|
|
|
ssize_t GUSISIOUXSocket::write(const GUSIGatherer & buffer)
|
|
|
|
{
|
2001-10-08 12:35:38 -03:00
|
|
|
if(hasCustomConsole())
|
|
|
|
{
|
|
|
|
if(fFd == 1)
|
|
|
|
return sOutConsole((char *) buffer.Buffer(), (int)buffer.Length());
|
|
|
|
else if(fFd == 2)
|
|
|
|
return sErrConsole((char *) buffer.Buffer(), (int)buffer.Length());
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-10 21:08:04 -04:00
|
|
|
ssize_t rv;
|
|
|
|
|
|
|
|
if ( !initialized ) Initialize();
|
|
|
|
PyMac_OutputNotSeen();
|
|
|
|
SIOUXUseWaitNextEvent = false;
|
|
|
|
rv = WriteCharsToConsole((char *) buffer.Buffer(), (int)buffer.Length());
|
|
|
|
GUSIContext::Yield(kGUSIPoll);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
int GUSISIOUXSocket::ioctl(unsigned int request, va_list)
|
|
|
|
{
|
|
|
|
switch (request) {
|
|
|
|
case FIOINTERACTIVE:
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return GUSISetPosixError(EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int GUSISIOUXSocket::fstat(struct stat * buf)
|
|
|
|
{
|
|
|
|
GUSISocket::fstat(buf);
|
|
|
|
buf->st_mode = S_IFCHR | 0666;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int GUSISIOUXSocket::isatty()
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static bool input_pending()
|
|
|
|
{
|
|
|
|
#if !TARGET_API_MAC_CARBON
|
|
|
|
// Jack thinks that completely removing this code is a bit
|
|
|
|
// too much...
|
|
|
|
QHdrPtr eventQueue = LMGetEventQueue();
|
|
|
|
EvQElPtr element = (EvQElPtr)eventQueue->qHead;
|
|
|
|
|
|
|
|
// now, count the number of pending keyDown events.
|
|
|
|
while (element != nil) {
|
|
|
|
if (element->evtQWhat == keyDown || element->evtQWhat == autoKey)
|
|
|
|
return true;
|
|
|
|
element = (EvQElPtr)element->qLink;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GUSISIOUXSocket::select(bool * canRead, bool * canWrite, bool *)
|
|
|
|
{
|
|
|
|
if ( !initialized ) Initialize();
|
|
|
|
bool cond = false;
|
|
|
|
if (canRead)
|
|
|
|
if (*canRead = input_pending())
|
|
|
|
cond = true;
|
|
|
|
if (canWrite)
|
|
|
|
cond = *canWrite = true;
|
|
|
|
|
|
|
|
return cond;
|
|
|
|
}
|
|
|
|
GUSISIOUXDevice * GUSISIOUXDevice::sInstance;
|
|
|
|
GUSISIOUXDevice * GUSISIOUXDevice::Instance()
|
|
|
|
{
|
|
|
|
if (!sInstance)
|
|
|
|
sInstance = new GUSISIOUXDevice();
|
|
|
|
return sInstance;
|
|
|
|
}
|
|
|
|
bool GUSISIOUXDevice::Want(GUSIFileToken & file)
|
|
|
|
{
|
|
|
|
switch (file.WhichRequest()) {
|
|
|
|
case GUSIFileToken::kWillOpen:
|
|
|
|
return file.IsDevice() && (file.StrStdStream(file.Path()) > -1);
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GUSISocket * GUSISIOUXDevice::open(GUSIFileToken &, int)
|
|
|
|
{
|
2001-10-08 12:35:38 -03:00
|
|
|
return GUSISIOUXSocket::Instance(1);
|
2001-02-10 21:08:04 -04:00
|
|
|
}
|
|
|
|
void GUSISetupConsoleDescriptors()
|
|
|
|
{
|
|
|
|
GUSIDescriptorTable * table = GUSIDescriptorTable::Instance();
|
|
|
|
|
2001-10-08 12:35:38 -03:00
|
|
|
table->InstallSocket(GUSISIOUXSocket::Instance(0));
|
|
|
|
table->InstallSocket(GUSISIOUXSocket::Instance(1));
|
|
|
|
table->InstallSocket(GUSISIOUXSocket::Instance(2));
|
|
|
|
}
|
|
|
|
|
|
|
|
void PyMac_SetConsoleHandler(PyReadHandler stdinH, PyWriteHandler stdoutH, PyWriteHandler stderrH)
|
|
|
|
{
|
|
|
|
if(stdinH && stdoutH && stderrH)
|
|
|
|
{
|
|
|
|
sInConsole = stdinH;
|
|
|
|
sOutConsole = stdoutH;
|
|
|
|
sErrConsole = stderrH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long PyMac_DummyReadHandler(char *buffer, long n)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
long PyMac_DummyWriteHandler(char *buffer, long n)
|
|
|
|
{
|
|
|
|
return 0;
|
2001-02-10 21:08:04 -04:00
|
|
|
}
|