/* HTANSI.c
** ANSI C FILE DESCRIPTOR TRANSPORT
**
** (c) COPYRIGHT MIT 1995.
** Please first read the full copyright statement in the file COPYRIGH.
** @(#) $Id: HTANSI.c,v 2.2 1996/05/15 22:33:54 eric Exp $
**
** History:
** HFN: writtem
*/
/* Library include files */
#include "sysdep.h"
#include "WWWUtil.h"
#include "HTError.h"
#include "HTBind.h"
#include "HTAlert.h"
#include "HTParse.h"
#include "HTReq.h"
#include "HTChannl.h"
#include "HTIOStream.h"
#include "HTNetMan.h"
#include "HTANSI.h" /* Implemented here */
struct _HTStream {
const HTStreamClass * isa;
/* ... */
};
struct _HTInputStream {
const HTInputStreamClass * isa;
HTChannel * ch;
HTNet * net;
FILE * fp;
HTStream * target;
char * write; /* Last byte written */
char * read; /* Last byte read */
char data [FILE_BUFFER_SIZE];
};
struct _HTOutputStream {
const HTOutputStreamClass * isa;
HTChannel * ch;
HTNet * net;
FILE * fp;
};
/* ------------------------------------------------------------------------- */
/* READ STREAM */
/* ------------------------------------------------------------------------- */
PRIVATE int HTANSIReader_flush (HTInputStream * me)
{
return me->target ? (*me->target->isa->flush)(me->target) : HT_OK;
}
PRIVATE int HTANSIReader_free (HTInputStream * me)
{
if (me->target) {
int status = (*me->target->isa->_free)(me->target);
if (status != HT_WOULD_BLOCK) me->target = NULL;
return status;
}
return HT_OK;
}
PRIVATE int HTANSIReader_abort (HTInputStream * me, HTList * e)
{
if (me->target) {
(*me->target->isa->abort)(me->target, NULL);
me->target = NULL;
}
return HT_ERROR;
}
PRIVATE int HTANSIReader_read (HTInputStream * me)
{
HTNet * net = me->net;
FILE * fp = net->fp;
int b_read;
int status;
/* Read the file desriptor */
while (fp) {
if ((b_read = fread(me->data, 1, FILE_BUFFER_SIZE, fp)) == 0){
if (ferror(fp)) {
if (PROT_TRACE) HTTrace("ANSI read... READ ERROR\n");
} else {
HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
if (PROT_TRACE)
HTTrace("ANSI read... Finished loading file %p\n", fp);
if (cbf) (*cbf)(net->request, HT_PROG_DONE,
HT_MSG_NULL, NULL, NULL, NULL);
return HT_CLOSED;
}
}
/* Remember how much we have read from the input socket */
me->write = me->data;
me->read = me->data + b_read;
if (PROT_TRACE)
HTTrace("ANSI read... %d bytes read from file %p\n", b_read, fp);
{
HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
net->bytes_read += b_read;
if (cbf) (*cbf)(net->request, HT_PROG_READ,
HT_MSG_NULL, NULL, NULL, NULL);
}
/* Now push the data down the stream */
if ((status = (*me->target->isa->put_block)
(me->target, me->data, b_read)) != HT_OK) {
if (status == HT_WOULD_BLOCK) {
if (PROT_TRACE) HTTrace("ANSI read... Target WOULD BLOCK\n");
#if 0
HTEvent_unregister(soc, FD_READ);
#endif
return HT_WOULD_BLOCK;
} else if (status == HT_PAUSE) {
if (PROT_TRACE) HTTrace("ANSI read... Target PAUSED\n");
#if 0
HTEvent_unregister(soc, FD_READ);
#endif
return HT_PAUSE;
} else if (status > 0) { /* Stream specific return code */
if (PROT_TRACE)
HTTrace("ANSI read... Target returns %d\n", status);
me->write = me->data + b_read;
return status;
} else { /* We have a real error */
if (PROT_TRACE) HTTrace("ANSI read... Target ERROR\n");
return status;
}
}
me->write = me->data + b_read;
}
if (PROT_TRACE) HTTrace("ANSI read... File descriptor is NULL...\n");
return HT_ERROR;
}
/*
** The difference between the close and the free method is that we don't
** close the connection in the free method - we only call the free method
** of the target stream. That way, we can keep the output stream as long
** as the channel itself.
*/
PRIVATE int HTANSIReader_close (HTInputStream * me)
{
if (PROT_TRACE) HTTrace("ANSI read... FREEING...\n");
HT_FREE(me);
return HT_OK;
}
PRIVATE const HTInputStreamClass HTANSIReader =
{
"ANSIReader",
HTANSIReader_flush,
HTANSIReader_free,
HTANSIReader_abort,
HTANSIReader_read,
HTANSIReader_close
};
PUBLIC HTInputStream * HTANSIReader_new (HTNet * net, HTChannel * ch,
HTStream * target, void * param,
int mode)
{
if (net && ch) {
HTInputStream * me = HTChannel_input(ch);
if (me == NULL) {
if ((me=(HTInputStream *) HT_CALLOC(1, sizeof(HTInputStream))) == NULL)
HT_OUTOFMEM("HTANSIReader_new");
me->isa = &HTANSIReader;
me->ch = ch;
}
me->target = target;
me->net = net;
me->fp = net->fp;
return me;
}
return NULL;
}
/* ------------------------------------------------------------------------- */
/* WRITE STREAM */
/* ------------------------------------------------------------------------- */
PRIVATE int HTANSIWriter_flush (HTOutputStream * me)
{
return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
}
PRIVATE int HTANSIWriter_free (HTOutputStream * me)
{
return HT_OK;
}
PRIVATE int HTANSIWriter_abort (HTOutputStream * me, HTList * e)
{
if (PROT_TRACE) HTTrace("ANSI write.. ABORTING...\n");
return HT_ERROR;
}
PRIVATE int HTANSIWriter_character (HTOutputStream * me, char c)
{
return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
}
PRIVATE int HTANSIWriter_string (HTOutputStream * me, const char* s)
{
if (*s) /* For vms :-( 10/04-94 */
return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
return HT_OK;
}
PRIVATE int HTANSIWriter_block (HTOutputStream * me, const char* s, int l)
{
int status ;
status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
if (l > 1 && status == HT_OK) (void) HTANSIWriter_flush(me);
return status;
}
/*
** The difference between the close and the free method is that we don't
** close the connection in the free method - we only call the free method
** of the target stream. That way, we can keep the output stream as long
** as the channel itself.
*/
PRIVATE int HTANSIWriter_close (HTOutputStream * me)
{
if (PROT_TRACE) HTTrace("ANSI write.. FREEING...\n");
HT_FREE(me);
return HT_OK;
}
PRIVATE const HTOutputStreamClass HTANSIWriter =
{
"ANSIWriter",
HTANSIWriter_flush,
HTANSIWriter_free,
HTANSIWriter_abort,
HTANSIWriter_character,
HTANSIWriter_string,
HTANSIWriter_block,
HTANSIWriter_close
};
PUBLIC HTOutputStream * HTANSIWriter_new (HTNet * net, HTChannel * ch,
void * param, int mode)
{
if (net && ch) {
HTOutputStream * me = HTChannel_output(ch);
if (me == NULL) {
if ((me=(HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL)
HT_OUTOFMEM("HTANSIWriter_new");
me->isa = &HTANSIWriter;
me->ch = ch;
}
me->net = net;
me->fp = net->fp;
return me;
}
return NULL;
}
Webmaster