home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 215.lha / Pipe_v2.02 / pipe.c < prev    next >
C/C++ Source or Header  |  1996-02-15  |  23KB  |  843 lines

  1.  
  2. /*
  3.  *  PIPE.C  V2.03
  4.  *
  5.  *  YOU MUST COMPILE  +BCDL,  Aztec (32 bit ints).
  6.  *
  7.  *  This represents a complete turnaround in functionality from V1.  I've
  8.  *  re-written it completely from scratch.  The PIPE: device now supports
  9.  *  bi-directional connections through a single file-handle, dynamic buffer
  10.  *  sizing, signal capability, and an almost-terminal-like capability.
  11.  *
  12.  *  NOTE NOTE NOTE: In most cases you simply use the same format as Version
  13.  *  1.. that is, redirect <pipe:name to get the data redirected >pipe:name,
  14.  *  don't get turned off by the technical discussion below.
  15.  *
  16.  */
  17.  
  18. /*
  19.  * Some #include's may be missing since I simply give an Aztec compiler
  20.  * option to load the entire symbol table and it doesn't actually go
  21.  * through these includes.
  22.  */
  23.  
  24.  
  25. #include <exec/types.h>
  26. #include <exec/nodes.h>
  27. #include <exec/lists.h>
  28. #include <exec/ports.h>
  29. #include <exec/libraries.h>
  30. #include <exec/devices.h>
  31. #include <exec/io.h>
  32. #include <exec/memory.h>
  33. #include <devices/console.h>
  34. #include <libraries/dos.h>
  35. #include <libraries/dosextens.h>
  36. #include <libraries/filehandler.h>
  37. #include <local/xmisc.h>
  38.  
  39. #define MPC (MEMF_PUBLIC|MEMF_CLEAR)        /* options to AllocMem()    */
  40.  
  41. #define ACTION_READWRITE    1004
  42. #define ACTION_FIND_INPUT   1005        /* various ACTION's supported   */
  43. #define ACTION_FIND_OUTPUT  1006
  44. #define ACTION_END        1007
  45. #define ACTION_EXAMINE        23
  46. #define ACTION_EXAMINENEXT  24
  47. #define ACTION_LOCATE        8
  48. #define ACTION_FREELOCK     15
  49. #define ACTION_COPYDIR        19
  50.  
  51. #undef    BADDR
  52. #define BADDR(x)   ((APTR)((long)x << 2))   /* convert BCPL->APTR       */
  53.  
  54. #define DOS_FALSE    0
  55. #define DOS_TRUE     -1
  56.  
  57. #define ST_REMOTE   0x01    /* this is the remote side        */
  58. #define ST_WASOPEN  0x02    /* this side openned at least once    */
  59. #define ST_REMEOF   0x04    /* other side closed        */
  60. #define ST_TERM     0x08    /* terminal pipe:name[/flags]    */
  61. #define ST_COOKED   0x10    /* cooked mode.            */
  62. #define ST_STAR     0x20    /* CLI strangeness '*' open         */
  63. #define ST_WATER    0x40    /* waiting to go below low-water mark   */
  64.  
  65.  
  66. typedef struct FileLock     LOCK;
  67. typedef struct FileInfoBlock FIB;
  68. typedef struct DosPacket    DOSPACKET;
  69. typedef struct Process        PROC;
  70. typedef struct DeviceNode   DEVNODE;
  71. typedef struct FileHandle   FH;
  72. typedef struct CommandLineInterface CLI;
  73. typedef unsigned char u_char;
  74. typedef struct Message        MSG;
  75.  
  76. extern XLIST *llink(), *lunlink();
  77.  
  78. /*
  79.  * a PBUF is part of a linked list of memory buffers waiting to be read
  80.  * on a pipe.
  81.  */
  82.  
  83. typedef struct _PBUF {
  84.     struct _PBUF *next;
  85.     long    bytes;
  86.     long    index;
  87.     char    buf[4];
  88. } PBUF;
  89.  
  90. /*
  91.  * The PIPE structure itself.  Actually consists of a linked pair of
  92.  * PIPE structures.  The other is accessed through pipe->remote and
  93.  * vise-versa.    One of the structures is the MASTER, the other is the
  94.  * SLAVE.  The SLAVE has the ST_REMOTE flag set. The XLIST and NAME
  95.  * entries are used only by the MASTER end for bookkeeping.
  96.  */
  97.  
  98.  
  99. typedef struct _PIPE {
  100.     XLIST   list;        /* linked list of all pipes    */
  101.     MSG     *rpend;        /* whos waiting to read from me */
  102.     MSG     *wpend;        /* whos waiting to write to me    */
  103.     char    *name;        /* name of this pipe        */
  104.     struct _PIPE *remote;    /* linked pair... other PIPE    */
  105.     short   refs;        /* # Open references        */
  106.     short   stat;        /* Status.. ST_XXXX flags    */
  107.     PBUF    *pbase, *plast;    /* buffers waiting to be read?    */
  108.     long    total;        /* total # bytes in buffers    */
  109.     long    lowwater;        /* below which writes are re-enabled    */
  110.     long    maxbytes;        /* Maximum total # bytes allowed    */
  111.     PROC    *procsignal;    /* process to signal on data present    */
  112.     short   signum;        /* signal number            */
  113. } PIPE;
  114.  
  115. /*
  116.  * NOTE: Globals in the Bss space are not automatically initialized to
  117.  * 0 when you don't use Aztec's startup _main, which we can't since
  118.  * this is a device.
  119.  */
  120.  
  121. extern DOSPACKET *taskwait();       /* wait for a message           */
  122. extern void *AllocMem();
  123. extern void *AllocDS();
  124. extern void *strcpy();
  125. extern void attemptread();          /* the MEAT                     */
  126. extern PROC *FindTask();
  127.  
  128. long SysBase;                /* required to make Exec calls  */
  129. long DOSBase, Fh;            /* Debugging.. required for DOS */
  130. char Buf[256];                /* Scratch buffer            */
  131.  
  132. _whocareswhatthisisnamed()
  133. {
  134.     PROC    *myproc;
  135.     DEVNODE    *mynode;
  136.     PIPE    *Pipe = NULL;
  137.     u_char    notdone;
  138.  
  139.     SysBase = *(long *)4;
  140.     Fh = NULL;
  141.     DOSBase = NULL;
  142.  
  143.     myproc  = (PROC *)FindTask(0L);
  144.  
  145.     /*
  146.      * INITIAL STARTUP MESSAGE
  147.      */
  148.  
  149.     {
  150.     register DOSPACKET *mypkt;
  151.  
  152.     mypkt    = taskwait(myproc);
  153.     mynode    = (DEVNODE *)BADDR(mypkt->dp_Arg3);
  154.     mynode->dn_Task = &myproc->pr_MsgPort;
  155.     returnpkt(mypkt, myproc, DOS_TRUE, 0);
  156.     }
  157.  
  158.  
  159. top:
  160.  
  161. #ifdef XDEBUG
  162.     DOSBase = OpenLibrary("dos.library", 0);
  163.     Fh = Open("con:0/0/400/100/pipedevice", 1006);
  164. #endif
  165.  
  166.     /*
  167.      * MAIN LOOP
  168.      */
  169.  
  170.     notdone = 1;
  171.     while(notdone) {
  172.     register DOSPACKET *mypkt;    /* dos packet received        */
  173.     register PIPE *pipe;        /* pointer to current PIPE  */
  174.     long type;            /* type of packet        */
  175.  
  176.     mypkt = taskwait(myproc);       /* wait/get next packet     */
  177. #ifdef XDEBUG
  178.     if (Fh)
  179.         fhprintf(Fh, "OldRes1 = %8lx\n", mypkt->dp_Res1);
  180. #endif
  181.     mypkt->dp_Res1 = DOS_TRUE;    /* default return value     */
  182.     mypkt->dp_Res2 = 0;        /* default no error        */
  183.     type = mypkt->dp_Type;        /* packet type            */
  184.  
  185.     /*
  186.      *  Extract pipe pointer (only applies to read/write)
  187.      */
  188.  
  189.     pipe  = (PIPE *)mypkt->dp_Arg1;
  190.  
  191. #ifdef XDEBUG
  192.     if (Fh) {
  193.         sprintf(Buf, "Packet: %4ld for %ld, pipe: %-8lx\n", mypkt->dp_Type, mypkt->dp_Arg3, pipe);
  194.         Write(Fh, Buf, strlen(Buf));
  195.     }
  196. #endif
  197.  
  198.     switch(type) {
  199.     case ACTION_FIND_INPUT:
  200.     case ACTION_FIND_OUTPUT:
  201.     case ACTION_READWRITE:
  202.         {
  203.         register PIPE *premote;     /* linked pair: other PIPE    */
  204.         register u_char *ptr, *s2;  /* scratch vars        */
  205.         register FH *fh;        /* File handle from dp_Arg1 */
  206.         short remflags = 0;        /* ST_XXX flags for premote */
  207.         short termflag = 0;        /* standard flags        */
  208.         long  maxbytes = 4096;        /* default max. buffer size */
  209.         PROC *procsignal = NULL;    /* default process to sig.    */
  210.         short signum = -1;
  211.         short queryflag = 0;        /* query option?        */
  212.  
  213.         fh = (FH *)BADDR(mypkt->dp_Arg1);       /* File handle  */
  214.         ptr = (u_char *)BADDR(mypkt->dp_Arg3);  /* PATHNAME     */
  215.         BMov(ptr+1, Buf, *ptr);                 /* BCPL strangeness */
  216.         Buf[*ptr] = 0;
  217.  
  218.         /*
  219.          *  If '*' is the PATHNAME, then it is the CLI asking us
  220.          *  to duplicate it's proc->pr_CIS entry.
  221.          */
  222.  
  223. #ifdef XDEBUG
  224.         if (Fh) {
  225.             fhprintf(Fh, "fh->fh_Buf == %08lx\n", fh->fh_Buf);
  226.             fhprintf(Fh, "fh->fh_Pos == %08lx\n", fh->fh_Pos);
  227.             fhprintf(Fh, "fh->fh_End == %08lx\n", fh->fh_End);
  228.             fhprintf(Fh, "fh->fh_Arg1 == %08lx\n", fh->fh_Arg1);
  229.             fhprintf(Fh, "fh->fh_Arg2 == %08lx\n", fh->fh_Arg2);
  230.         }
  231. #endif
  232.         if (strcmp(Buf, "*") == 0) {
  233.             register PROC *proc;
  234.             register FH *fh;
  235.  
  236.             proc = (PROC *)mypkt->dp_Port->mp_SigTask;
  237. #ifdef XDEBUG
  238.             if (Fh) {
  239.             fhprintf(Fh, "CLI -> STDIN %08lx ARG1 %08lx\n", ((CLI *)BADDR(proc->pr_CLI))->cli_StandardInput,
  240.                 ((FH *)BADDR(((CLI *)BADDR(proc->pr_CLI))->cli_StandardInput))->fh_Arg1);
  241.             fhprintf(Fh, "CLI -> STDOU %08lx ARG1 %08lx\n", ((CLI *)BADDR(proc->pr_CLI))->cli_StandardOutput,
  242.                 ((FH *)BADDR(((CLI *)BADDR(proc->pr_CLI))->cli_StandardOutput))->fh_Arg1);
  243.             fhprintf(Fh, "CLI -> CURIN %08lx ARG1 %08lx\n", ((CLI *)BADDR(proc->pr_CLI))->cli_CurrentInput,
  244.                 ((FH *)BADDR(((CLI *)BADDR(proc->pr_CLI))->cli_CurrentInput))->fh_Arg1);
  245.             fhprintf(Fh, "CLI -> CUROU %08lx ARG1 %08lx\n", ((CLI *)BADDR(proc->pr_CLI))->cli_CurrentOutput,
  246.                 ((FH *)BADDR(((CLI *)BADDR(proc->pr_CLI))->cli_CurrentOutput))->fh_Arg1);
  247.             fhprintf(Fh, "OPEN*: %08lx %08lx %08lx\n", mypkt->dp_Arg1, mypkt->dp_Arg2, mypkt->dp_Arg3);
  248.             fhprintf(Fh, "  pr_CIS: %08lx // Arg1 %08lx\n", proc->pr_CIS, ((FH *)BADDR(proc->pr_CIS))->fh_Arg1);
  249.             fhprintf(Fh, "  pr_COS: %08lx // Arg1 %08lx\n", proc->pr_COS, ((FH *)BADDR(proc->pr_COS))->fh_Arg1);
  250.             }
  251. #endif
  252.             if (proc->pr_CIS) {
  253.             pipe = (PIPE *)((FH *)BADDR(proc->pr_CIS))->fh_Arg1;
  254.             pipe->stat |= ST_STAR;        /* FLAG IT..is CLI  */
  255.             type = ACTION_FIND_INPUT;    /* SLAVE ONLY        */
  256.             goto skip;
  257.             } else {
  258.             pipe = Pipe;            /* most recent open */
  259.             pipe->stat |= ST_STAR;
  260.             type = ACTION_FIND_INPUT;    /* SLAVE ONLY        */
  261.             goto skip;
  262.             }
  263.         }
  264.  
  265.         /*
  266.          *  Process PIPE options.  Note that I don't manually
  267.          *  skip over ascii-numerics since that happens
  268.          *  automatically in the inner for() loop.
  269.          *
  270.          *  FLAGS ARE NOT PART OF THE PIPE NAME!  pipe:a and
  271.          *  pipe:a/n refer to the same PIPE.
  272.          */
  273.  
  274.         for (ptr = (u_char *)Buf; *ptr; ++ptr) {
  275.             if (*ptr == '/') {
  276.             *ptr = 0;            /* not part of name */
  277.             for (++ptr; *ptr; ++ptr) {
  278.                 if (*ptr == 'S')        /* SLAVE    */
  279.                 type = ACTION_FIND_INPUT;
  280.                 if (*ptr == 'M')        /* MASTER   */
  281.                 type = ACTION_FIND_OUTPUT;
  282.                 if (*ptr == 'c')
  283.                 ;
  284.                 if (*ptr == 'q')        /* QUERY    */
  285.                 queryflag = 1;
  286.                 if (*ptr == 'n')        /* INFINITE BUFFERING   */
  287.                 maxbytes = 0x1FFFFFFF;
  288.                 if (*ptr == 't')        /* TTY                  */
  289.                 termflag |= ST_TERM;
  290.                 if (*ptr == 'b') {      /* BUFFER SIZE          */
  291.                 maxbytes = atoi(ptr+1);
  292.                 if (maxbytes < 0)
  293.                     maxbytes = 0;
  294.                 if (maxbytes > 0x1FFFFFFF)
  295.                     maxbytes = 0x1FFFFFFF;
  296.                 }
  297.                 if (*ptr == 's') {      /* SIGNAL              */
  298.                 signum = atoi(ptr+1);
  299.                 procsignal = (PROC *)mypkt->dp_Port->mp_SigTask;
  300.                 }
  301.             }
  302.             break;
  303.             }
  304.         }
  305.  
  306.         /*
  307.          *  See if PIPE exists already.
  308.          */
  309.  
  310.         for (pipe = Pipe; pipe; pipe = (PIPE *)pipe->list.next) {
  311.             if (strcmp(pipe->name, Buf) == 0)
  312.             break;
  313.         }
  314.         if (pipe == NULL) {
  315.             if (queryflag)      /* Query Failed */
  316.             goto fail;
  317.             pipe    = (PIPE *)AllocMem(sizeof(PIPE), MPC);
  318.             premote = (PIPE *)AllocMem(sizeof(PIPE), MPC);
  319.             pipe->name        = (char *)strcpy(AllocMem(strlen(Buf)+1, 0), Buf);
  320.             pipe->remote    = premote;
  321.             pipe->stat        |= termflag;
  322.             pipe->maxbytes  = premote->maxbytes = 4096;
  323.             pipe->lowwater  = premote->lowwater = 2048;
  324.             premote->remote = pipe;
  325.             premote->stat   |= ST_REMOTE|termflag;
  326.             llink(&Pipe, pipe);
  327.  
  328. #ifdef XDEBUG
  329.             if (Fh) {
  330.             sprintf(Buf, "Pipe: %8lx, Pipe->next %8lx\n",
  331.                 Pipe, Pipe->list.next);
  332.             Write(Fh, Buf, strlen(Buf));
  333.             }
  334. #endif
  335.         }
  336.  
  337.         /*
  338.          * If openning the SLAVE, we should point to the SLAVE
  339.          * part of the pipe structure.
  340.          */
  341.  
  342.         if (type == ACTION_FIND_INPUT)
  343.             pipe = pipe->remote;
  344.  
  345.         if (queryflag) {
  346.             if (pipe->remote->refs == 0) {
  347. fail:            mypkt->dp_Res1 = DOS_FALSE;
  348.             mypkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  349.             goto done;
  350.             }
  351.         }
  352. skip:
  353.         ++pipe->refs;
  354.         pipe->procsignal = procsignal;
  355.         pipe->signum = signum;
  356.         pipe->remote->maxbytes = maxbytes;
  357.         pipe->remote->lowwater = maxbytes >> 1;
  358.         pipe->remote->stat |= remflags;
  359.         if (pipe->remote->lowwater < 2048)
  360.             pipe->remote->lowwater = maxbytes;
  361.  
  362.         /*
  363.          *  the ST_WASOPEN flag is not set on open for 'reads'.
  364.          *  Rather, it is set when the read operation is actually
  365.          *  done.  This is so programs like C:COPY can do an
  366.          *  Open(name,1005)/Close() to check for existance before
  367.          *  actually openning the destination 1006 without
  368.          *  screwing up the PIPE.
  369.          */
  370.  
  371.         if (type == ACTION_FIND_OUTPUT)
  372.             pipe->stat |= ST_WASOPEN;
  373.  
  374.         pipe->remote->stat &= ~ST_REMEOF;
  375.         fh->fh_Arg1 = (long)pipe;
  376.         fh->fh_Port = (struct MsgPort *)DOS_TRUE;
  377.         if ((pipe->wpend || pipe->pbase) && pipe->procsignal)
  378.             Signal(pipe->procsignal, 1 << pipe->signum);
  379.         }
  380. done:
  381.         returnpktplain(mypkt, myproc);
  382.         break;
  383.  
  384.     case ACTION_END:                /* CLOSE    */
  385.         --pipe->refs;
  386.  
  387.         /*
  388.          * If closing process had a signal, we had better not
  389.          * signal that process anymore.
  390.          */
  391.  
  392.         if (pipe->procsignal == (PROC *)mypkt->dp_Port->mp_SigTask)
  393.         pipe->procsignal = NULL;
  394.  
  395.         /*
  396.          * Check to see if we can deallocate the PIPE.  The ST_REMEOF
  397.          * flag means that one end has closed communications and
  398.          * exited while the other end was still active.  This causes
  399.          * an EOF on Read() and an error on Write().
  400.          */
  401.  
  402.         if (pipe->refs == 0) {
  403.         if (pipe->stat & ST_WASOPEN)
  404.             pipe->remote->stat |= ST_REMEOF;
  405.         attemptread(pipe->remote, myproc);
  406.         if (pipe->remote->stat & ST_WASOPEN) {
  407.             if (pipe->remote->refs == 0) {
  408.             register PIPE *master = pipe;
  409.             if (pipe->stat & ST_REMOTE)
  410.                 master = pipe->remote;
  411.             lunlink(master);
  412.  
  413. #ifdef XDEBUG
  414.             if (Fh) {
  415.                 sprintf(Buf, "Unlink %8lx\n", master);
  416.                 Write(Fh, Buf, strlen(Buf));
  417.             }
  418. #endif
  419.  
  420.             FreeMem(master->name, strlen(master->name)+1);
  421.             freepbufs(master);
  422.             freepbufs(master->remote);
  423.             FreeMem(master->remote, sizeof(PIPE));
  424.             FreeMem(master, sizeof(PIPE));
  425.             if (Pipe == NULL)       /* Can we exit the process? */
  426.                 notdone = 0;
  427. #ifdef XDEBUG
  428.             if (Fh) {
  429.                 sprintf(Buf, "Pipe = %8lx\n", Pipe);
  430.                 Write(Fh,Buf,strlen(Buf));
  431.             }
  432. #endif
  433.             }
  434.         }
  435.         }
  436.         returnpktplain(mypkt, myproc);
  437.         break;
  438.     case ACTION_READ:
  439.         pipe->stat |= ST_WASOPEN;
  440.         mypkt->dp_Res1 = 0;     /* default return value is 0    */
  441.         llinkend(&pipe->rpend, mypkt->dp_Link);
  442.         attemptread(pipe, myproc);
  443.         break;
  444.     case ACTION_WRITE:
  445.         mypkt->dp_Res1 = 0;     /* default return value is 0    */
  446.         if (pipe->stat & ST_REMEOF) {
  447.         mypkt->dp_Res1 = -1;
  448.         mypkt->dp_Res2 = ERROR_SEEK_ERROR;
  449.         returnpktplain(mypkt, myproc);
  450.         break;
  451.         }
  452.         llinkend(&pipe->remote->wpend, mypkt->dp_Link);
  453.         attemptread(pipe->remote, myproc);
  454.         break;
  455.     case ACTION_COPYDIR:    /*  1:lock res1:newlock    */
  456.         {
  457.         register LOCK *lock = AllocDS(sizeof(LOCK));
  458.  
  459.         BMov(mypkt->dp_Arg1 << 2, lock, sizeof(LOCK));
  460.         returnpkt(mypkt, myproc, (long)lock << 2, 0);
  461.         }
  462.         break;
  463.     case ACTION_LOCATE:    /*  1:lock 2:name 3:mode res1:lock/NULL */
  464.         {
  465.         register LOCK *lock;
  466.         register char *str = (char *)(mypkt->dp_Arg2 << 2);
  467.  
  468.         pipe = (PIPE *)&Pipe;
  469.         if (str[str[0]] != ':') {
  470.             for (pipe = Pipe; pipe; pipe = (PIPE *)pipe->list.next) {
  471.             if (str[0] == strlen(pipe->name) && strncmp(str+1, pipe->name, str[0]) == 0)
  472.                 break;
  473.             }
  474.         }
  475.         if (pipe) {
  476.             lock = AllocDS(sizeof(LOCK));
  477.             lock->fl_Key = (long)pipe;
  478.             lock->fl_Access = mypkt->dp_Arg3;
  479.             lock->fl_Task = &myproc->pr_MsgPort;
  480.             lock->fl_Volume = (BPTR)((long)mynode >> 2);
  481.             returnpkt(mypkt, myproc, (long)lock >> 2, 0);
  482.         } else {
  483.             returnpkt(mypkt, myproc, NULL, ERROR_OBJECT_NOT_FOUND);
  484.         }
  485.         }
  486.         break;
  487.     case ACTION_FREELOCK:    /*  1:lock res1:bool    */
  488.         {
  489.         if (mypkt->dp_Arg1)
  490.             FreeDS(mypkt->dp_Arg1 << 2);
  491.         returnpkt(mypkt, myproc, DOS_TRUE, 0);
  492.         }
  493.         break;
  494.     case ACTION_EXAMINE:    /*  1:lock 2:fib res1:bool  */
  495.         {
  496.         register LOCK *lock = (LOCK *)(mypkt->dp_Arg1 << 2);
  497.         register FIB  *fib  = (FIB  *)(mypkt->dp_Arg2 << 2);
  498.  
  499.         BZero(fib, sizeof(FIB));
  500.         pipe = (PIPE *)(fib->fib_DiskKey = lock->fl_Key);
  501.         if (pipe == (PIPE *)&Pipe) {
  502.             fib->fib_DirEntryType = 1;
  503.             strcpy(fib->fib_FileName+1, "PIPE:");
  504.         } else {
  505.             fib->fib_DirEntryType = -1;
  506.             strcpy(fib->fib_FileName+1, pipe->name);
  507.             fib->fib_Size = pipe->total + pipe->remote->total;
  508.         }
  509.         fib->fib_FileName[0] = strlen(fib->fib_FileName+1);
  510.         }
  511.         returnpkt(mypkt, myproc, DOS_TRUE, 0);
  512.         break;
  513.     case ACTION_EXAMINENEXT:    /*    1:lock 2:fib res1:bool    */
  514.         {
  515.         register FIB  *fib  = (FIB  *)(mypkt->dp_Arg2 << 2);
  516.         register PIPE *pipe = (PIPE *)fib->fib_DiskKey;
  517.  
  518.         if (pipe == (PIPE *)&Pipe)
  519.             pipe = Pipe;
  520.         else
  521.             pipe = (PIPE *)pipe->list.next;
  522.         if (pipe) {
  523.             fib->fib_DirEntryType = -1;
  524.             strcpy(fib->fib_FileName+1, pipe->name);
  525.             fib->fib_Protection = 0;
  526.             fib->fib_Size = pipe->total + pipe->remote->total;
  527.             fib->fib_NumBlocks = 0;
  528.             /*
  529.             sprintf(fib->fib_Comment+1, "this is a comment");
  530.             */
  531.             fib->fib_Comment[1] = 0;
  532.  
  533.             fib->fib_DiskKey = (long)pipe;
  534.             fib->fib_FileName[0] = strlen(fib->fib_FileName+1);
  535.             fib->fib_Comment [0] = strlen(fib->fib_Comment +1);
  536.             returnpkt(mypkt, myproc, DOS_TRUE, 0);
  537.         } else {
  538.             returnpkt(mypkt, myproc, DOS_FALSE, ERROR_NO_MORE_ENTRIES);
  539.         }
  540.         }
  541.         break;
  542.     default:
  543.         returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
  544.         break;
  545.     }
  546.     }
  547.  
  548. #ifdef XDEBUG
  549.     if (Fh)
  550.     Close(Fh);
  551. #endif
  552.     if (DOSBase)
  553.     CloseLibrary(DOSBase);
  554.  
  555.     /*
  556.      *    Can only exit if no messages pending.  There might be a window
  557.      *    here, but there is nothing that can be done about it.
  558.      */
  559.  
  560.     Forbid();
  561.     if (taskpktrdy(myproc)) {
  562.     Permit();
  563.     goto top;
  564.     }
  565.     mynode->dn_Task = FALSE;
  566.     Permit();
  567.  
  568.     /* we are a process "so we fall off the end of the world" */
  569.     /* MUST fall through */
  570. }
  571.  
  572. void *
  573. AllocDS(bytes)
  574. {
  575.     register long *ptr;
  576.     bytes += 4;
  577.  
  578.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  579.     *ptr = bytes;
  580.     return(ptr + 1);
  581. }
  582.  
  583. FreeDS(ptr)
  584. register long *ptr;
  585. {
  586.     if (ptr)
  587.     FreeMem(ptr - 1, *(ptr-1));
  588. }
  589.  
  590.  
  591. /*
  592.  *  All purpose routine which does everything.    Basically:
  593.  *
  594.  *  (A) Fill as many read requests as possible with data from the SBUFs
  595.  *  (B) Fill as many read requests as possible with data from pending
  596.  *    write requests.
  597.  *  (C) Place as many write requests into SBUFs so we can return them.
  598.  *
  599.  *  Also handles EOF and signalling conditions.
  600.  */
  601.  
  602. void
  603. attemptread(pipe, myproc)
  604. register PIPE *pipe;
  605. PROC *myproc;
  606. {
  607.     MSG *mr, *mw;
  608.     register DOSPACKET *rp, *wp;
  609.     register PBUF *pb;
  610.     register long rleft, wleft, len;
  611.  
  612. #ifdef XDEBUG
  613.     if (Fh) {
  614.     if (pipe->stat & ST_REMOTE)
  615.         Write(Fh, "Reader: ", 8);
  616.     else
  617.         Write(Fh, "Writer: ", 8);
  618.     }
  619. #endif
  620.  
  621.     /*
  622.      *    Fill as many read requests as possible from buffer list.
  623.      */
  624.  
  625.     while ((mr = pipe->rpend) && (pb = pipe->pbase)) {
  626.     rp = (DOSPACKET *)mr->mn_Node.ln_Name;
  627.  
  628.     rleft = rp->dp_Arg3 - rp->dp_Res1;
  629.     wleft = pb->bytes - pb->index;
  630.  
  631.     if (wleft > rleft)
  632.         wleft = rleft;
  633.     BMov(pb->buf + pb->index, rp->dp_Arg2 + rp->dp_Res1, wleft);
  634.  
  635.     if ((rp->dp_Res1 += wleft) == rp->dp_Arg3) {
  636.         lunlink(mr);
  637.         returnpktplain(rp, myproc);
  638.     }
  639.     if ((pb->index += wleft) == pb->bytes) {
  640.         pipe->pbase = pb->next;
  641.         if (pipe->pbase == NULL)
  642.         pipe->plast = NULL;
  643.         pipe->total -= pb->bytes;
  644. #ifdef XDEBUG
  645.         if (Fh) {
  646.         sprintf(Buf, "FreeMem: %8lx %ld\n", pb, sizeof(PBUF)- sizeof(pb->buf) + pb->bytes);
  647.         Write(Fh, Buf, strlen(Buf));
  648.         }
  649. #endif
  650.         FreeMem(pb, sizeof(PBUF) - sizeof(pb->buf) + pb->bytes);
  651.     }
  652.     }
  653.     if (pipe->total < pipe->lowwater)
  654.     pipe->stat &= ~ST_WATER;
  655.  
  656.     /*
  657.      *    Fill as many read requests as possible from pending write requests
  658.      */
  659.  
  660.     while ((mr = pipe->rpend) && (mw = pipe->wpend)) {
  661.     rp = (DOSPACKET *)mr->mn_Node.ln_Name;
  662.     wp = (DOSPACKET *)mw->mn_Node.ln_Name;
  663.  
  664.     /* wp->dp_Arg2 is buf, wp->dp_Arg3 is #, wp->dp_Res1 is actual    */
  665.     /* rp->dp_Arg2 is buf, rp->dp_Arg3 is #, rp->dp_Res1 is actual    */
  666.  
  667.     rleft = rp->dp_Arg3 - rp->dp_Res1;  /* # left to read    */
  668.     wleft = wp->dp_Arg3 - wp->dp_Res1;  /* # left to write    */
  669.  
  670.     if (wleft > rleft)  /* wleft is amount to actually transfer */
  671.         wleft = rleft;
  672.     BMov(wp->dp_Arg2 + wp->dp_Res1, rp->dp_Arg2 + rp->dp_Res1, wleft);
  673.     if ((wp->dp_Res1 += wleft) == wp->dp_Arg3) {
  674. #ifdef XDEBUG
  675.         if (Fh)
  676.         Write(Fh, "wexhaust ", 9);
  677. #endif
  678.         lunlink(mw);
  679.         returnpktplain(wp, myproc);
  680.     }
  681.     if ((rp->dp_Res1 += wleft) == rp->dp_Arg3) {
  682. #ifdef XDEBUG
  683.         if (Fh)
  684.         Write(Fh, "rexhaust ", 9);
  685. #endif
  686.         lunlink(mr);
  687.         returnpktplain(rp, myproc);
  688.     }
  689.     }
  690.  
  691.     /*
  692.      * If REMOTE EOF, return any remaining read requests.  However, if
  693.      * was from a NEWCLI, then do big hack and don't return the requests
  694.      * since it will crash the system.    That is, the requests stay pending.
  695.      * If we were openned with a signal option,  return remaining read
  696.      * requests with an error (-1).
  697.      *
  698.      * Note: partially filled read requests are returned normally.
  699.      */
  700.  
  701.     if ((pipe->stat & (ST_REMEOF|ST_STAR)) == ST_REMEOF) {
  702.     while (mr = pipe->rpend) {
  703.         lunlink(mr);
  704.         rp = (DOSPACKET *)mr->mn_Node.ln_Name;
  705.         if (pipe->procsignal && rp->dp_Res1 == 0) {
  706.         rp->dp_Res1 = -1;
  707.         rp->dp_Res2 = ERROR_NO_MORE_ENTRIES;    /* nothing else comes close.    */
  708.         }
  709.         returnpktplain(rp, myproc);
  710.     }
  711.     return;
  712.     }
  713.  
  714.     /*
  715.      * If a pipe has a signal attached to it:
  716.      *    (A) signal the process if any writes are pending
  717.      *    (B) return ALL read requests always immediately whether they are
  718.      *    fullfilled or not.
  719.      */
  720.  
  721.     if (pipe->procsignal) {
  722.     if (pipe->wpend)
  723.         Signal(pipe->procsignal, 1 << pipe->signum);
  724.     while (mr = pipe->rpend) {
  725.         lunlink(mr);
  726.         rp = (DOSPACKET *)mr->mn_Node.ln_Name;
  727.         returnpktplain(rp, myproc);
  728.     }
  729.     }
  730.  
  731.     /*
  732.      * Put any remaining write requests into buffers, if possible.
  733.      * Do not copy new write requests if we haven't gotten back to the
  734.      * low water mark yet
  735.      */
  736.  
  737.     while ((mw = pipe->wpend) && !(pipe->stat & ST_WATER)) {
  738.     wp = (DOSPACKET *)mw->mn_Node.ln_Name;
  739.     wleft = wp->dp_Arg3 - wp->dp_Res1;
  740.     if (pipe->total + wleft > pipe->maxbytes) {
  741.         pipe->stat |= ST_WATER;
  742.         break;
  743.     }
  744.     pb = (PBUF *)AllocMem(sizeof(PBUF) + wleft - sizeof(pb->buf), 0);
  745.  
  746. #ifdef XDEBUG
  747.     if (Fh) {
  748.         sprintf(Buf, "Allocate: %8lx %8ld %ld\n", pb, wleft, sizeof(PBUF) + wleft - sizeof(pb->buf));
  749.         Write(Fh, Buf, strlen(Buf));
  750.     }
  751. #endif
  752.  
  753.     if (pb == NULL)     /* Sorry, no go.    */
  754.         break;
  755.     BMov(wp->dp_Arg2 + wp->dp_Res1, pb->buf, wleft);
  756.     pb->next = NULL;
  757.     pb->bytes = wleft;
  758.     pb->index = 0;
  759.     if (pipe->plast) {
  760.         pipe->plast->next = pb;
  761.         pipe->plast = pb;
  762.     } else {
  763.         pipe->pbase = pipe->plast = pb;
  764.     }
  765.     wp->dp_Res1 += wleft;
  766.     lunlink(mw);
  767.     returnpktplain(wp, myproc);
  768.     pipe->total += wleft;
  769.     }
  770.  
  771.     /*
  772.      * If in Terminal mode, a read request need only a single byte
  773.      * to return.
  774.      */
  775.  
  776.     if ((pipe->stat & ST_TERM) && (mr = pipe->rpend)) {
  777.     rp = (DOSPACKET *)mr->mn_Node.ln_Name;
  778.     if (rp->dp_Res1) {
  779.         lunlink(mr);
  780.         returnpktplain(rp, myproc);
  781.     }
  782.     }
  783.  
  784. #ifdef XDEBUG
  785.     if (Fh)
  786.     Write(Fh, "\n", 1);
  787. #endif
  788. }
  789.  
  790. /*
  791.  *  Link a request onto the end of a doubly linked list.  Requests must
  792.  *  be processed in order.
  793.  */
  794.  
  795. llinkend(px, link)
  796. register XLIST **px, *link;
  797. {
  798.     while (*px)
  799.     px = &(*px)->next;
  800.     *px = link;
  801.     link->prev = px;
  802.     link->next = NULL;
  803. }
  804.  
  805. freepbufs(pipe)
  806. register PIPE *pipe;
  807. {
  808.     register PBUF *pb, *npb;
  809.  
  810.     for (pb = pipe->pbase; pb; pb = npb) {
  811.     npb = pb->next;
  812.     FreeMem(pb, sizeof(PBUF) - sizeof(pb->buf) + pb->bytes);
  813.     }
  814.     pipe->pbase = pipe->plast = NULL;
  815. }
  816.  
  817. XLIST *
  818. llink(list, en)
  819. register XLIST *en, **list;
  820. {
  821.     en->next = *list;
  822.     en->prev = list;
  823.     *list = en;
  824.     if (en->next)
  825.     en->next->prev = &en->next;
  826.     return(en);
  827. }
  828.  
  829. XLIST *
  830. lunlink(en)
  831. register XLIST *en;
  832. {
  833.     if (en) {
  834.     if (en->next)
  835.         en->next->prev = en->prev;
  836.     *en->prev = en->next;
  837.     en->next = NULL;
  838.     en->prev = NULL;
  839.     }
  840.     return(en);
  841. }
  842.  
  843.