From c4929b800a019b8f20b0779dca2e1f8de70e0e1e Mon Sep 17 00:00:00 2001 From: chombier <> Date: Sat, 17 Mar 2001 13:09:13 +0000 Subject: [PATCH] new socket interface for tty device --- lsh/MacOS/src/GUSITTY.cp | 242 +++++++++++++++++++++++++++++++++++++++ lsh/MacOS/src/GUSITTY.h | 18 +++ 2 files changed, 260 insertions(+) create mode 100644 lsh/MacOS/src/GUSITTY.cp create mode 100644 lsh/MacOS/src/GUSITTY.h diff --git a/lsh/MacOS/src/GUSITTY.cp b/lsh/MacOS/src/GUSITTY.cp new file mode 100644 index 0000000..3f91def --- /dev/null +++ b/lsh/MacOS/src/GUSITTY.cp @@ -0,0 +1,242 @@ +/* + * GUSITTY.cp + * (c) 2000 Jean-Pierre Stierlin. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GUSIInternal.h" +#include "GUSITTY.h" +#include "GUSIDevice.h" +#include "GUSIDescriptor.h" +#include "GUSIBasics.h" +#include "GUSIDiag.h" + +#include + +#include +#include +#include +/*#include */ + + +class GUSITTYDevice : public GUSIDevice { +public: + static GUSITTYDevice * Instance(); + + // [[GUSITTYDevice]] is prepared to handle an [[open]] on a limited set of names. + // + // = + virtual bool Want(GUSIFileToken & file); + // [[open]] returns instance of [[GUSITTYSocket]]. + // + // = + virtual GUSISocket * open(GUSIFileToken &, int flags); +private: + GUSITTYDevice() {} + + static GUSITTYDevice * sInstance; +}; + + + +class GUSITTYSocket : public GUSISocket { +public: + ~GUSITTYSocket(); + + // Some member functions are fairly trivial wrappers. + // + // = + ssize_t read(const GUSIScatterer & buffer); + // = + ssize_t write(const GUSIGatherer & buffer); + // = + virtual int ioctl(unsigned int request, va_list arg); + // Since we know we're running on a pseudodevice, we can pass on that fact. + // + // = + virtual int fstat(struct stat * buf); + // And we also know we're a TTY. + // + // = + virtual int isatty(); + // [[select]] requires a walk of the event queue. + // + // = + bool select(bool * canRead, bool * canWrite, bool *); + +protected: + GUSITTYSocket(int id, int flags); + + int mId; + int mFlags; + + friend class GUSITTYDevice; +}; + + + + + +/* + * GUSIwithTTYSockets + */ +extern "C" void GUSIwithTTYSockets() +{ + GUSIDeviceRegistry::Instance()->AddDevice(GUSITTYDevice::Instance()); +} + + + +/* + * GUSITTYDevice::Instance + */ + +GUSITTYDevice * GUSITTYDevice::sInstance; + +GUSITTYDevice * GUSITTYDevice::Instance() +{ + if (!sInstance) + sInstance = new GUSITTYDevice(); + return sInstance; +} + +/* + * GUSITTYDevice::Want + */ +bool GUSITTYDevice::Want(GUSIFileToken &file) +{ + const char *path = file.Path(); + + switch (file.WhichRequest()) { + case GUSIFileToken::kWillOpen: + return file.IsDevice() && file.StrFragEqual(path+4, "tty") + && (!path[7] + || (file.StrFragEqual(path+7, "in") && !path[9]) + || (file.StrFragEqual(path+7, "out") && !path[10]) + || (file.StrFragEqual(path+7, "err") && !path[10])); + default: + return false; + } +} + +/* + * GUSITTYDevice::open + */ +GUSISocket * GUSITTYDevice::open(GUSIFileToken &file, int flags) +{ + GUSISocket *sock; + const char *path = file.Path(); + int id; + + if (!path[7]) { + id = 3; + } else if (!path[9]) { + id = 0; + } else if (file.StrFragEqual(path+7, "out")) { + id = 1; + } else /*if (file.StrFragEqual(path+7, "err"))*/ { + id = 2; + } + if ( !(sock = new GUSITTYSocket(id, flags) )) { + GUSISetPosixError(ENOMEM); + } + return sock; +} + + + +/* + * GUSITTYSocket::GUSITTYSocket + */ +GUSITTYSocket::GUSITTYSocket(int id, int flags) : mId(id), mFlags(flags) +{ + InstallTTY(id, flags); +} + + +/* + * GUSITTYSocket::~GUSITTYSocket + */ +GUSITTYSocket::~GUSITTYSocket() +{ + RemoveTTY(mId, mFlags); +} + +/* + * GUSITTYSocket::read + */ +ssize_t GUSITTYSocket::read(const GUSIScatterer & buffer) +{ + /* FIXME: flush pending output */ + /*FlushTTY(mId);*/ + return buffer.SetLength( + ReadCharsFromTTY(mId, mFlags, (char *) buffer.Buffer(), (int)buffer.Length())); +} + +/* + * GUSITTYSocket::write + */ +ssize_t GUSITTYSocket::write(const GUSIGatherer & buffer) +{ + return WriteCharsToTTY(mId, mFlags, (char *) buffer.Buffer(), (int)buffer.Length()); +} + +/* + * GUSITTYSocket::ioctl + */ +int GUSITTYSocket::ioctl(unsigned int request, va_list) +{ + switch (request) { + case FIOINTERACTIVE: + return 0; + default: + return GUSISetPosixError(EOPNOTSUPP); + } +} + +/* + * GUSITTYSocket::fstat + */ +int GUSITTYSocket::fstat(struct stat * buf) +{ + GUSISocket::fstat(buf); + buf->st_mode = S_IFCHR | 0666; + + return 0; +} + +/* + * GUSITTYSocket::isatty + */ +int GUSITTYSocket::isatty() +{ + return 1; +} + +/* + * GUSITTYSocket::select + */ +bool GUSITTYSocket::select(bool * canRead, bool * canWrite, bool *) +{ + bool cond = false; + if (canRead) + if (*canRead = AvailableFromTTY(mId, mFlags)) + cond = true; + if (canWrite) + cond = *canWrite = true; + + return cond; +} diff --git a/lsh/MacOS/src/GUSITTY.h b/lsh/MacOS/src/GUSITTY.h new file mode 100644 index 0000000..4689c50 --- /dev/null +++ b/lsh/MacOS/src/GUSITTY.h @@ -0,0 +1,18 @@ +#ifndef _GUSITTY_ +#define _GUSITTY_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int InstallTTY(int id, int flags); +extern void RemoveTTY(int id, int flags); +extern int ReadCharsFromTTY(int id, int flags, char * buffer, int length); +extern int WriteCharsToTTY(int id, int flags, char * buffer, int length); +extern int AvailableFromTTY(int id, int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _GUSITTY_ */