gopher/readline2.c

250 lines
5.0 KiB
C
Raw Normal View History

2012-04-15 03:40:35 +00:00
#pragma optimize 79
2012-04-28 01:18:31 +00:00
#pragma noroot
2012-04-15 03:40:35 +00:00
2012-04-08 18:19:26 +00:00
#include "readline2.h"
#include <tcpipx.h>
#include <memory.h>
#include <stdio.h>
2012-04-08 18:19:26 +00:00
2012-04-08 19:13:46 +00:00
static LongWord find_crlf(const char *cp, LongWord length)
2012-04-08 18:19:26 +00:00
{
2012-04-08 19:13:46 +00:00
LongWord rv;
2012-04-08 18:19:26 +00:00
2012-04-08 19:13:46 +00:00
rv = 0;
2012-04-08 18:19:26 +00:00
2012-04-08 19:13:46 +00:00
asm {
// scan all the full blocks.
ldy #0
ldx length+2
beq remainder
loop1:
lda [<cp],y
and #0xff
cmp #'\r'
beq match
cmp #'\n'
beq match
iny
bne loop1
// scanned a full bank, increment cp && rv
// decrement x
inc <cp+2
inc <rv+2
dex
bne loop1
// if x = 0, drop to remainder bytes.
remainder:
// scan non-full bank
// y = 0
// x is the counter var.
ldx <length
beq done
loop2:
lda [<cp],y
and #0xff
cmp #'\r'
beq match
cmp #'\n'
beq match
iny
dex
beq done
bra loop2
match:
sty <rv
bra exit
done:
lda #-1
sta <rv
sta <rv+2
exit:
}
2012-04-08 18:19:26 +00:00
2012-04-08 19:13:46 +00:00
return rv;
2012-04-08 18:19:26 +00:00
}
2012-04-08 19:13:46 +00:00
2012-04-08 18:19:26 +00:00
/*
* read a line terminated by \r\n, \r, or \n
*
* Returns:
* -1: eof (but may still have data)
* 0: no data read
* 1: data read (but may be an empty string)
2012-04-08 18:19:26 +00:00
*/
int ReadLine2(Word ipid, rlBuffer *buffer)
2012-04-08 18:19:26 +00:00
{
userRecordHandle urh;
userRecordPtr ur;
2012-04-09 01:29:03 +00:00
2012-04-08 19:13:46 +00:00
char *cp;
2012-04-08 18:19:26 +00:00
Handle h;
LongWord hsize;
LongWord size;
Word term;
2012-04-09 01:29:03 +00:00
Word tlen;
Word state;
2012-04-08 18:19:26 +00:00
if (!buffer) return -1; // ?
2012-04-09 01:29:03 +00:00
2012-04-10 04:18:59 +00:00
buffer->bufferHandle = NULL;
2012-04-09 01:29:03 +00:00
buffer->bufferSize = 0;
2012-04-08 18:19:26 +00:00
buffer->terminator = 0;
2012-04-09 01:29:03 +00:00
buffer->moreFlag = 0;
2012-04-08 18:19:26 +00:00
urh = TCPIPGetUserRecord(ipid);
if (_toolErr || !urh) return -1;
2012-04-08 18:19:26 +00:00
ur = *urh;
2012-04-09 01:29:03 +00:00
state = ur->uwTCP_State;
// TCPREAD returns a resource error for these.
if (state == TCPSCLOSED) return -1;
if (state < TCPSESTABLISHED) return 0;
2012-04-09 01:29:03 +00:00
2012-04-10 04:18:59 +00:00
h = (Handle)ur->uwTCPDataIn;
2012-04-09 01:29:03 +00:00
// should never happen....
if (!h) return -1;
2012-04-08 19:13:46 +00:00
cp = *(char **)h;
2012-04-08 18:19:26 +00:00
hsize = GetHandleSize(h);
2012-04-09 01:29:03 +00:00
if (!hsize)
2012-04-08 18:19:26 +00:00
{
if (state >= TCPSCLOSEWAIT) return -1;
2012-04-08 18:19:26 +00:00
return 0;
}
2012-04-09 01:29:03 +00:00
size = find_crlf(cp, hsize);
2012-04-09 01:29:03 +00:00
// -1 = not found.
if (size == 0xffffffff)
2012-04-08 18:19:26 +00:00
{
2012-04-09 01:29:03 +00:00
// if state >= CLOSEWAIT, assume no more data incoming
// and return as-is w/o terminator.
2012-04-09 01:29:03 +00:00
// if state < TCPSCLOSEWAIT, the terminator has not yet been
// received, so don't return anything.
// tcpread does an implied push if state == tcpsCLOSEWAIT
if (state < TCPSCLOSEWAIT)
{
buffer->moreFlag = 1;
return 0;
}
term = 0;
tlen = 0;
2012-04-08 18:19:26 +00:00
}
else
2012-04-09 01:29:03 +00:00
{
hsize -= size;
cp += size;
// check for \r\n
term = *(Word *)cp;
if (term == 0x0a0d && hsize >= 2)
{
tlen = 2;
}
else
{
term &= 0x00ff;
tlen = 1;
}
2012-04-08 18:19:26 +00:00
}
// read the data.
// read will stop reading if there was a push.
// if using \r\n, there could be something stupid like a push
// in the middle, so read it in and then shrink it afterwards.
2012-04-08 18:19:26 +00:00
//
2012-04-08 19:13:46 +00:00
// 99% of the time, it should just be one read, but generating
// the handle now and reading into a pointer keeps it simpler
// for the case where that is not the case.
2012-04-08 19:13:46 +00:00
2012-04-09 01:29:03 +00:00
// size = data to return
// hsize = data to read.
2012-04-08 19:13:46 +00:00
hsize = size + tlen;
h = NewHandle(hsize, ur->uwUserID, attrNoSpec | attrLocked, 0);
2012-04-09 01:29:03 +00:00
if (_toolErr) return tcperrNoResources;
2012-04-08 18:19:26 +00:00
2012-04-09 01:29:03 +00:00
buffer->bufferSize = size;
buffer->bufferHandle = h;
2012-04-10 04:18:59 +00:00
buffer->terminator = term;
2012-04-08 19:13:46 +00:00
cp = *(char **)h;
while (hsize)
2012-04-08 18:19:26 +00:00
{
2012-04-09 01:29:03 +00:00
Word rv;
rrBuff rb;
2012-04-10 04:18:59 +00:00
rv = TCPIPReadTCP(ipid, 0, (Ref)cp, hsize, &rb);
2012-04-09 01:29:03 +00:00
// tcperrConClosing is the only possible error
// (others were handled above via the state).
if (rb.rrBuffCount > hsize)
{
asm {
brk 0xea
lda <h
ldx <h+2
lda <cp
ldx <cp+2
lda <hsize
ldx <hsize+2
}
}
2012-04-08 19:13:46 +00:00
hsize -= rb.rrBuffCount;
2012-04-09 01:29:03 +00:00
cp += rb.rrBuffCount;
buffer->moreFlag = rb.rrMoreFlag;
// should never hang in an infinite loop.
2012-04-08 18:19:26 +00:00
}
if (tlen)
{
// remove the delimiter
// if line length is 0, dispose the handle entirely.
2012-04-08 19:13:46 +00:00
// term will be set to indicate it's a blank line.
2012-04-08 18:19:26 +00:00
if (!size)
{
DisposeHandle(h);
2012-04-09 01:29:03 +00:00
buffer->bufferHandle = 0;
2012-04-08 18:19:26 +00:00
}
else
{
SetHandleSize(size, h);
}
}
// if closing and no more data, return -1
// else return 1.
// eh, let them make another call.
//if (state > TCPSCLOSEWAIT && rb->moreFlag == 0)
// return -1;
return 1;
}