home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / d / gstream / c / ramstream < prev    next >
Encoding:
Text File  |  1993-05-08  |  12.1 KB  |  489 lines

  1. /*************************************************************
  2. *                                                            *
  3. *    Module: ramstream.c (part of gstream package)           *
  4. *                                                            *
  5. *   Version: 0.01                                            *
  6. *                                                            *
  7. *    Author: Simon Proven                                    *
  8. *                                                            *
  9. *     Owner:  Simon Proven 1993                             *
  10. *                                                            *
  11. *   Purpose: To provide gstream access to the wimp RAM       *
  12. *            transfer protcol.                               *
  13. *                                                            *
  14. *      Uses: gstream, wimp, event, werr, flex, win, wimpt    *
  15. *                                                            *
  16. * Conditions:                                                *
  17. *             You can produce and sell executable code from  *
  18. *             this module freely.  The source code may be    *
  19. *             distributed freely, but not for profit.        *
  20. *                                                            *
  21. *             If you like these modules alot, and use them   *
  22. *             in your own programs, feel free to thank me    *
  23. *             with cash - 10 or more will get you a disc    *
  24. *             with the latest versions and new stream types. *
  25. *                                                            *
  26. * Disclaimer:                                                *
  27. *             This software is supplied in good faith, but I *
  28. *             cannot accept liability for any loss incurred  *
  29. *             through the use or inability to use any part   *
  30. *             of this software.                              *
  31. *                                                            *
  32. * How to contact me:                                         *
  33. *                                                            *
  34. * email:                      snail mail:                    *
  35. * sproven@cs.strath.ac.uk     Simon Proven,                  *
  36. *                             Castle Cottage,                *
  37. *                             Portencross,                   *
  38. *                             West Kilbride,                 *
  39. *                             KA23 9QA                       *
  40. *                             SCOTLAND                       *
  41. *                                                            *
  42. * Tel. (+44) 294 829 721                                     *
  43. *                                                            *
  44. *************************************************************/
  45.  
  46. #include "gstream.h"
  47. #include "wimp.h"
  48. #include "event.h"
  49. #include "werr.h"
  50. #include "flex.h"
  51. #include "win.h"
  52. #include "wimpt.h"
  53.  
  54.  
  55. typedef struct
  56. {
  57.     wimp_t    task;        /* recieving task's handle */
  58.     int    their_ref;    /* my_ref of last message recieved */
  59.     int    our_ref;    /* my_ref of last message sent */
  60.     int    their_bufsize;    /* size of their buffer */
  61.     char     *their_buffer;    /* address of their buffer */
  62.     int    written;    /* number of bytes written to their buffer */
  63.     int    failed;        /* flag for failed */
  64.     int    busy;        /* busy flag */
  65.     int    finished;
  66. } ramsend_str;
  67.  
  68. typedef struct
  69. {
  70.     wimp_t    task;
  71.     int    their_ref;
  72.     int    our_ref;
  73.     int    failed;
  74.     int    busy;
  75.     void    *buffer;
  76.     size_t    nbytes;
  77.     int    finished;
  78. } ramfetch_str;
  79.  
  80. static int ramfetch(void *ptr, size_t nbytes, gstream *stream)
  81. {
  82.     os_error *e;
  83.     wimp_msgstr msg;
  84.     ramfetch_str **data=(ramfetch_str **) &(stream->data);
  85.  
  86.     if ((**data).finished)
  87.         return 0;
  88.  
  89.     msg.hdr.action=wimp_MRAMFETCH;
  90.     msg.hdr.size=sizeof(wimp_msghdr)+sizeof(wimp_msgramfetch);
  91.     msg.hdr.your_ref=(**data).their_ref;
  92.     msg.data.ramfetch.addr=(char *) ptr;
  93.     msg.data.ramfetch.nbytes=nbytes;
  94.  
  95.  
  96.     e=wimp_sendmessage(wimp_ESENDWANTACK,&msg,(**data).task);
  97.     if (e!=NULL)
  98.     {
  99.         wimpt_complain(e);
  100.         return -1;
  101.     }
  102.  
  103.     (**data).our_ref=msg.hdr.my_ref;
  104.     (**data).buffer=ptr;
  105.     (**data).busy=TRUE;
  106.     (**data).failed=FALSE;
  107.     do { event_process(); } while ((**data).busy);
  108.     if ((**data).failed)
  109.         return -1;
  110.     if ((**data).nbytes<nbytes)
  111.         (**data).finished=TRUE;
  112.     return (**data).nbytes;
  113. }
  114.  
  115. static size_t readram(void *ptr, size_t nbytes, void *s)
  116. {
  117.     gstream *stream=(gstream *) s;
  118.     int n;
  119.  
  120.  
  121.     if (nbytes==0)
  122.         return 0;
  123.  
  124.     n=ramfetch(ptr,nbytes,stream);
  125.     if (n<0)
  126.         return 0;
  127.     else
  128.         return((size_t) n);
  129.  
  130. }
  131. /* this function deals with the unknown wimp events for
  132.  * the ramsend stream type.  It is only interested in
  133.  * wimp_MRAMFETCH types
  134.  */
  135.  
  136. static int ramsend_unknowns(wimp_eventstr *e, void *handle)
  137. {
  138.     gstream *stream=(gstream *) handle;
  139.     ramsend_str **data=(ramsend_str **) &(stream->data);
  140.  
  141.     switch(e->e)
  142.     {
  143.         case wimp_ESEND:
  144.         case wimp_ESENDWANTACK:
  145.             if (e->data.msg.hdr.your_ref==(**data).our_ref)
  146.             {
  147.                 switch (e->data.msg.hdr.action)
  148.                 {
  149.                     case wimp_MRAMFETCH:
  150.                         (**data).their_ref=e->data.msg.hdr.my_ref;
  151.                         (**data).their_bufsize=e->data.msg.data.ramfetch.nbytes;
  152.                         (**data).their_buffer=e->data.msg.data.ramfetch.addr;
  153.                         (**data).busy=FALSE;
  154.                         return(TRUE);
  155.                     default:
  156.                         return(FALSE);
  157.                 }
  158.             }
  159.             else
  160.                 return FALSE;
  161.         case wimp_EACK:
  162.             if (e->data.msg.hdr.my_ref==(**data).our_ref)
  163.             {
  164.                 werr(FALSE,"RAM transfer failed: reciever died");
  165.                 (**data).failed=TRUE;
  166.                 (**data).busy=FALSE;
  167.                 return(TRUE);
  168.             }
  169.             else
  170.                 return(FALSE);
  171.         default:
  172.             return(FALSE);
  173.     }
  174. }
  175.  
  176. /* this function deals with the unknown wimp events for
  177.  * the ramfetch stream type.  It is only interested in
  178.  * wimp_MRAMTRANSMIT types
  179.  */
  180.  
  181. static int ramfetch_unknowns(wimp_eventstr *e, void *handle)
  182. {
  183.     gstream        *stream=(gstream *) handle;
  184.     ramfetch_str    **data=(ramfetch_str **) &(stream->data);
  185.  
  186.     switch(e->e)
  187.     {
  188.         case wimp_ESEND:
  189.         case wimp_ESENDWANTACK:
  190.             if (e->data.msg.hdr.your_ref==(**data).our_ref)
  191.             {
  192.                 switch (e->data.msg.hdr.action)
  193.                 {
  194.                     case wimp_MRAMTRANSMIT:
  195.                         (**data).their_ref=e->data.msg.hdr.my_ref;
  196.                         (**data).nbytes=e->data.msg.data.ramtransmit.nbyteswritten;
  197.                         (**data).busy=FALSE;
  198.                         return(TRUE);
  199.                     default:
  200.                         return(FALSE);
  201.                 }
  202.             }
  203.             else
  204.                 return FALSE;
  205.         case wimp_EACK:
  206.             if (e->data.msg.hdr.my_ref==(**data).our_ref)
  207.             {
  208.                 werr(FALSE,"Protocol failed");
  209.                 (**data).failed=TRUE;
  210.                 (**data).busy=FALSE;
  211.                 return(TRUE);
  212.             }
  213.             else
  214.                 return(FALSE);
  215.         default:
  216.             return(FALSE);
  217.     }
  218. }
  219.  
  220. /* this function sends the wimp_MRAMFETCH message to the destination
  221.  * task, and waits for a reply.  It should only be called when the
  222.  * destination task's buffer is full or when the stream is being
  223.  * closed
  224.  */
  225.  
  226. static int ramsend(gstream *stream)
  227. {
  228.     os_error *e;
  229.     wimp_msgstr msg;
  230.  
  231.     ramsend_str **data=(ramsend_str **) &(stream->data);
  232.  
  233.  
  234.     msg.hdr.action=wimp_MRAMTRANSMIT;
  235.     msg.hdr.size=sizeof(wimp_msghdr)+sizeof(wimp_msgramtransmit);
  236.     msg.hdr.your_ref=(**data).their_ref;
  237.     msg.data.ramtransmit.addr=(**data).their_buffer;
  238.     msg.data.ramtransmit.nbyteswritten=(**data).written;
  239.  
  240.     if ((**data).their_bufsize==(**data).written)
  241.     {
  242.         e=wimp_sendmessage(wimp_ESENDWANTACK,&msg,(**data).task);
  243.         if (e!=NULL)
  244.         {
  245.             wimpt_complain(e);
  246.             return(FALSE);
  247.         }
  248.         (**data).our_ref=msg.hdr.my_ref;
  249.         (**data).busy=TRUE;
  250.         (**data).failed=FALSE;
  251.         do { event_process(); } while ((**data).busy);
  252.         if ((**data).failed)
  253.             return(FALSE);
  254.         (**data).written=0;
  255.     }
  256.     else
  257.     {
  258.         e=wimp_sendmessage(wimp_ESEND,&msg,(**data).task);
  259.         if (e!=NULL)
  260.         {
  261.             wimpt_complain(e);
  262.             return(FALSE);
  263.         }
  264.         (**data).written=0;
  265.         (**data).finished=TRUE;
  266.     }
  267.     return(TRUE);
  268. }
  269.  
  270. /* this function sends the data currently in the buffer to the
  271.  * recieving task.
  272.  */
  273.  
  274. static size_t writeram(void *ptr, size_t nbytes, void *s)
  275. {
  276.     gstream        *stream=(gstream *) s;
  277.     size_t        pos=0;
  278.     os_error    *e;
  279.     ramsend_str    **data=(ramsend_str **) &(stream->data);
  280.  
  281.  
  282.     while ((nbytes-pos)>0)
  283.     {
  284.         if ((**data).written==(**data).their_bufsize)
  285.             if (!ramsend(stream))
  286.             {
  287.                 stream->error=TRUE;
  288.                 return 0;
  289.             }
  290.  
  291.         if (((**data).their_bufsize-(**data).written)>=(nbytes-pos))
  292.         {
  293.             e=wimp_transferblock(    wimpt_task(),
  294.                         (char *) ptr+pos,
  295.                         (**data).task,
  296.                         (char *) (**data).their_buffer+(**data).written,
  297.                         nbytes-pos);
  298.             if (e!=NULL)
  299.             {
  300.                 stream->error=TRUE;
  301.                 wimpt_complain(e);
  302.                 return 0;
  303.             }
  304.             (**data).written+=nbytes-pos;
  305.             pos=nbytes;
  306.         }
  307.         else
  308.         {
  309.             e=wimp_transferblock(    wimpt_task(),
  310.                         (char *) ptr+pos,
  311.                         (**data).task,
  312.                         (**data).their_buffer+(**data).written,
  313.                         (**data).their_bufsize-(**data).written);
  314.             if (e!=NULL)
  315.             {
  316.                 stream->error=TRUE;
  317.                 wimpt_complain(e);
  318.                 return pos;
  319.             }
  320.             pos+=(**data).their_bufsize-(**data).written;
  321.             (**data).written=(**data).their_bufsize;
  322.         }
  323.     }
  324.     return pos;
  325. }
  326.  
  327. /* this function closes a RAM_FETCH stream */
  328.  
  329. static int gscloseramfetch(void *s)
  330. {
  331.     gstream    *stream=(gstream *) s;
  332.     char dummy[256];
  333.  
  334.     while(readram(dummy,256,stream)!=0)
  335.         ;
  336.  
  337.     win_remove_unknown_event_processor(ramfetch_unknowns,(void *)stream);
  338.  
  339.     flex_free(&(stream->data));
  340.  
  341.     return TRUE;
  342. }
  343.  
  344. /* this function closes a RAM_SEND stream */
  345.  
  346. static int gscloseramsend(void *s)
  347. {
  348.     gstream *stream=(gstream *) s;
  349.  
  350.     ramsend_str **data=(ramsend_str **) &(stream->data);
  351.  
  352.  
  353.     if (!stream->error)
  354.     {
  355.         if ((**data).written==(**data).their_bufsize)
  356.             ramsend(stream);
  357.         if (!stream->error)
  358.             ramsend(stream);
  359.     }
  360.  
  361.     win_remove_unknown_event_processor(ramsend_unknowns,(void *)stream);
  362.  
  363.     flex_free(&(stream->data));
  364.  
  365.     if (!stream->error)
  366.         return TRUE;
  367.     else
  368.         return FALSE;
  369. }
  370.  
  371. /* this function should be called to respond to a RAMFetch
  372.  * message - in other words, after we have requested to
  373.  * send data to an application, if we get a RAMFetch then
  374.  * this function can be used to open the stream to send
  375.  * the data.
  376.  *
  377.  * msg should point to the RAMFetch message just send from
  378.  * the target task
  379.  */
  380.  
  381. int gsopenramsend(wimp_msgstr *msg, gstream *stream)
  382. {
  383.     ramsend_str **data;
  384.  
  385.     stream->bufsize=gs_BUFSIZE;
  386.     stream->size=0;
  387.     stream->pos=0;
  388.     stream->type=WRITE;
  389.     stream->error=FALSE;
  390.  
  391.     stream->io.write=writeram;
  392.     stream->close=gscloseramsend;
  393.  
  394.     if (!flex_alloc(&(stream->data),sizeof(ramsend_str)))
  395.     {
  396.         werr(FALSE,"Not enough space");
  397.         return FALSE;
  398.     }
  399.  
  400.     data=(ramsend_str **) &(stream->data);
  401.  
  402.     if ((stream->bufsize=gsgetbuf(&(stream->buffer),stream->bufsize,4))==0)
  403.     {
  404.         werr(FALSE,"Not enough space");
  405.         flex_free(&(stream->data));
  406.         return(FALSE);
  407.     }
  408.     else
  409.     {
  410.         (**data).task=msg->hdr.task;
  411.         (**data).their_ref=msg->hdr.my_ref;
  412.         (**data).their_bufsize=msg->data.ramfetch.nbytes;
  413.         (**data).their_buffer=msg->data.ramfetch.addr;
  414.         (**data).written=0;
  415.         (**data).failed=FALSE;
  416.         (**data).finished=FALSE;
  417.         win_add_unknown_event_processor(ramsend_unknowns,(void *)stream);
  418.         return TRUE;
  419.     }
  420. }
  421.  
  422. /* This function should be called if we get a datasave message.
  423.  * It will attempt to open a stream to fetch data directly from
  424.  * the sending application via the RAM transfer protocol.  The
  425.  * sending application may not be interested - if this happens
  426.  * then this function will return FALSE and the program should
  427.  * resort to the scrap file method.
  428.  *
  429.  * msg should point to the DataSave message just recieved
  430.  */
  431.  
  432. int gsopenramfetch(wimp_msgstr *msg, gstream *stream)
  433. {
  434.  
  435.     ramfetch_str **data;
  436.  
  437.     if (msg->hdr.task==wimpt_task())
  438.     {
  439.         werr(FALSE,"Sorry, I'm not talking to myself");
  440.         return FALSE;
  441.     }
  442.  
  443.     stream->bufsize=gs_BUFSIZE;
  444.     stream->size=0;
  445.     stream->pos=0;
  446.     stream->type=READ;
  447.     stream->ungetsize=0;
  448.     stream->error=FALSE;
  449.  
  450.     stream->io.read=readram;
  451.     stream->close=gscloseramfetch;
  452.  
  453.     if (!flex_alloc(&(stream->data),sizeof(ramfetch_str)))
  454.     {
  455.         werr(FALSE,"Not enough space");
  456.         return 2;
  457.     }
  458.  
  459.     data=(ramfetch_str **) &(stream->data);
  460.  
  461.     if ((stream->bufsize=gsgetbuf(&(stream->buffer),stream->bufsize,4))==0)
  462.     {
  463.         werr(FALSE,"Not enough space");
  464.         flex_free(&(stream->data));
  465.         return 2;
  466.     }
  467.     else
  468.     {
  469.         stream->ungetsize=0;
  470.         stream->ungetpos=0;
  471.         (**data).task=msg->hdr.task;
  472.         (**data).their_ref=msg->hdr.my_ref;
  473.         (**data).our_ref=msg->hdr.your_ref;
  474.         (**data).finished=FALSE;
  475.         win_add_unknown_event_processor(ramfetch_unknowns,(void *)stream);
  476.         
  477.         if ((stream->size=ramfetch(stream->buffer,stream->bufsize,stream))>=0)
  478.             return 1;
  479.         else
  480.         {
  481.             flex_free(&(stream->buffer));
  482.             flex_free(&(stream->data));
  483.             win_remove_unknown_event_processor(ramfetch_unknowns,(void *)stream);
  484.             return 0;
  485.         }
  486.     }
  487. }
  488.  
  489.