home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Washington_1988 / DevCon88.1 / AmigaTechniques / cliphandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  14.0 KB  |  509 lines

  1. /*
  2.  *  clipboard.c 
  3.  *  by Robert R. Burns
  4.  *
  5.  * Copyright (c) 1988 Commodore-Amiga, Inc.
  6.  *
  7.  * Executables based on this information may be used in software
  8.  * for Commodore Amiga computers.  All other rights reserved.
  9.  *
  10.  * This information is provided "as is"; no warranties are made.
  11.  * All use is at your own risk, and no liability or responsibility is assumed.
  12.  *
  13.  *  The devs:mountlist needed:
  14.  * 
  15.  *--------------------------------------------------------------------
  16.  *  CLIP:       Handler   = l:clipboard-handler
  17.  *              Stacksize = 5000
  18.  *              Priority  = 5
  19.  *              GlobVec   = 1
  20.  *  #
  21.  *--------------------------------------------------------------------
  22.  *
  23.  * I have done this under MANX, but I don't see too much trouble getting
  24.  * it to work with Lattice...just don't use any startup code and
  25.  * disable the stack checking on LC2 with '-v'. 
  26.  */
  27.  
  28. #include    "exec/types.h"
  29. #include    "exec/nodes.h"
  30. #include    "exec/lists.h"
  31. #include    "exec/ports.h"
  32. #include    "exec/libraries.h"
  33. #include    "exec/devices.h"
  34. #include    "exec/io.h"
  35. #include    "exec/memory.h"
  36. #include    "intuition/intuition.h"
  37. #include    "libraries/dos.h"
  38. #include    "libraries/dosextens.h"
  39. #include    "libraries/filehandler.h"
  40. #include    "devices/clipboard.h"
  41.  
  42. #ifdef MANX
  43. #include    "functions.h"
  44.  
  45. ULONG SysBase,        /* these are here to make the startup code happy */
  46.     _savsp;        /* (this is unique to Manx Aztec C startup) */
  47. #endif
  48.  
  49. struct Process *FindTask();
  50. struct Message *GetMsg();
  51. struct ClipArg *AllocMem();
  52.  
  53. /* A version of BADDR() has no problems with casting */
  54. #undef  BADDR
  55. #define BADDR(x)    ((APTR)((long)x << 2))
  56.  
  57. #ifndef    ACTION_FIND_INPUT
  58. #define ACTION_FIND_INPUT       1005L    /* please refer to DOS Tech. Ref. */
  59. #endif
  60. #ifndef    ACTION_FIND_OUTPUT
  61. #define ACTION_FIND_OUTPUT      1006L
  62. #endif
  63. #ifndef    ACTION_END
  64. #define ACTION_END              1007L
  65. #endif
  66. #ifndef    ACTION_SEEK
  67. #define    ACTION_SEEK        1008L
  68. #endif
  69.  
  70. struct ClipArg {
  71.     struct IOClipReq ca_IOR;
  72.     struct DosPacket *ca_Packet;    /* active dos packet */
  73.     void (*ca_ReplyPacket)();        /* (*ca_ReplyPacket)(process, ca, ) */
  74.     ULONG ca_Data;            /* (used to hold seek arguments) */
  75.     ULONG ca_Argument;            /*  "  */
  76.     ULONG ca_Offset;            /*  "  */
  77.     UWORD ca_Direction;            /* read or write */
  78. };
  79.  
  80. void 
  81. returnPacket(process, packet, res1)
  82. struct Process *process;
  83. struct DosPacket *packet;
  84. ULONG res1;
  85. {
  86.     struct Message *message;
  87.     struct MsgPort *replyport;
  88.  
  89.     packet->dp_Res1 = res1;
  90.     replyport = packet->dp_Port;
  91.     packet->dp_Port = &process->pr_MsgPort;
  92.     message = packet->dp_Link;
  93.     message->mn_Node.ln_Name = (char *) packet;
  94.  
  95. #ifdef    DEBUG
  96. kprintf("returnPacket: %ld %ld\t", packet->dp_Res1, packet->dp_Res2);
  97. #endif
  98.  
  99.     PutMsg(replyport, message);
  100. }
  101.  
  102.  
  103. void
  104. replyClip(process, ca, openCnt)
  105. struct Process *process;
  106. struct ClipArg *ca;
  107. int *openCnt;
  108. {
  109. #ifdef    DEBUG
  110. kprintf("replyClip... ");
  111. #endif
  112.     if (ca->ca_IOR.io_Error) {
  113.     /* Return an indecipherable error */
  114.     ca->ca_Packet->dp_Res2 = 1000+ca->ca_IOR.io_Error;
  115.     returnPacket(process, ca->ca_Packet, -1);
  116.     }
  117.     else {
  118.     returnPacket(process, ca->ca_Packet, ca->ca_IOR.io_Actual);
  119.     }
  120. }
  121.  
  122. void
  123. seekClip(process, ca, openCnt)
  124. struct Process *process;
  125. struct ClipArg *ca;
  126. int *openCnt;
  127. {
  128. #ifdef    DEBUG
  129. kprintf("seekClip... ");
  130. #endif
  131.     if ((ca->ca_IOR.io_Error) || (ca->ca_IOR.io_Actual != 4L)) {
  132.     /* cannot seek from end of file */
  133.     ca->ca_Packet->dp_Res2 = ERROR_SEEK_ERROR;
  134.     returnPacket(process, ca->ca_Packet, -1);
  135.     }
  136.     else {
  137.     ca->ca_IOR.io_Offset = ca->ca_Data + ca->ca_Argument + 8;
  138.     returnPacket(process, ca->ca_Packet, ca->ca_Offset);
  139.     }
  140. }
  141.  
  142.  
  143. void
  144. closeClip(process, ca, openCnt)
  145. struct Process *process;
  146. struct ClipArg *ca;
  147. int *openCnt;
  148. {
  149.     struct DosPacket *packet;
  150. #ifdef    DEBUG
  151. kprintf("closeClip %ld... ", ca->ca_IOR.io_Error);
  152. #endif
  153.  
  154.     /* cache the packet */
  155.     packet = ca->ca_Packet;
  156.     /* close the clipboard device */
  157.     CloseDevice(&ca->ca_IOR);
  158.     /* free the clipboard IO request */
  159.     FreeMem(ca, sizeof(struct ClipArg));
  160.     (*openCnt)--;
  161.     returnPacket(process, packet, DOSTRUE);
  162. }
  163.  
  164.  
  165. _main()
  166. {
  167.     /* handler related data structures */
  168.     struct Process *myProcess;        /* my process */
  169.     struct DeviceNode *myDevNode;    /* our device node passed in Arg3 */
  170.     struct DosPacket *packet;        /* a pointer to a dos packet sent */
  171.     struct MsgPort clipReplyPort;    /* the reply port for clipboard IO */
  172.     struct IOClipReq openIOR;        /* clipboard request to keep dev open */
  173.     struct ClipArg *ca;            /* clipboard.device IO request, etc. */
  174.     struct FileHandle *fh;        /* a pointer to a file handle */
  175.     ULONG sigPacket, sigClipReply;    /* individual signal masks */
  176.     ULONG sigWait;            /* combined signal mask */
  177.     ULONG signal;            /* current signal mask */
  178.     UWORD unit;                /* clipboard unit number */
  179.     int openCnt;            /* access counter to this handler */
  180.     char alive;                /* absence of ACTION_DIE */
  181.     struct Message *message;        /* a message temporary */
  182.     char *name;                /* filename temporary */
  183.     int result, i;            /* some temporarys */
  184.  
  185. #ifdef DEBUG
  186.     kprintf("\n********************\nStart CLIP:\n");
  187. #endif
  188.  
  189.     /*
  190.      * Initialization: initialize some things while the parameter packet
  191.      *   gets here
  192.      */
  193.     myProcess = (struct Process *) FindTask(0L);    /* find myself */
  194.  
  195.     /* set up the message port for clipboard I/O requests */
  196.     clipReplyPort.mp_Node.ln_Type = NT_MSGPORT;
  197.     clipReplyPort.mp_Flags = 0;
  198.     clipReplyPort.mp_SigBit = AllocSignal(-1);
  199.     clipReplyPort.mp_SigTask = (struct Task *) myProcess;
  200.     NewList(&clipReplyPort.mp_MsgList);
  201.  
  202.     /* set the signal masks */
  203.     sigPacket = 1 << myProcess->pr_MsgPort.mp_SigBit;
  204.     sigClipReply = 1 << clipReplyPort.mp_SigBit;
  205.     sigWait = sigPacket | sigClipReply;
  206.  
  207.     alive = TRUE;                    /* handler loop flag */
  208.     openCnt = 0;                    /* handler open count */
  209.     /*
  210.      * Get Parameters: since this is a non-BCPL module it gets sent the
  211.      *   parameter pkt. (BCPL modules get it in D1)
  212.      */
  213.  
  214.     while ((message = GetMsg(&myProcess->pr_MsgPort)) == NULL)
  215.     /* wait for parameter packet */
  216.     Wait(sigPacket);
  217.  
  218. #ifdef DEBUG
  219.     kprintf("Got Parmeter Packet\n");
  220. #endif
  221.  
  222.     /*
  223.      * open the clipboard.device so it will stay open throughout the duration
  224.      * of the life of the CLIP: handler.  Otherwise, the clip goes to disk
  225.      * a lot.
  226.      */
  227.     openIOR.io_Message.mn_ReplyPort = &clipReplyPort;
  228.     openIOR.io_Device = 0;
  229.     OpenDevice("clipboard.device", 0, &openIOR, 0);
  230.  
  231.     /* get the pointer to the device node */
  232.     packet = (struct DosPacket *) (message->mn_Node.ln_Name);
  233.     myDevNode = (struct DeviceNode *) BADDR(packet->dp_Arg3);
  234.  
  235.     /*
  236.      * install our taskid ... if we don't...for every reference
  237.      * to our handler a NEW process will be created.  This is
  238.      * fine for things like CON: (console handler) but if you
  239.      * plan to be the only dude on block ( like the file-system
  240.      * handler or SER: ) you should fill the task field with
  241.      * your taskid (ie.  &(pr_MsgPort) ) Note:
  242.      * remember that shared code has to be reentrant. (like
  243.      * CON: handler) ( keep your variables on the stack
  244.      * [autos], and allocate memory for larger data structures
  245.      * and "FLAG" global data structures that need only be
  246.      * intialized once )
  247.      */
  248.     myDevNode->dn_Task = &myProcess->pr_MsgPort;
  249.  
  250. #ifdef DEBUG
  251.     kprintf("Returning parmeter packet\n");
  252. #endif
  253.  
  254.     /* indicate initialization was successful */
  255.     returnPacket(myProcess, packet, DOSTRUE);
  256.  
  257.     /*
  258.      * Main Loop: look for things to do that are either
  259.      *   1. New packets to this handler
  260.      *   2. Completions of clipboard.device IO and thus of an associated packet
  261.      */
  262.     while (alive) {            /* start of the real work */
  263. #ifdef DEBUG
  264.     kprintf("Waiting... ");
  265. #endif
  266.     signal = Wait(sigWait);
  267.  
  268.     /*
  269.      * Packet handler: handle the packet
  270.      */
  271.     if (signal & sigPacket) {
  272.         while (message = GetMsg(&myProcess->pr_MsgPort)) {
  273.         packet = (struct DosPacket *) (message->mn_Node.ln_Name);
  274.         switch (packet->dp_Type) {
  275.         case ACTION_FIND_INPUT:
  276.         case ACTION_FIND_OUTPUT:
  277.             /*
  278.              * Open: be flexible about opening for read or write here
  279.              */
  280. #ifdef    DEBUG
  281.     kprintf("Open: \"");
  282.     for (i = 1; i <= *(char *) BADDR(packet->dp_Arg3); i++)
  283.         kprintf("%lc", ((char *) BADDR(packet->dp_Arg3))[i]);
  284.     kprintf("\"\t");
  285. #endif
  286.             fh = (struct FileHandle *) BADDR(packet->dp_Arg1);
  287.             /* allocate the clipboard IO request */
  288.             ca = (struct ClipArg *)
  289.                 AllocMem(sizeof(struct ClipArg), MEMF_CLEAR);
  290.             fh->fh_Port = DOSFALSE;    /* not interactive */
  291.             if (fh->fh_Arg1 = (LONG) ca) {
  292.             ca->ca_IOR.io_Message.mn_ReplyPort = &clipReplyPort;
  293.             /* get the clip unit from the name, if it exists */
  294.             unit = 0;
  295.             name = (char *) BADDR(packet->dp_Arg3);
  296.             /*   find colon of clip device name */
  297.             for (i = 1; (i <= *name) && (name[i] != ':'); i++);
  298. #ifdef    DEBUG
  299. kprintf("u i %ld '%lc'\t", i, name[i]);
  300. #endif
  301.             for (i++; i <= *name; i++) {
  302.                 if ((name[i] >= '0') && (name[i] <= '9')) {
  303.                 unit *= 10;
  304.                 unit += name[i] - '0';
  305.                 }
  306.                 else {
  307. #ifdef    DEBUG
  308. kprintf("\\ i %ld '%lc'\t", i, name[i]);
  309. #endif
  310.                 unit = -1;
  311.                 break;
  312.                 }
  313.             }
  314. #ifdef    DEBUG
  315. kprintf("unit %ld\n", unit);
  316. #endif
  317.             if (unit >= 0) {
  318.                 /* open the clipboard device */
  319.                 result = OpenDevice("clipboard.device", unit,
  320.                     &ca->ca_IOR, 0);
  321.                 if (result != 0) {
  322.                 FreeMem(ca, sizeof(struct ClipArg));
  323.                 fh->fh_Arg1 = NULL;
  324.                 packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  325.                 }
  326.             }
  327.             else {
  328.                 FreeMem(ca, sizeof(struct ClipArg));
  329.                 fh->fh_Arg1 = NULL;
  330.                 packet->dp_Res2 = ERROR_BAD_STREAM_NAME;
  331.             }
  332.             }
  333.             else {
  334.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  335.             }
  336.             ca->ca_Direction = 0L;    /* neither read nor write */
  337.             if (fh->fh_Arg1 == NULL) {
  338.             returnPacket(myProcess, packet, DOSFALSE);
  339.             }
  340.             else {
  341.             returnPacket(myProcess, packet, DOSTRUE);
  342.             openCnt++;
  343.             }
  344.             break;
  345.  
  346.         case ACTION_END:
  347.             /*
  348.              * Close
  349.              */
  350. #ifdef    DEBUG
  351.     kprintf("Close\t");
  352. #endif
  353.             ca = (struct ClipArg *) packet->dp_Arg1;
  354.             if (ca) {
  355.             /* terminate the reading or writing */
  356.             if (ca->ca_Direction != 0) {
  357.                 ca->ca_Packet = packet;
  358.                 ca->ca_ReplyPacket = closeClip;
  359.                 if (ca->ca_Direction == ACTION_READ) {
  360.                 /* read past EOF to signal reading is done */
  361.                 ca->ca_IOR.io_Command = CMD_READ;
  362.                 ca->ca_IOR.io_Length = 1;
  363.                 ca->ca_IOR.io_Data = NULL;
  364.                 ca->ca_IOR.io_Offset = 0xfffffffe;
  365.                 }
  366.                 else {
  367.                 /* update to signal writing is done */
  368.                 ca->ca_IOR.io_Command = CMD_UPDATE;
  369.                 }
  370.                 SendIO(&ca->ca_IOR);
  371.                 break;
  372.             }
  373.             else {
  374.                 /* close the clipboard device */
  375.                 CloseDevice(&ca->ca_IOR);
  376.                 /* free the clipboard IO request */
  377.                 FreeMem(ca, sizeof(struct ClipArg));
  378.                 openCnt--;
  379.             }
  380.             }
  381.             returnPacket(myProcess, packet, DOSTRUE);
  382.             break;
  383.  
  384.         case ACTION_READ:
  385.             /*
  386.              * Read
  387.              */
  388. #ifdef DEBUG
  389.     kprintf("Read: %ld\t", packet->dp_Arg3);
  390. #endif
  391.             ca = (struct ClipArg *) packet->dp_Arg1;
  392.             if (ca->ca_Direction != ACTION_WRITE) {
  393.             ca->ca_Direction = ACTION_READ;
  394.             ca->ca_Packet = packet;
  395.             ca->ca_ReplyPacket = replyClip;
  396.             /* issue clip read */
  397.             ca->ca_IOR.io_Command = CMD_READ;
  398.             ca->ca_IOR.io_Length = packet->dp_Arg3;
  399.             ca->ca_IOR.io_Data = (STRPTR) packet->dp_Arg2;
  400.             SendIO(&ca->ca_IOR);
  401.             }
  402.             else {
  403.             /* cannot read in the middle of a clip write */
  404.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  405.             returnPacket(myProcess, packet, -1);
  406.             }
  407.             break;
  408.  
  409.         case ACTION_WRITE:
  410. #ifdef DEBUG
  411.     kprintf("Write: %ld\t", packet->dp_Arg3);
  412. #endif
  413.             ca = (struct ClipArg *) packet->dp_Arg1;
  414.             if (ca->ca_Direction != ACTION_READ) {
  415.             ca->ca_Direction = ACTION_WRITE;
  416.             ca->ca_Packet = packet;
  417.             ca->ca_ReplyPacket = replyClip;
  418.             /* issue clip write */
  419.             ca->ca_IOR.io_Command = CMD_WRITE;
  420.             ca->ca_IOR.io_Length = packet->dp_Arg3;
  421.             ca->ca_IOR.io_Data = (STRPTR) packet->dp_Arg2;
  422.             SendIO(&ca->ca_IOR);
  423.             }
  424.             else {
  425.             /* cannot write in the middle of a clip read */
  426.             packet->dp_Res2 = ERROR_WRITE_PROTECTED;
  427.             returnPacket(myProcess, packet, -1);
  428.             }
  429.             break;
  430.  
  431.         case ACTION_SEEK:
  432.             /*
  433.              * Seek
  434.              */
  435. #ifdef DEBUG
  436.     kprintf("Seek: %ld %ld\t", packet->dp_Arg2, packet->dp_Arg3);
  437. #endif
  438.             ca = (struct ClipArg *) packet->dp_Arg1;
  439.             result = ca->ca_IOR.io_Offset;    /* cache old position */
  440.             if (packet->dp_Arg3 == OFFSET_BEGINNING) {
  441.             ca->ca_IOR.io_Offset = packet->dp_Arg2;
  442.             returnPacket(myProcess, packet, result);
  443.             }
  444.             else if (packet->dp_Arg3 == OFFSET_CURRENT) {
  445.             ca->ca_IOR.io_Length += packet->dp_Arg2;
  446.             returnPacket(myProcess, packet, result);
  447.             }
  448.             else {
  449.             /* can only determine end by reading IFF length */
  450.             if (ca->ca_Direction != ACTION_WRITE) {
  451.                 ca->ca_Argument = packet->dp_Arg2;
  452.                 ca->ca_Offset = result;
  453.                 ca->ca_Direction = ACTION_READ;
  454.                 ca->ca_Packet = packet;
  455.                 ca->ca_ReplyPacket = seekClip;
  456.                 /* issue clip read */
  457.                 ca->ca_IOR.io_Command = CMD_READ;
  458.                 ca->ca_IOR.io_Length = 4;
  459.                 ca->ca_IOR.io_Data = (STRPTR) &ca->ca_Data;
  460.                 ca->ca_IOR.io_Offset = 4;
  461.                 SendIO(&ca->ca_IOR);
  462.             }
  463.             else {
  464.                 /* cannot seek from end of file */
  465.                 packet->dp_Res2 = ERROR_SEEK_ERROR;
  466.                 returnPacket(myProcess, packet, -1);
  467.             }
  468.             }
  469.             break;
  470.  
  471.         default:
  472.             /*
  473.              * Unsupported packet type
  474.              */
  475. #ifdef DEBUG
  476.     kprintf("Unknown packet type %ld\t", packet->dp_Type);
  477. #endif
  478.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  479.             returnPacket(myProcess, packet, DOSFALSE);
  480.         }                /* switch(packet->dp_Type) */
  481.         }
  482.     }
  483.     /*
  484.      * Clipboard IO Reply: reply the packet
  485.      */
  486.     if (signal & sigClipReply) {
  487.         while (ca = (struct ClipArg *) GetMsg(&clipReplyPort)) {
  488.         /*
  489.          * ReplyPacket: process this ClipArg by calling its
  490.          *   reply routine
  491.          */
  492.         (*ca->ca_ReplyPacket)(myProcess, ca, &openCnt);
  493.         }
  494.     }
  495.     }                    /* while() */
  496.  
  497. #ifdef    DEBUG
  498. kprintf("Kill CLIP:\n");
  499. #endif
  500.  
  501.     if (openIOR.io_Device != 0) CloseDevice(&openIOR);
  502.  
  503.     myDevNode->dn_Task = NULL;    /* zero the taskid field of device node */
  504.  
  505.     /*
  506.      * Return: let whoever it was that spawned us provide the cleanup code
  507.      */
  508. }                    /* _main() */
  509.