You ( Leigh Johnston ) replied ( to me ):
> > Reading HTTP, NNTP, IMAP, SMTP etc.; UTF 8|16 or binary:
> [ vomit puddle snipped ]
>
> Your coding style, including the use of "goto",
> is egregious, mate.
> Please stop spamming your shit to this newsgroup.
"#define" and "goto" are like fast cars;
Yes, they're dangerous, but I _love them anyway.
The code I post here not for you, or anyone else,
but for myself, so I can think about it, and change it;
I'm changing it now, and continue doing so.
Whenever you see a lot of WhiteSpace and comments,
as here, you know _immediately that there's _problems.
My latest:
// "Text" servers give you bits and pieces, line fragments.
// "gFull()", below, ensures that you get full lines;
// or, optionally, a full header ( HTTP, NNTP, IMAP ).
int gFull() { int rv, Ch0, Ch, Ch2, Room, _FullHdr, Done ; double Mark ;
_LnP B, P, E ; _FullHdr = FullHdr, Ch = FullHdr = Done = 0 ;
// "P_In" marks the start of a _full line, or a _full header;
// Initially: P_In = E_In = B_In ; uchar B_In[ OneMeg ];
// E_In is the end of the received data;
// here, it's extended by szII, the size of the previous line fragment.
*LnP(E_In) = Ch_E_In, E_In += szII, szII = Ch_E_In = *LnP(E_In) = 0 ;
if ( ( B_Chunk ? B_Chunk : P_In ) >= E_In ) {
// Previous data has been used up, get more.
// In a "Transfer-Encoding" "chunked" body,
// "B_Chunk" points to a "chunk header".
//
// Return here, to "Recv:", to get a _Full line|header.
Recv: if ( rv = P_In - B_In )
// Reclaim space; memmove() "P_In" to "B_In[]".
memmove( B_In, P_In, E_In - P_In + 2 ),
P_In -= rv, E_In -= rv, !B_Chunk ? 0 : ( B_Chunk -= rv ) ;
// Calculate the (free) buffer size and start the timer.
*E_In = 0, Room = OneMeg - ( E_In - B_In ) - 9, Mark = Secs ;
if ( Room < 99 ) {
Notice( L"No Header ( or line ) may exceed 1 MegaByte." ),
disConn; Rtn(-1); }
LOOP {
if ( Sz = recv( Connected, __LnP( E_In ), Room, 0 ),
!Sz && ( E_Art = E_In + Sz, Done = _ViaHTTP ) || Sz > 0 )
// Got data. When "Done", "E_Art" marks the end.
goto OnLine ;
if ( rv = WSAGetLastError(), rv == WSAEWOULDBLOCK ) {
// Wait on the server.
if ( Secs > Mark + Time_Out ) {
Notice( L"The User Timed Out, %d seconds.", Time_Out ),
disConn; Rtn(-2); }
if ( Respond(), Game != ServerIO )
// The User Canceled the DownLoad.
Rtn(-3); continue ; }
Notice( L"The Server Timed Out, WSAGetLastError(): %d.", rv ),
disConn; Rtn(-4); }
// Got Data; Null and "E_In" mark the end.
OnLine: E_In += Sz, *LnP(E_In) = Ch_E_In = 0 ; }
if ( Done || _BinBody ) Rtn(0);
if ( P = P_In, _FullHdr ) {
// When it's just a header, no body,
// we need the "\r\n.\r\n"; otherwise get "\r\n\r\n".
LoopP( Ch != 13 || Ch2 != 10 || !( Ch0 == 10 || Ch0 == '.' && P[-2] == 10 ) );
Ch = Ch2 ; }
// Headers and such _Must end in CR LF ( 13, 10 );
// "InBody", 13 and/or 10 is OK.
else if ( !InBody ) { LoopP( Ch != 10 ); }
else if ( !UTF16 ) { LoopP( !CRorLF ); }
else { LnP P = LnP( P_In ), B = P ; LoopP( !CRorLF ); }
if ( !Ch )
// No full Header|Line, just a fragment; ReadIn more.
goto Recv;
if ( !InBody ) Rtn(0);
// Scan backwards for the line fragment, in the body.
if ( B = P_In, E = E_In, !UTF16 )
while( E > B && ( Ch = *--E, !CRorLF ) );
else while( E - 1 > B && ( *--E || ( Ch = *--E, !CRorLF ) ) );
// An OK download, got one full line, at least.
// "szII", "E_In" and "Ch_E_In" MarkOff the line fragment.
E += 1 + UTF16, szII = E_In - E, E_In = E,
Ch_E_In = *LnP(E_In), *LnP(E_In) = 0 ; Rtn(0); }
Near Globals:
const int OneMeg = 999000 ;
#define Rtn( Err ) return !( ErrDia = Err )
// "ErrDia" holds a ServerDialog Error.
int ErrDia, UTF16, _ViaHTTP, _BinBody, szII, FullHdr, InBody ;
wchar Ch_E_In ; uchar B_In[ OneMeg ];
_LnP B_Chunk, P_In, E_In, E_Art ;
Far Globals:
const int szChr = sizeof( wchar );
typedef wchar_t wchar ; typedef unsigned char uchar ;
typedef wchar *LnP ; typedef uchar *_LnP ; typedef char *__LnP ;
typedef LARGE_INTEGER DubInt ;
#define Tics ( QueryPerformanceCounter( ( DubInt * ) & _Tics ), _Tics )
#define Secs ( _Secs = Tics / _Hz )
#define CRorLF ( Ch == 13 || Ch == 10 )
// "LoopP()" loops P through a null terminated line.
// When "Bool" allows, it loops up to, and including, the null,
// setting Ch0, Ch, and Ch2 ( for Bool ), as it goes.
#define LoopP( Bool ) Ch = 1, Ch2 = 0, P-- ; \
while( ( Ch0 = Ch ) && ( Ch = *++P, Ch2 = !Ch ? 0 : P[1], Bool ) )