📄 pchannel.cxx
字号:
/*
* pchannel.cxx
*
* Operating System utilities.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Log: pchannel.cxx,v $
* Revision 1.16 2001/11/13 04:13:22 robertj
* Added ability to adjust size of ios buffer on PChannels.
*
* Revision 1.15 2001/09/27 10:23:42 craigs
* CHanged ReadString to allow read until end of input with P_MAX_INDEX arg
*
* Revision 1.14 2001/09/11 02:36:52 robertj
* Fixed crash bug when ReadString() gets I/O error.
*
* Revision 1.13 2001/09/10 21:58:31 craigs
* Fixed cut and paste problem that broke PIndirectChannel::Write
*
* Revision 1.12 2001/09/10 02:51:23 robertj
* Major change to fix problem with error codes being corrupted in a
* PChannel when have simultaneous reads and writes in threads.
*
* Revision 1.11 2001/06/04 10:13:38 robertj
* Added compare function to compare value of os_handle.
* Added has function based on os_handle value.
*
* Revision 1.10 2001/01/02 06:07:07 robertj
* Fixed race condition in reopening indirect channel, thanks Bertrand Croq.
*
* Revision 1.9 2000/11/14 08:25:58 robertj
* Added function to propagate the error text through to indirect channel.
*
* Revision 1.8 2000/08/22 08:33:37 robertj
* Removed PAssert() for write to unattached indirect channel, now sets
* return code so is similay to "unopened file" semantics.
*
* Revision 1.7 2000/06/26 11:17:20 robertj
* Nucleus++ port (incomplete).
*
* Revision 1.6 1999/07/06 08:55:05 robertj
* Fixed bug in PFile::Copy, does not write last chunk of data to new file.
*
* Revision 1.5 1999/06/17 14:44:42 robertj
* Fixed incorrect comparison of open write channel
*
* Revision 1.4 1999/06/17 13:38:11 robertj
* Fixed race condition on indirect channel close, mutex needed in PIndirectChannel.
*
* Revision 1.3 1999/02/22 10:10:12 robertj
* Changed channel output flush to remove double Write() call.
*
* Revision 1.2 1999/01/31 00:57:18 robertj
* Fixed bug when opening an already open file, should close it!
*
* Revision 1.1 1998/11/30 12:46:19 robertj
* Initial revision
*
*/
#include <ptlib.h>
#include <ctype.h>
///////////////////////////////////////////////////////////////////////////////
// PChannel
PChannelStreamBuffer::PChannelStreamBuffer(PChannel * chan)
: channel(PAssertNULL(chan))
{
}
BOOL PChannelStreamBuffer::SetBufferSize(PINDEX newSize)
{
return input.SetSize(newSize) && output.SetSize(newSize);
}
int PChannelStreamBuffer::overflow(int c)
{
if (pbase() == NULL) {
char * p = output.GetPointer(1024);
setp(p, p+output.GetSize());
}
int bufSize = pptr() - pbase();
if (bufSize > 0) {
setp(pbase(), epptr());
if (!channel->Write(pbase(), bufSize))
return EOF;
}
if (c != EOF) {
*pptr() = (char)c;
pbump(1);
}
return 0;
}
int PChannelStreamBuffer::underflow()
{
if (eback() == NULL) {
char * p = input.GetPointer(1024);
char * e = p+input.GetSize();
setg(p, e, e);
}
if (gptr() != egptr())
return (BYTE)*gptr();
if (!channel->Read(eback(), egptr() - eback()) ||
channel->GetErrorCode() != PChannel::NoError)
return EOF;
PINDEX count = channel->GetLastReadCount();
char * p = egptr() - count;
memmove(p, eback(), count);
setg(eback(), p, egptr());
return (BYTE)*p;
}
int PChannelStreamBuffer::sync()
{
int inAvail = egptr() - gptr();
if (inAvail > 0) {
setg(eback(), egptr(), egptr());
if (channel->IsDescendant(PFile::Class()))
((PFile *)channel)->SetPosition(-inAvail, PFile::Current);
}
if (pptr() > pbase())
return overflow();
return 0;
}
streampos PChannelStreamBuffer::seekoff(streamoff off,
#ifdef __MWERKS__
ios::seekdir dir, ios::openmode)
#else
ios::seek_dir dir, int)
#endif
{
sync();
if (!channel->IsDescendant(PFile::Class()))
return -1;
((PFile *)channel)->SetPosition(off, (PFile::FilePositionOrigin)dir);
return ((PFile *)channel)->GetPosition();
}
PChannel::PChannel()
: readTimeout(PMaxTimeInterval), writeTimeout(PMaxTimeInterval)
{
os_handle = -1;
memset(lastErrorCode, 0, sizeof(lastErrorCode));
memset(lastErrorNumber, 0, sizeof(lastErrorNumber));
lastReadCount = lastWriteCount = 0;
init(new PChannelStreamBuffer(this));
Construct();
}
PChannel::~PChannel()
{
flush();
Close();
delete (PChannelStreamBuffer *)rdbuf();
init(NULL);
}
PObject::Comparison PChannel::Compare(const PObject & obj) const
{
PAssert(IsDescendant(PChannel::Class()), PInvalidCast);
int h1 = GetHandle();
int h2 = ((const PChannel&)obj).GetHandle();
if (h1 < h2)
return LessThan;
if (h1 > h2)
return GreaterThan;
return EqualTo;
}
PINDEX PChannel::HashFunction() const
{
return GetHandle()%97;
}
BOOL PChannel::IsOpen() const
{
return os_handle >= 0;
}
int PChannel::ReadChar()
{
BYTE c;
BOOL retVal = Read(&c, 1);
return (retVal && lastReadCount == 1) ? c : -1;
}
int PChannel::ReadCharWithTimeout(PTimeInterval & timeout)
{
SetReadTimeout(timeout);
PTimeInterval startTick = PTimer::Tick();
int c;
if ((c = ReadChar()) < 0) // Timeout or aborted
return -1;
timeout -= PTimer::Tick() - startTick;
return c;
}
BOOL PChannel::ReadBlock(void * buf, PINDEX len)
{
char * ptr = (char *)buf;
PINDEX numRead = 0;
while (numRead < len && Read(ptr+numRead, len - numRead))
numRead += lastReadCount;
lastReadCount = numRead;
return lastReadCount == len;
}
PString PChannel::ReadString(PINDEX len)
{
PString str;
if (len == P_MAX_INDEX) {
PINDEX l = 0;
for (;;) {
char * p = l + str.GetPointer(l+1000+1);
if (!Read(p, 1000))
break;
l += lastReadCount;
}
str.SetSize(l+1);
} else {
if (!ReadBlock(str.GetPointer(len+1), len))
return PString();
str.SetSize(lastReadCount+1);
}
return str;
}
BOOL PChannel::WriteString(const PString & str)
{
const char * ptr = str;
PINDEX len = 0, slen = str.GetLength();
while (len < slen && Write(ptr+len, slen - len))
len += lastWriteCount;
return len == slen;
}
BOOL PChannel::ReadAsync(void * buf, PINDEX len)
{
BOOL retVal = Read(buf, len);
OnReadComplete(buf, lastReadCount);
return retVal;
}
void PChannel::OnReadComplete(void *, PINDEX)
{
}
BOOL PChannel::WriteChar(int c)
{
PAssert(c >= 0 && c < 256, PInvalidParameter);
char buf = (char)c;
return Write(&buf, 1);
}
BOOL PChannel::WriteAsync(const void * buf, PINDEX len)
{
BOOL retVal = Write(buf, len);
OnWriteComplete(buf, lastWriteCount);
return retVal;
}
void PChannel::OnWriteComplete(const void *, PINDEX)
{
}
BOOL PChannel::SetBufferSize(PINDEX newSize)
{
return ((PChannelStreamBuffer *)rdbuf())->SetBufferSize(newSize);
}
enum {
NextCharEndOfString = -1,
NextCharDelay = -2,
NextCharSend = -3,
NextCharWait = -4
};
static int HexDigit(char c)
{
if (!isxdigit(c))
return 0;
int hex = c - '0';
if (hex < 10)
return hex;
hex -= 'A' - '9' - 1;
if (hex < 16)
return hex;
return hex - ('a' - 'A');
}
static int GetNextChar(const PString & command,
PINDEX & pos, PTimeInterval * time = NULL)
{
int temp;
if (command[pos] == '\0')
return NextCharEndOfString;
if (command[pos] != '\\')
return command[pos++];
switch (command[++pos]) {
case '\0' :
return NextCharEndOfString;
case 'a' : // alert (ascii value 7)
pos++;
return 7;
case 'b' : // backspace (ascii value 8)
pos++;
return 8;
case 'f' : // formfeed (ascii value 12)
pos++;
return 12;
case 'n' : // newline (ascii value 10)
pos++;
return 10;
case 'r' : // return (ascii value 13)
pos++;
return 13;
case 't' : // horizontal tab (ascii value 9)
pos++;
return 9;
case 'v' : // vertical tab (ascii value 11)
pos++;
return 11;
case 'x' : // followed by hh where nn is hex number (ascii value 0xhh)
if (isxdigit(command[++pos])) {
temp = HexDigit(command[pos++]);
if (isxdigit(command[pos]))
temp += HexDigit(command[pos++]);
return temp;
}
return command[pos];
case 's' :
pos++;
return NextCharSend;
case 'd' : // ns delay for n seconds/milliseconds
case 'w' :
temp = command[pos] == 'd' ? NextCharDelay : NextCharWait;
long milliseconds = 0;
while (isdigit(command[++pos]))
milliseconds = milliseconds*10 + command[pos] - '0';
if (milliseconds <= 0)
milliseconds = 1;
if (command[pos] == 'm')
pos++;
else {
milliseconds *= 1000;
if (command[pos] == 's')
pos++;
}
if (time != NULL)
*time = milliseconds;
return temp;
}
if (command[pos] < '0' || command[pos] > '7')
return command[pos++];
// octal number
temp = command[pos++] - '0';
if (command[pos] < '0' || command[pos] > '7')
return temp;
temp += command[pos++] - '0';
if (command[pos] < '0' || command[pos] > '7')
return temp;
temp += command[pos++] - '0';
return temp;
}
BOOL PChannel::ReceiveCommandString(int nextChar,
const PString & reply, PINDEX & pos, PINDEX start)
{
if (nextChar != GetNextChar(reply, pos)) {
pos = start;
return FALSE;
}
PINDEX dummyPos = pos;
return GetNextChar(reply, dummyPos) < 0;
}
BOOL PChannel::SendCommandString(const PString & command)
{
abortCommandString = FALSE;
int nextChar;
PINDEX sendPosition = 0;
PTimeInterval timeout;
SetWriteTimeout(10000);
while (!abortCommandString) { // not aborted
nextChar = GetNextChar(command, sendPosition, &timeout);
switch (nextChar) {
default :
if (!WriteChar(nextChar))
return FALSE;
break;
case NextCharEndOfString :
return TRUE; // Success!!
case NextCharSend :
break;
case NextCharDelay : // Delay in send
PThread::Current()->Sleep(timeout);
break;
case NextCharWait : // Wait for reply
PINDEX receivePosition = sendPosition;
if (GetNextChar(command, receivePosition) < 0) {
SetReadTimeout(timeout);
while (ReadChar() >= 0)
if (abortCommandString) // aborted
return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -