home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************
- * *
- * Module: ramstream.c (part of gstream package) *
- * *
- * Version: 0.01 *
- * *
- * Author: Simon Proven *
- * *
- * Owner: Simon Proven 1993 *
- * *
- * Purpose: To provide gstream access to the wimp RAM *
- * transfer protcol. *
- * *
- * Uses: gstream, wimp, event, werr, flex, win, wimpt *
- * *
- * Conditions: *
- * You can produce and sell executable code from *
- * this module freely. The source code may be *
- * distributed freely, but not for profit. *
- * *
- * If you like these modules alot, and use them *
- * in your own programs, feel free to thank me *
- * with cash - 10 or more will get you a disc *
- * with the latest versions and new stream types. *
- * *
- * Disclaimer: *
- * This software is supplied in good faith, but I *
- * cannot accept liability for any loss incurred *
- * through the use or inability to use any part *
- * of this software. *
- * *
- * How to contact me: *
- * *
- * email: snail mail: *
- * sproven@cs.strath.ac.uk Simon Proven, *
- * Castle Cottage, *
- * Portencross, *
- * West Kilbride, *
- * KA23 9QA *
- * SCOTLAND *
- * *
- * Tel. (+44) 294 829 721 *
- * *
- *************************************************************/
-
- #include "gstream.h"
- #include "wimp.h"
- #include "event.h"
- #include "werr.h"
- #include "flex.h"
- #include "win.h"
- #include "wimpt.h"
-
-
- typedef struct
- {
- wimp_t task; /* recieving task's handle */
- int their_ref; /* my_ref of last message recieved */
- int our_ref; /* my_ref of last message sent */
- int their_bufsize; /* size of their buffer */
- char *their_buffer; /* address of their buffer */
- int written; /* number of bytes written to their buffer */
- int failed; /* flag for failed */
- int busy; /* busy flag */
- int finished;
- } ramsend_str;
-
- typedef struct
- {
- wimp_t task;
- int their_ref;
- int our_ref;
- int failed;
- int busy;
- void *buffer;
- size_t nbytes;
- int finished;
- } ramfetch_str;
-
- static int ramfetch(void *ptr, size_t nbytes, gstream *stream)
- {
- os_error *e;
- wimp_msgstr msg;
- ramfetch_str **data=(ramfetch_str **) &(stream->data);
-
- if ((**data).finished)
- return 0;
-
- msg.hdr.action=wimp_MRAMFETCH;
- msg.hdr.size=sizeof(wimp_msghdr)+sizeof(wimp_msgramfetch);
- msg.hdr.your_ref=(**data).their_ref;
- msg.data.ramfetch.addr=(char *) ptr;
- msg.data.ramfetch.nbytes=nbytes;
-
-
- e=wimp_sendmessage(wimp_ESENDWANTACK,&msg,(**data).task);
- if (e!=NULL)
- {
- wimpt_complain(e);
- return -1;
- }
-
- (**data).our_ref=msg.hdr.my_ref;
- (**data).buffer=ptr;
- (**data).busy=TRUE;
- (**data).failed=FALSE;
- do { event_process(); } while ((**data).busy);
- if ((**data).failed)
- return -1;
- if ((**data).nbytes<nbytes)
- (**data).finished=TRUE;
- return (**data).nbytes;
- }
-
- static size_t readram(void *ptr, size_t nbytes, void *s)
- {
- gstream *stream=(gstream *) s;
- int n;
-
-
- if (nbytes==0)
- return 0;
-
- n=ramfetch(ptr,nbytes,stream);
- if (n<0)
- return 0;
- else
- return((size_t) n);
-
- }
- /* this function deals with the unknown wimp events for
- * the ramsend stream type. It is only interested in
- * wimp_MRAMFETCH types
- */
-
- static int ramsend_unknowns(wimp_eventstr *e, void *handle)
- {
- gstream *stream=(gstream *) handle;
- ramsend_str **data=(ramsend_str **) &(stream->data);
-
- switch(e->e)
- {
- case wimp_ESEND:
- case wimp_ESENDWANTACK:
- if (e->data.msg.hdr.your_ref==(**data).our_ref)
- {
- switch (e->data.msg.hdr.action)
- {
- case wimp_MRAMFETCH:
- (**data).their_ref=e->data.msg.hdr.my_ref;
- (**data).their_bufsize=e->data.msg.data.ramfetch.nbytes;
- (**data).their_buffer=e->data.msg.data.ramfetch.addr;
- (**data).busy=FALSE;
- return(TRUE);
- default:
- return(FALSE);
- }
- }
- else
- return FALSE;
- case wimp_EACK:
- if (e->data.msg.hdr.my_ref==(**data).our_ref)
- {
- werr(FALSE,"RAM transfer failed: reciever died");
- (**data).failed=TRUE;
- (**data).busy=FALSE;
- return(TRUE);
- }
- else
- return(FALSE);
- default:
- return(FALSE);
- }
- }
-
- /* this function deals with the unknown wimp events for
- * the ramfetch stream type. It is only interested in
- * wimp_MRAMTRANSMIT types
- */
-
- static int ramfetch_unknowns(wimp_eventstr *e, void *handle)
- {
- gstream *stream=(gstream *) handle;
- ramfetch_str **data=(ramfetch_str **) &(stream->data);
-
- switch(e->e)
- {
- case wimp_ESEND:
- case wimp_ESENDWANTACK:
- if (e->data.msg.hdr.your_ref==(**data).our_ref)
- {
- switch (e->data.msg.hdr.action)
- {
- case wimp_MRAMTRANSMIT:
- (**data).their_ref=e->data.msg.hdr.my_ref;
- (**data).nbytes=e->data.msg.data.ramtransmit.nbyteswritten;
- (**data).busy=FALSE;
- return(TRUE);
- default:
- return(FALSE);
- }
- }
- else
- return FALSE;
- case wimp_EACK:
- if (e->data.msg.hdr.my_ref==(**data).our_ref)
- {
- werr(FALSE,"Protocol failed");
- (**data).failed=TRUE;
- (**data).busy=FALSE;
- return(TRUE);
- }
- else
- return(FALSE);
- default:
- return(FALSE);
- }
- }
-
- /* this function sends the wimp_MRAMFETCH message to the destination
- * task, and waits for a reply. It should only be called when the
- * destination task's buffer is full or when the stream is being
- * closed
- */
-
- static int ramsend(gstream *stream)
- {
- os_error *e;
- wimp_msgstr msg;
-
- ramsend_str **data=(ramsend_str **) &(stream->data);
-
-
- msg.hdr.action=wimp_MRAMTRANSMIT;
- msg.hdr.size=sizeof(wimp_msghdr)+sizeof(wimp_msgramtransmit);
- msg.hdr.your_ref=(**data).their_ref;
- msg.data.ramtransmit.addr=(**data).their_buffer;
- msg.data.ramtransmit.nbyteswritten=(**data).written;
-
- if ((**data).their_bufsize==(**data).written)
- {
- e=wimp_sendmessage(wimp_ESENDWANTACK,&msg,(**data).task);
- if (e!=NULL)
- {
- wimpt_complain(e);
- return(FALSE);
- }
- (**data).our_ref=msg.hdr.my_ref;
- (**data).busy=TRUE;
- (**data).failed=FALSE;
- do { event_process(); } while ((**data).busy);
- if ((**data).failed)
- return(FALSE);
- (**data).written=0;
- }
- else
- {
- e=wimp_sendmessage(wimp_ESEND,&msg,(**data).task);
- if (e!=NULL)
- {
- wimpt_complain(e);
- return(FALSE);
- }
- (**data).written=0;
- (**data).finished=TRUE;
- }
- return(TRUE);
- }
-
- /* this function sends the data currently in the buffer to the
- * recieving task.
- */
-
- static size_t writeram(void *ptr, size_t nbytes, void *s)
- {
- gstream *stream=(gstream *) s;
- size_t pos=0;
- os_error *e;
- ramsend_str **data=(ramsend_str **) &(stream->data);
-
-
- while ((nbytes-pos)>0)
- {
- if ((**data).written==(**data).their_bufsize)
- if (!ramsend(stream))
- {
- stream->error=TRUE;
- return 0;
- }
-
- if (((**data).their_bufsize-(**data).written)>=(nbytes-pos))
- {
- e=wimp_transferblock( wimpt_task(),
- (char *) ptr+pos,
- (**data).task,
- (char *) (**data).their_buffer+(**data).written,
- nbytes-pos);
- if (e!=NULL)
- {
- stream->error=TRUE;
- wimpt_complain(e);
- return 0;
- }
- (**data).written+=nbytes-pos;
- pos=nbytes;
- }
- else
- {
- e=wimp_transferblock( wimpt_task(),
- (char *) ptr+pos,
- (**data).task,
- (**data).their_buffer+(**data).written,
- (**data).their_bufsize-(**data).written);
- if (e!=NULL)
- {
- stream->error=TRUE;
- wimpt_complain(e);
- return pos;
- }
- pos+=(**data).their_bufsize-(**data).written;
- (**data).written=(**data).their_bufsize;
- }
- }
- return pos;
- }
-
- /* this function closes a RAM_FETCH stream */
-
- static int gscloseramfetch(void *s)
- {
- gstream *stream=(gstream *) s;
- char dummy[256];
-
- while(readram(dummy,256,stream)!=0)
- ;
-
- win_remove_unknown_event_processor(ramfetch_unknowns,(void *)stream);
-
- flex_free(&(stream->data));
-
- return TRUE;
- }
-
- /* this function closes a RAM_SEND stream */
-
- static int gscloseramsend(void *s)
- {
- gstream *stream=(gstream *) s;
-
- ramsend_str **data=(ramsend_str **) &(stream->data);
-
-
- if (!stream->error)
- {
- if ((**data).written==(**data).their_bufsize)
- ramsend(stream);
- if (!stream->error)
- ramsend(stream);
- }
-
- win_remove_unknown_event_processor(ramsend_unknowns,(void *)stream);
-
- flex_free(&(stream->data));
-
- if (!stream->error)
- return TRUE;
- else
- return FALSE;
- }
-
- /* this function should be called to respond to a RAMFetch
- * message - in other words, after we have requested to
- * send data to an application, if we get a RAMFetch then
- * this function can be used to open the stream to send
- * the data.
- *
- * msg should point to the RAMFetch message just send from
- * the target task
- */
-
- int gsopenramsend(wimp_msgstr *msg, gstream *stream)
- {
- ramsend_str **data;
-
- stream->bufsize=gs_BUFSIZE;
- stream->size=0;
- stream->pos=0;
- stream->type=WRITE;
- stream->error=FALSE;
-
- stream->io.write=writeram;
- stream->close=gscloseramsend;
-
- if (!flex_alloc(&(stream->data),sizeof(ramsend_str)))
- {
- werr(FALSE,"Not enough space");
- return FALSE;
- }
-
- data=(ramsend_str **) &(stream->data);
-
- if ((stream->bufsize=gsgetbuf(&(stream->buffer),stream->bufsize,4))==0)
- {
- werr(FALSE,"Not enough space");
- flex_free(&(stream->data));
- return(FALSE);
- }
- else
- {
- (**data).task=msg->hdr.task;
- (**data).their_ref=msg->hdr.my_ref;
- (**data).their_bufsize=msg->data.ramfetch.nbytes;
- (**data).their_buffer=msg->data.ramfetch.addr;
- (**data).written=0;
- (**data).failed=FALSE;
- (**data).finished=FALSE;
- win_add_unknown_event_processor(ramsend_unknowns,(void *)stream);
- return TRUE;
- }
- }
-
- /* This function should be called if we get a datasave message.
- * It will attempt to open a stream to fetch data directly from
- * the sending application via the RAM transfer protocol. The
- * sending application may not be interested - if this happens
- * then this function will return FALSE and the program should
- * resort to the scrap file method.
- *
- * msg should point to the DataSave message just recieved
- */
-
- int gsopenramfetch(wimp_msgstr *msg, gstream *stream)
- {
-
- ramfetch_str **data;
-
- if (msg->hdr.task==wimpt_task())
- {
- werr(FALSE,"Sorry, I'm not talking to myself");
- return FALSE;
- }
-
- stream->bufsize=gs_BUFSIZE;
- stream->size=0;
- stream->pos=0;
- stream->type=READ;
- stream->ungetsize=0;
- stream->error=FALSE;
-
- stream->io.read=readram;
- stream->close=gscloseramfetch;
-
- if (!flex_alloc(&(stream->data),sizeof(ramfetch_str)))
- {
- werr(FALSE,"Not enough space");
- return 2;
- }
-
- data=(ramfetch_str **) &(stream->data);
-
- if ((stream->bufsize=gsgetbuf(&(stream->buffer),stream->bufsize,4))==0)
- {
- werr(FALSE,"Not enough space");
- flex_free(&(stream->data));
- return 2;
- }
- else
- {
- stream->ungetsize=0;
- stream->ungetpos=0;
- (**data).task=msg->hdr.task;
- (**data).their_ref=msg->hdr.my_ref;
- (**data).our_ref=msg->hdr.your_ref;
- (**data).finished=FALSE;
- win_add_unknown_event_processor(ramfetch_unknowns,(void *)stream);
-
- if ((stream->size=ramfetch(stream->buffer,stream->bufsize,stream))>=0)
- return 1;
- else
- {
- flex_free(&(stream->buffer));
- flex_free(&(stream->data));
- win_remove_unknown_event_processor(ramfetch_unknowns,(void *)stream);
- return 0;
- }
- }
- }
-
-