home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / new / amigalibdisks / d980 / apipe / pgmpipe.c < prev    next >
C/C++ Source or Header  |  1994-04-04  |  25KB  |  860 lines

  1. /*
  2. **  Pgmpipe.c --- main module of APipe-Handler
  3. **
  4. **  Copyright (C) 1991 by Per Bojsen.  All Rights Reserved.
  5. **
  6. **  Permission is granted to any individual or institution to use, copy,
  7. **  modify, and distribute this software, provided that this complete
  8. **  copyright and permission notice is maintained, intact, in all copies
  9. **  and supporting documentation.
  10. **
  11. **  This software is provided on an "as is" basis without express or
  12. **  implied warranty.
  13. **
  14. **  NOTE: The code is reentrant.  Be careful when modifying it.
  15. **
  16. **  $Id: pgmpipe.c,v 1.7 92/09/12 16:49:11 bojsen Exp Locker: bojsen $
  17. **
  18. **  $Log:    pgmpipe.c,v $
  19. **  Revision 1.7  92/09/12  16:49:11  bojsen
  20. **  Improved cloning of file handles so that reading/writing will start
  21. **  from current position.
  22. **  
  23. **  Revision 1.6  92/02/20  23:46:11  bojsen
  24. **  Fixed bug in handling multiple outstanding read packets add EOF.
  25. **
  26. **  Revision 1.5  91/11/24  17:01:25  bojsen
  27. **  Made extraction of command line from file name more robust; the code now
  28. **  handles the case where the handler name is not prepended.
  29. **
  30. **  Revision 1.4  91/11/24  02:22:39  bojsen
  31. **  First released version.  Changed references to ChildProcess() to
  32. **  _ChildProcess().
  33. **
  34. **  Revision 1.3  91/10/01  02:35:30  bojsen
  35. **  Added code to clone current dir of requester process.  Changed code
  36. **  to obtain pointer to requester process.
  37. **
  38. **  Revision 1.2  91/09/24  23:59:44  bojsen
  39. **  Fixed typo in #include line.
  40. **
  41. **  Revision 1.1  91/09/24  23:54:06  bojsen
  42. **  Initial revision
  43. **
  44. */
  45.  
  46. #include <exec/types.h>
  47. #include <exec/memory.h>
  48. #include <utility/tagitem.h>
  49. #include <clib/macros.h>
  50. #include <dos/dos.h>
  51. #include <dos/dosextens.h>
  52. #include <dos/dostags.h>
  53. #include <dos/var.h>
  54. #ifdef __SASC
  55. #include <proto/exec.h>
  56. #include <proto/dos.h>
  57. #endif /* __SASC */
  58. #include <string.h>
  59. #include "APipe-Handler_rev.h"
  60.  
  61. /*
  62.  *  Version tagging.
  63.  */
  64. STATIC char VersionTag[] = VERSTAG;
  65.  
  66. /*
  67.  *  Debugging.
  68.  */
  69. #ifdef DEBUG
  70. #define DPrintF(args) do { KPrintF args; } while (0)
  71. #else /* !DEBUG */
  72. #define DPrintF(args)
  73. #endif /* !DEBUG */
  74.  
  75. #define AbsExecBase 4L
  76. #define LIB_VERSION_SUPPORTED 37L
  77. #define PIPEBUFFER_SIZE 4096
  78.  
  79. /* defines for read/write status */
  80. #define PPIPE_NOTOPEN   0
  81. #define PPIPE_OPEN      4
  82. #define PPIPE_READ      1
  83. #define PPIPE_READOPEN  (PGMPIPE_READ | PGMPIPE_OPEN)
  84. #define PPIPE_WRITE     2
  85. #define PPIPE_WRITEOPEN (PGMPIPE_WRITE | PGMPIPE_OPEN)
  86. #define PPIPE_RWMASK    3
  87.  
  88. /* defines for fh_Arg1 field of filehandles */
  89. #define PPIPE_READER  1
  90. #define PPIPE_WRITER  2
  91.  
  92. /* defines for closing variable */
  93. #define PPIPE_C_OPEN          0
  94. #define PPIPE_C_RDRCLOSING    1
  95. #define PPIPE_C_WRTCLOSING    2
  96. #define PPIPE_C_CLOSINGMASK   3
  97. #define PPIPE_C_RDRCLOSED     4
  98. #define PPIPE_C_WRTCLOSED     8
  99. #define PPIPE_C_CLOSEDMASK  0xC
  100.  
  101. /*
  102.  *  Parameter packet to child process.
  103.  */
  104. struct ChildMsg
  105. {
  106.   struct Message  ExecMsg;
  107.   char           *CmdLine;   /* the command line to execute */
  108.   LONG            StackSize; /* use this stacksize for child's child */
  109.   BPTR            PathList;  /* path list for child */
  110.   ULONG           Flags;     /* flags for child */
  111.   LONG            RC;        /* return code from child process */
  112. };
  113.  
  114. /* Defines for ChildMsg.Flags */
  115. #define CHMF_PIPE 1L /* stdin of child is a pipe (of PIPE: type) */
  116. #define CHMF_PATH 2L /* path is passed in in PathList */
  117.  
  118. /*
  119.  *  Command path element.
  120.  */
  121. struct PathEntry
  122. {
  123.   BPTR pe_NextPathEntry;
  124.   BPTR pe_PathLock;
  125. };
  126.  
  127. /*
  128.  *  The library bases must be global by AmigaOS programming standards,
  129.  *  and the pragma libcall requires them.
  130.  */
  131. struct ExecBase *SysBase;
  132. struct DosLibrary *DOSBase;
  133.  
  134.  
  135. /*
  136.  *  Prototypes for external functions.
  137.  */
  138. extern int _ChildProcess(void);
  139.  
  140. /*
  141.  *  Prototypes for local functions.
  142.  */
  143. ULONG CopyFromFIFO(UBYTE *FIFO, ULONG FIFOSize, UBYTE **Start, UBYTE *End,
  144.                    ULONG *FIFOFill, UBYTE *Dest, ULONG NumBytes);
  145. ULONG CopyToFIFO(UBYTE *FIFO, ULONG FIFOSize, UBYTE **Start, UBYTE **End,
  146.                  ULONG *FIFOFill, UBYTE *Src, ULONG NumBytes);
  147. STRPTR GetCommandLine(STRPTR FileSpec, BSTR HandlerName);
  148. LONG ExecCommand(char *CmdLine, struct MsgPort **ParentPort,
  149.                  struct Process *Requester, struct FileHandle *ChildIO,
  150.                  LONG IoDirection);
  151. BPTR CloneProcessIO(struct Process *Friend, LONG IoDirection);
  152. BPTR ClonePathList(struct CommandLineInterface *Peer);
  153. void FreePathList(BPTR);
  154.  
  155. void
  156. PgmPipe()
  157. {
  158.   struct DosLibrary *l_DOSBase;
  159.  
  160.   SysBase = *((struct ExecBase **) AbsExecBase); /* `open' exec.library */
  161.  
  162.   if (l_DOSBase =
  163.         (struct DosLibrary *) OpenLibrary("dos.library", LIB_VERSION_SUPPORTED))
  164.   {
  165.     struct Process *ourProc, *theirProc;
  166.     struct DosList *ourDevNode;
  167.     struct DosPacket *packet, *writePkt = NULL, *readPkt = NULL;
  168.     struct DosPacket *writeCls = NULL, *readCls = NULL;
  169.     struct MsgPort *childPort = NULL;
  170.     struct MsgPort *oldConTask = NULL;
  171.     struct ChildMsg *childMsg = NULL;
  172.     struct FileHandle *fhIncoming, *fhOutgoing;
  173.     UBYTE *pipeBuffer;
  174.     UBYTE *pbStart, *pbEnd;
  175.     ULONG bytesReady, bytesR = 0, bytesW = 0;
  176.     UWORD closing = PPIPE_C_RDRCLOSED | PPIPE_C_WRTCLOSED;
  177.     UWORD readwrite = PPIPE_NOTOPEN;
  178.     ULONG waitSigMask;
  179.     struct MinList readQ, writeQ;
  180. #ifdef DEBUG
  181.     ULONG packetNum = 0;
  182. #endif /* DEBUG */
  183.  
  184.     NewList((struct List *) &readQ);
  185.     NewList((struct List *) &writeQ);
  186.  
  187.     DOSBase = l_DOSBase; /* patch the global library base */
  188.  
  189.     ourProc = (struct Process *) FindTask(NULL);
  190.     waitSigMask = 1L << ourProc->pr_MsgPort.mp_SigBit;
  191.     packet = WaitPkt(); /* get parameter packet */
  192.  
  193.     if ((pipeBuffer = AllocMem(PIPEBUFFER_SIZE, 0)) == NULL)
  194.       ReplyPkt(packet, DOSFALSE, ERROR_NO_FREE_STORE);
  195.     else
  196.     {
  197.       pbStart = pbEnd = pipeBuffer;
  198.       bytesReady = 0;
  199.  
  200.       /*
  201.        *  Currently we don't use the parameters provided in the parameter
  202.        *  packet.  Since we want a new process for each instance of reference
  203.        *  to our handler we don't patch the DeviceList node, but use the
  204.        *  node to get the handler name.
  205.        */
  206.  
  207.       ourDevNode = (struct DosList *) BADDR(packet->dp_Arg3);
  208.  
  209.       ReplyPkt(packet, DOSTRUE, packet->dp_Arg2);
  210.  
  211.       do
  212.       {
  213.         struct Node *node;
  214.         char *cmdLine;
  215.         LONG ioerr;
  216.  
  217.         if (readPkt && bytesReady == 0 && writePkt == NULL &&
  218.             closing & PPIPE_C_WRTCLOSED)
  219.         {
  220.           ReplyPkt(readPkt, bytesR, 0);
  221.           while (readPkt = (struct DosPacket *)
  222.                              (node = RemHead((struct List *) &readQ),
  223.                               node ? node->ln_Name : NULL))
  224.             ReplyPkt(readPkt, 0, 0);
  225.         }
  226.  
  227. #ifdef DEBUG
  228.         if (readPkt || writePkt)
  229.           DPrintF(("Event loop: readPkt == 0x%08lx writePkt == 0x%08lx\n",
  230.                    readPkt, writePkt));
  231. #endif /* DEBUG */
  232.  
  233.         if (packet = WaitPkt())
  234.         {
  235.           DPrintF(("Packet %ld, port 0x%08lx: ", ++packetNum, packet->dp_Port));
  236.  
  237.           switch (packet->dp_Type)
  238.           {
  239.             struct TagItem adoTags[2];
  240.  
  241.             case ACTION_FINDINPUT:
  242.               DPrintF(("ACTION_FINDINPUT 0x%08lx 0x%08lx %s\n",
  243.                        packet->dp_Arg1 << 2, packet->dp_Arg2 << 2,
  244.                        (char *) (packet->dp_Arg3 << 2) + 1));
  245.  
  246.               if (readwrite != PPIPE_NOTOPEN)
  247.               {
  248.                 ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
  249.                 break;
  250.               }
  251.               else
  252.                 readwrite = PPIPE_READ;
  253.  
  254.             case ACTION_FINDOUTPUT:
  255. #ifdef DEBUG
  256.               if (packet->dp_Type == ACTION_FINDOUTPUT)
  257.                 DPrintF(("ACTION_FINDOUTPUT 0x%08lx 0x%08lx %s\n",
  258.                          packet->dp_Arg1 << 2, packet->dp_Arg2 << 2,
  259.                          (char *) (packet->dp_Arg3 << 2) + 1));
  260. #endif /* DEBUG */
  261.  
  262.               if (readwrite & PPIPE_OPEN)
  263.               {
  264.                 ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
  265.                 break;
  266.               }
  267.               else if (readwrite != PPIPE_READ)
  268.                 readwrite = PPIPE_WRITE;
  269.  
  270.               fhIncoming = (struct FileHandle *) BADDR(packet->dp_Arg1);
  271.  
  272.               /*
  273.                *  Obtai