home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / duucp-1.17 / AU-117b4-src.lha / src / fifolib / fifo-handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-25  |  25.4 KB  |  1,131 lines

  1.  
  2. /*
  3.  *  FIFO-HANDLER.C    V37.5
  4.  *
  5.  *  Provide an interface to the fifo.library
  6.  *  Provide remote shell support, including "*" support and interactive
  7.  *  support.
  8.  *
  9.  *  !!! MUST BE RUN, CANNOT USE MOUNT !!!
  10.  *
  11.  *  FIFO:fifo_name/flags
  12.  *           r    for reading
  13.  *           w    for writing
  14.  *           c    cooked (else raw)
  15.  *           e    EOF on close (if a writer)
  16.  *           k    allows writer to close before reader opens without
  17.  *            any data lost.
  18.  *           K    a reader MUST exist or write(s) will fail
  19.  *           q    QUIT (debugging)
  20.  *           m    master
  21.  *           t    tee off the read stream (no interference with other
  22.  *            readers)
  23.  *           s    shell
  24.  *
  25.  *           d    debug mode (read by running 'RemCLI DBFifo')
  26.  */
  27.  
  28. #define CLI_START
  29.  
  30. #include "handler.h"
  31. #include "fifo.h"
  32. #include <lists.h>
  33. #include <string.h>
  34.  
  35. #define FIFO_SIZE   2048
  36.  
  37. #define SIGS    (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)
  38.  
  39. void myexit(int);
  40. void Initialize(void);
  41. void returnpacket(DosPacket *);
  42. void HandleRequestMsg(Message *);
  43. void WaitMsg(Message *);
  44. void SigHandles(char *, long);
  45. void xprintf(char *, ...);
  46. void *DosAllocMem(long);
  47. int OpenHandle(FHan *, char *, char *, long, long, long);
  48. void CloseHandle(FHan *);
  49. void DosFree(void *);
  50. MsgPort *SpecPort(FHan *);
  51. void MkDevice(char *);
  52. void DelDevice(void);
  53.  
  54. short        DDebug;
  55. short        NotDone = 1;
  56. MsgPort     *IoSink;
  57. MsgPort     *PktPort;
  58. #ifndef CLI_START
  59. DeviceNode  *DevNode;
  60. #endif
  61. void        *FifoBase;
  62. long        PktPortMask;
  63. #ifdef DEBUG
  64. long        DBFifo;
  65. #endif
  66.  
  67. List    HanList;
  68.  
  69. extern struct DosLibrary *DOSBase;
  70.  
  71. static const char vn [] = "\0$VER: fifo-handler 37.5 (25.12.93)";
  72.  
  73. __stkargs void
  74. _main (char *arg, long arglen)
  75. {
  76.     DosPacket  *packet;
  77.  
  78.     NewList((MaxList *)&HanList);
  79.  
  80.     Initialize();
  81.  
  82.     /*
  83.      *    Main Loop
  84.      */
  85.  
  86.     while (NotDone || GetHead(&HanList)) {
  87.     {
  88.         Message *msg;
  89.  
  90.         while (msg = GetMsg(IoSink))
  91.         HandleRequestMsg(msg);
  92.         if ((msg = GetMsg(PktPort)) == NULL) {
  93.         if (Wait(SIGS | PktPortMask) & SIGBREAKF_CTRL_C)
  94.             NotDone = 0;
  95.         continue;
  96.         }
  97.         packet = (DosPacket *)msg->mn_Node.ln_Name;
  98.     }
  99.     if (packet->dp_Type != ACTION_WRITE)
  100.         packet->dp_Res1 = DOS_TRUE;
  101.     packet->dp_Res2 = 0;
  102.  
  103. #ifdef DEBUG
  104.     if (DDebug)
  105.         xprintf("packet %08lx (%d)\n", packet->dp_Type, packet->dp_Type);
  106. #endif
  107.  
  108.     switch(packet->dp_Type) {
  109.     case ACTION_DIE:
  110.         NotDone = 0;
  111.         break;
  112.     case ACTION_FINDUPDATE:     /*    FileHandle,Lock,Name        Bool    */
  113.     case ACTION_FINDINPUT:        /*    FileHandle,Lock,Name        Bool    */
  114.     case ACTION_FINDOUTPUT:     /*    FileHandle,Lock,Name        Bool    */
  115.  
  116.         {
  117.         FileHandle *fh = BTOC(packet->dp_Arg1);
  118.         FHan *han;
  119.         char fifo_name_m[128];
  120.         char fifo_name_s[128];
  121.         short error = 0;
  122.         long han_flags = 0;
  123.         long opn_flags = FIFOF_NORMAL | FIFOF_NBIO;
  124.         long opn_size  = FIFO_SIZE;
  125.  
  126.         {
  127.             char *bas = BTOC(packet->dp_Arg3);
  128.             char *ptr;
  129.             unsigned char len = *(unsigned char *)bas;
  130.             long sigs = 0;
  131.  
  132. #ifdef DEBUG
  133.             if (DDebug)
  134.             xprintf("open: %*.*s\n", len, len, bas + 1);
  135. #endif
  136.             for (ptr = ++bas; *ptr != ':' && len; ++ptr, --len);
  137.             if (len && *ptr == ':') {
  138.             ++ptr;
  139.             --len;
  140.             } else {
  141.             len = ptr - bas;
  142.             ptr = bas;
  143.             }
  144.             bas = ptr;
  145.             for (ptr = bas; *ptr != '/' && len; ++ptr, --len);
  146.             {
  147.             int i = ptr - bas;
  148.             strncpy(fifo_name_m, bas, i);
  149.             strncpy(fifo_name_s, bas, i);
  150.             strcpy(fifo_name_m + i, "_m");
  151.             strcpy(fifo_name_s + i, "_s");
  152.             }
  153.             if (len && *ptr == '/') {
  154.             for (++ptr, --len; len; ++ptr, --len) {
  155.                 switch(*ptr) {
  156.                 case 'q':
  157.                 NotDone = 0;
  158.                 break;
  159.                 case 'e':
  160.                 han_flags |= FHF_CLOSEEOF;
  161.                 break;
  162.                 case 'c':
  163.                 han_flags |= FHF_COOKED;
  164.                 break;
  165.                 case 'r':
  166.                 han_flags |= FHF_READ;
  167.                 break;
  168.                 case 'w':
  169.                 han_flags |= FHF_WRITE;
  170.                 break;
  171.                 case 'k':
  172.                 opn_flags |= FIFOF_KEEPIFD;
  173.                 break;
  174.                 case 'K':
  175.                 opn_flags |= FIFOF_RREQUIRED;
  176.                 break;
  177.                 case 'm':
  178.                 han_flags |= FHF_MASTER;
  179.                 break;
  180.                 case 't':
  181.                 han_flags |= FHF_TEE;
  182.                 break;
  183.                 case 'd':
  184. #ifdef DEBUG
  185.                 if (DDebug == 0) {
  186.                     DDebug = 1;
  187.                     DBFifo = OpenFifo("DBFifo_s", 1024, FIFOF_WRITE | FIFOF_NORMAL);
  188.                 }
  189. #endif
  190.                 break;
  191.                 case 'x':
  192. #ifdef DEBUG
  193.                 if (DDebug) {
  194.                     DDebug = 0;
  195.                     if (DBFifo)
  196.                     CloseFifo(DBFifo, FIFOF_EOF);
  197.                     DBFifo = NULL;
  198.                 }
  199. #endif
  200.                 break;
  201.                 case 's':
  202.                 han_flags |= FHF_SHELL;
  203.                 break;
  204.                 case 'C':
  205.                 sigs |= SIGBREAKF_CTRL_C;
  206.                 break;
  207.                 case 'D':
  208.                 sigs |= SIGBREAKF_CTRL_D;
  209.                 break;
  210.                 case 'E':
  211.                 sigs |= SIGBREAKF_CTRL_E;
  212.                 break;
  213.                 case 'F':
  214.                 sigs |= SIGBREAKF_CTRL_F;
  215.                 break;
  216.                 default:
  217.                 error = 1;
  218.                 break;
  219.                 }
  220.             }
  221.             }
  222.             if (sigs) {
  223.             if (han_flags & FHF_MASTER)
  224.                 SigHandles(fifo_name_m, sigs);
  225.             else
  226.                 SigHandles(fifo_name_s, sigs);
  227.             }
  228.         }
  229.  
  230.         /*
  231.          *  To handle the stderr channel, "*", an interactive
  232.          *  shell must be openned with the 's' flag, which causes
  233.          *  a special message port to be created for the interactive
  234.          *  shell (and thus the pr_ConsoleTask field)
  235.          *
  236.          *  To handle COOKED data mode, FIFO: itself must processed
  237.          *  received data before the slave device, echoing it back
  238.          *  on the master channel and doing other cooked processing.
  239.          */
  240.  
  241.         if (error == 0) {
  242.             if (strcmp(fifo_name_m, "*_m") == 0) {
  243.             if (fh->fh_Port && (long)fh->fh_Port != -1) {
  244.                 han = (FHan *)fh->fh_Port->mp_Node.ln_Name;
  245.                 ++han->ff_Refs;
  246.                 fh->fh_Arg1 = (LONG) han;
  247.                 fh->fh_Port = (MsgPort *) DOS_TRUE;
  248.                 break;
  249.             }
  250.             fh->fh_Port = (MsgPort *) DOS_FALSE;
  251.             packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  252.             break;
  253.             }
  254.  
  255.             if (han = AllocMem(sizeof(FHan) + strlen(fifo_name_s) + 1, MEMF_CLEAR | MEMF_PUBLIC)) {
  256.             han->ff_Node.ln_Name = (char *)(han + 1);
  257.             if (OpenHandle(han, fifo_name_s, fifo_name_m, han_flags, opn_size, opn_flags) >= 0) {
  258.                 if (han_flags & FHF_SHELL) {
  259.                 han->ff_Port = SpecPort(han);
  260.                 fh->fh_Type = han->ff_Port;
  261.                 }
  262.                 fh->fh_Arg1 = (LONG) han;
  263.                 fh->fh_Port = (MsgPort *) DOS_TRUE;
  264.                 AddTail((MaxList *)&HanList, &han->ff_Node);
  265.                 ++han->ff_Refs;
  266.                 han->ff_Flags = han_flags;
  267.                 han->ff_RdMsg.mn_ReplyPort = IoSink;
  268.                 han->ff_RdMsg.mn_Node.ln_Name = (char *)han;
  269.                 han->ff_WrMsg.mn_ReplyPort = IoSink;
  270.                 han->ff_WrMsg.mn_Node.ln_Name = (char *)han;
  271.                 han->ff_Task = packet->dp_Port->mp_SigTask;
  272.                 /*
  273.                 han->ff_Task = ((Message *)packet->dp_Link)->mn_ReplyPort->mp_SigTask;
  274.                 */
  275.                 if (han_flags & FHF_WRITE)
  276.                 han->ff_FBufSiz = BufSizeFifo(han->ff_FifoW);
  277.                 NewList((MaxList *)&han->ff_RdWait);
  278.                 NewList((MaxList *)&han->ff_WrWait);
  279.                 if (han_flags & FHF_COOKED) {
  280.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  281.                 han->ff_Flags |= FHF_RPEND;
  282.                 han->ff_CookBuf = AllocMem(CB_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
  283.                 }
  284.                 break;
  285.             }
  286.             AddTail((MaxList *)&HanList, &han->ff_Node);
  287.             CloseHandle(han);
  288.             }
  289.         }
  290.         fh->fh_Port = (MsgPort *)DOS_FALSE;
  291.         packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  292. #ifdef DEBUG
  293.         if (DDebug)
  294.             xprintf("open failed\n");
  295. #endif
  296.         }
  297.         break;
  298.     /* 3Sep92 DAV Added ACTION_WAIT_CHAR support */
  299.     case ACTION_WAIT_CHAR:        /*    FHArg1,ULONG Timeout, CharReady */
  300.         /*
  301.          *    If a character is ready for reading, return DOSTRUE (-1L)
  302.          *    This is a quick-fix, timeout is always 0
  303.          */
  304.  
  305.  
  306.         if (packet->dp_Arg2 && packet->dp_Arg2 != -1) {
  307.         FHan *han = (FHan *)(((MsgPort *)packet->dp_Arg2)->mp_Node.ln_Name);
  308.         char *ptr;
  309.  
  310.         packet->dp_Res1 = 0; /* default */
  311.  
  312.         if( (han->ff_Flags & FHF_READ) && (!(han->ff_Flags & FHF_REOF))) {
  313.  
  314.             if (han->ff_Flags & FHF_COOKED) {
  315.             if ((strlen(han->ff_CookBuf)) != han->ff_CookIdx || han->ff_LRet)
  316.                 packet->dp_Res1 = -1;
  317.             } else {
  318.             if(ReadFifo(han->ff_FifoR, &ptr, 0) > 0)
  319.                 packet->dp_Res1 = -1;
  320.             }
  321.         } else {
  322.             /* I want to know about EOF (code ?) */
  323.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  324.         }
  325.         }
  326.         break;
  327.     case ACTION_READ:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  328.         /*
  329.          *    read from fifo.  If we are in cooked mode this action is
  330.          *    only able to read from the cooked buffer, and then only
  331.          *    if a line is complete.
  332.          */
  333.  
  334.         {
  335.         FHan *han = (FHan *)packet->dp_Arg1;
  336.         char *ptr;
  337.         long n;
  338.  
  339.         if (!(han->ff_Flags & FHF_READ)) {
  340.             packet->dp_Res1 = -1;
  341.             break;
  342.         }
  343.         if (han->ff_Flags & FHF_REOF) {
  344.             han->ff_Flags &= ~FHF_REOF;
  345.             packet->dp_Res1 = 0;
  346.             break;
  347.         }
  348.         if (han->ff_Flags & FHF_COOKED) {
  349.             long n;
  350.             if ((n = strlen(han->ff_CookBuf)) != han->ff_CookIdx || han->ff_LRet) {
  351.             ++n;
  352.             if (n > packet->dp_Arg3)
  353.                 n = packet->dp_Arg3;
  354.             else
  355.                 han->ff_CookBuf[n-1] = '\n';
  356.             movmem(han->ff_CookBuf, (void *)packet->dp_Arg2, n);
  357.             movmem(han->ff_CookBuf + n, han->ff_CookBuf, han->ff_CookIdx - n + 1);
  358.             han->ff_CookIdx -= n;
  359.             if (han->ff_CookIdx == 0)
  360.                 han->ff_LRet = 0;
  361.             packet->dp_Res1 = n;
  362.  
  363.             /*
  364.              *  if we blocked on reading the fifo to cook more
  365.              *  data, we unblock it here.
  366.              */
  367.  
  368.             han->ff_Flags &= ~FHF_COOKBFUL;
  369.             if ((han->ff_Flags & FHF_RPEND) == 0) {
  370.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  371.                 han->ff_Flags |= FHF_RPEND;
  372.             }
  373.             break;
  374.             } else {
  375.             if (han->ff_Flags & FHF_REOF) {
  376.                 han->ff_Flags &= ~FHF_REOF;
  377.                 packet->dp_Res1 = 0;
  378.                 break;
  379.             }
  380.             }
  381.         } else {
  382.             n = ReadFifo(han->ff_FifoR, &ptr, 0);
  383.             if (n < 0 || (n == 0 && (han->ff_Flags & FHF_REOF))) {
  384.             han->ff_Flags &= ~FHF_REOF;
  385.             packet->dp_Res1 = 0;
  386.             break;
  387.             }
  388.             if (n > 0) {
  389.             if (n > packet->dp_Arg3)
  390.                 n = packet->dp_Arg3;
  391.             movmem(ptr, (void *)packet->dp_Arg2, n);
  392.             if (ReadFifo(han->ff_FifoR, &ptr, n) < 0)
  393.                 han->ff_Flags |= FHF_REOF;
  394.             packet->dp_Res1 = n;
  395.             break;
  396.             }
  397.         }
  398.  
  399.         /*
  400.          *  blocked
  401.          */
  402.  
  403.         AddTail((MaxList *)&han->ff_RdWait, &((Message *)packet->dp_Link)->mn_Node);
  404.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  405.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  406.             han->ff_Flags |= FHF_RPEND;
  407.         }
  408.         packet = NULL;
  409.         }
  410.         break;
  411.     case ACTION_WRITE:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  412.         {
  413.         FHan *han = (FHan *)packet->dp_Arg1;
  414.         long n;
  415.         long i;
  416.  
  417.         if (!(han->ff_Flags & FHF_WRITE)) {
  418.             packet->dp_Res1 = -1;
  419.             break;
  420.         }
  421.  
  422.         i = packet->dp_Arg3;
  423. #ifdef DEBUG
  424.         if (DDebug)
  425.             xprintf("i = %d\n", i);
  426. #endif
  427.         if (i < 0) {    /*  re-scan    */
  428.             i = -i;
  429.             packet->dp_Arg3 = i;
  430.         } else {    /*  initial pkt */
  431.             packet->dp_Res1 = 0;
  432.         }
  433.  
  434.  
  435.         /*
  436.          *  check for output stopped due to pending input line
  437.          *
  438.          *  dp_Arg3 < 0 indicates a re-scan (so we do not clear
  439.          *  our dp_Res1 field that is tracking the amnt written)
  440.          */
  441.  
  442.         if ((han->ff_Flags & FHF_COOKED) && han->ff_CookIdx && han->ff_LRet == 0) {
  443.             packet->dp_Arg3 = -packet->dp_Arg3;
  444.             AddTail((MaxList *)&han->ff_WrWait, &((Message *)packet->dp_Link)->mn_Node);
  445.             han->ff_Flags |= FHF_WIHOLD;
  446.             packet = NULL;
  447.             break;
  448.         }
  449.  
  450.  
  451.         /*
  452.          *  limit size of writes to fifo to something the fifo can
  453.          *  handle.  If cooked mode writer, prepend CR to LF's.
  454.          */
  455.  
  456.         if (i > (han->ff_FBufSiz >> 1) - 1)
  457.             i = (han->ff_FBufSiz >> 1) - 1;
  458.  
  459.         if (han->ff_Flags & FHF_COOKED) {
  460.             char *ptr = (char *)packet->dp_Arg2;
  461.             long j;
  462.  
  463.             for (j = 0; j < i; ++j) {
  464.             if (ptr[j] == '\n') {
  465.                 if (j == 0) {
  466.                 n = WriteFifo(han->ff_FifoW, "\r\n", 2);
  467.                 if (n == 2)
  468.                     n = 1;    /*  skip LF */
  469.                 break;
  470.                 }
  471.                 n = WriteFifo(han->ff_FifoW, ptr, j);
  472.                 break;
  473.             }
  474.             }
  475.             if (i == j)
  476.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  477.         } else {
  478.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  479.         }
  480.  
  481.         /*
  482.          *  object too large or broken pipe
  483.          */
  484.  
  485.         if (n < 0) {
  486.             packet->dp_Res1 = -1;
  487.             packet->dp_Res2 = ERROR_OBJECT_TOO_LARGE;
  488.             break;
  489.         }
  490. #ifdef DEBUG
  491.         if (DDebug)
  492.             xprintf("n = %d, res1 = %d,  i=%d\n", n, packet->dp_Res1 + n, i);
  493. #endif
  494.         packet->dp_Res1 += n;
  495.         if (n == packet->dp_Arg3)
  496.             break;
  497.  
  498.         packet->dp_Arg3 = -(packet->dp_Arg3 - n);
  499.         packet->dp_Arg2 += n;
  500.  
  501.         /*
  502.          *  blocked
  503.          *  n == 0
  504.          */
  505.  
  506. #ifdef DEBUG
  507.         if (DDebug)
  508.             xprintf("AddTail:res1 = %d\n", packet->dp_Res1);
  509. #endif
  510.  
  511.         AddTail((MaxList *)&han->ff_WrWait, &((Message *)packet->dp_Link)->mn_Node);
  512.         if ((han->ff_Flags & FHF_WAVAIL) == 0) {
  513.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  514.             han->ff_Flags |= FHF_WAVAIL;
  515.         }
  516.         packet = NULL;
  517.         }
  518.         break;
  519.     case ACTION_REQUEST:        /*    FHArg1, msg, how        Bool    */
  520.         {
  521.         FHan *han = (FHan *)packet->dp_Arg1;
  522.  
  523.         if ((unsigned short)packet->dp_Arg3 == FREQ_RPEND) {
  524.             if (han->ff_FifoR)
  525.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  526.             else
  527.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  528.             break;
  529.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_WAVAIL) {
  530.             if (han->ff_FifoW)
  531.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  532.             else
  533.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  534.             break;
  535.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_ABORT) {
  536.             if (han->ff_FifoR)
  537.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  538.             if (han->ff_FifoW)
  539.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  540.         } else {
  541.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  542.         }
  543.         }
  544.         break;
  545.     case ACTION_END:        /*    FHArg1                Bool:TRUE    */
  546.         {
  547.         FHan
  548.             *han = (FHan *) packet->dp_Arg1;
  549.  
  550.         if (--han->ff_Refs == 0) {
  551.             if (han->ff_Flags & FHF_RPEND) {
  552.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  553.             WaitMsg(&han->ff_RdMsg);
  554.             }
  555.             if (han->ff_Flags & FHF_WAVAIL) {
  556.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_ABORT);
  557.             WaitMsg(&han->ff_WrMsg);
  558.             }
  559.             returnpacket(packet);   /* before ff_Port goes away */
  560.             CloseHandle(han);
  561.             packet = NULL;
  562.         }
  563.         }
  564.         break;
  565.     case ACTION_SCREEN_MODE:
  566.         if (packet->dp_Arg2 && packet->dp_Arg2 != -1) {
  567.         FHan *han = (FHan *)(((MsgPort *)packet->dp_Arg2)->mp_Node.ln_Name);
  568.  
  569. #ifdef DEBUG
  570.         if (DDebug)
  571.             xprintf("handle %s arg1 %d\n", han->ff_Node.ln_Name, packet->dp_Arg1);
  572. #endif
  573.  
  574.         switch (packet->dp_Arg1) {
  575.         case DOS_TRUE:        /*    RAW    */
  576.             if (han->ff_Flags & FHF_COOKED) {
  577.             han->ff_Flags &= ~(FHF_COOKED|FHF_WIHOLD|FHF_COOKECHOBLK|FHF_COOKBFUL);
  578.  
  579.             if ((han->ff_Flags & FHF_READ) && !(han->ff_Flags & FHF_RPEND)) {
  580.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  581.                 han->ff_Flags |= FHF_RPEND;
  582.             }
  583.             if ((han->ff_Flags & FHF_WRITE) && !(han->ff_Flags & FHF_WAVAIL)) {
  584.                 RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  585.                 han->ff_Flags |= FHF_WAVAIL;
  586.             }
  587.             }
  588.             break;
  589.         case DOS_FALSE:     /*    COOKED    */
  590.             if (!(han->ff_Flags & FHF_COOKED)) {
  591.             han->ff_Flags |= FHF_COOKED;
  592.  
  593.             }
  594.             break;
  595.         }
  596.         }
  597.         break;
  598.     case ACTION_SEEK:        /*    FHArg1,Position,Mode        OldPosition */
  599.     default:
  600.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  601.         break;
  602.     }
  603.     if (packet) {
  604.         if (packet->dp_Res2)
  605.         packet->dp_Res1 = DOS_FALSE;
  606.         returnpacket(packet);
  607.     }
  608.     }
  609.     myexit(0);
  610. }
  611.  
  612. int
  613. OpenHandle(han, r_name, w_name, han_flags, opn_size, opn_flags)
  614. FHan *han;
  615. char *r_name;    /*  slave name    */
  616. char *w_name;    /*  master name */
  617. long han_flags;
  618. long opn_size;
  619. long opn_flags;
  620. {
  621.     if (han_flags & FHF_MASTER) {
  622.     strcpy(han->ff_Node.ln_Name, w_name);
  623.     } else {
  624.     char *swap;
  625.     strcpy(han->ff_Node.ln_Name, r_name);
  626.     swap = r_name;
  627.     r_name = w_name;
  628.     w_name = swap;
  629.     }
  630.  
  631.     if ((han_flags & FHF_TEE) == 0 && (han_flags & FHF_READ)) {
  632.     FHan *h2;
  633.     for (h2 = (FHan *)HanList.mlh_Head; h2->ff_Node.ln_Succ; h2 = (FHan *)h2->ff_Node.ln_Succ) {
  634.         if (strcmp(h2->ff_Node.ln_Name, han->ff_Node.ln_Name) == 0) {
  635.         if ((h2->ff_Flags & FHF_TEE) == 0 && h2->ff_SRead) {
  636.             han->ff_SRead = h2->ff_SRead;
  637.             ++han->ff_SRead->sr_Refs;
  638.             break;
  639.         }
  640.         }
  641.     }
  642.     }
  643.  
  644.     if ((han_flags & FHF_READ) && han->ff_SRead == NULL) {
  645.     han->ff_SRead = AllocMem(sizeof(SharRead), MEMF_CLEAR | MEMF_PUBLIC);
  646.     han->ff_SRead->sr_FifoR = OpenFifo(r_name, opn_size, opn_flags | FIFOF_READ);
  647.     han->ff_SRead->sr_Refs    = 1;
  648.     if (han->ff_FifoR == NULL)
  649.         return(-1);
  650.     }
  651.     if (han_flags & FHF_WRITE) {
  652.     han->ff_FifoW = OpenFifo(w_name, opn_size, opn_flags | FIFOF_WRITE);
  653.     if (han->ff_FifoW == NULL)
  654.         return(-1);
  655.     }
  656.     return(0);
  657. }
  658.  
  659. void
  660. CloseHandle(han)
  661. FHan *han;
  662. {
  663.     Remove(&han->ff_Node);
  664.     if (han->ff_SRead) {
  665.     if (--han->ff_SRead->sr_Refs == 0) {
  666.         if (han->ff_FifoR)
  667.         CloseFifo(han->ff_FifoR, 0);
  668.         FreeMem(han->ff_SRead, sizeof(SharRead));
  669.     }
  670.     han->ff_SRead = NULL;
  671.     }
  672.     if (han->ff_FifoW) {
  673.     if (han->ff_Flags & FHF_CLOSEEOF)
  674.         CloseFifo(han->ff_FifoW, FIFOF_EOF);
  675.     else
  676.         CloseFifo(han->ff_FifoW, 0);
  677.     han->ff_FifoW = NULL;
  678.     }
  679.     if (han->ff_Port) {
  680.     FreeMem(han->ff_Port, sizeof(MsgPort) + sizeof(Interrupt));
  681.     han->ff_Port = NULL;
  682.     }
  683.     if (han->ff_CookBuf)
  684.     FreeMem(han->ff_CookBuf, CB_SIZE);
  685.     FreeMem(han, sizeof(FHan) + strlen(han->ff_Node.ln_Name) + 1);
  686. }
  687.  
  688.  
  689. /*
  690.  *  handle cooked data by actually reading it from the fifo, echoing it
  691.  *  to the return channel (if it exists), and processing it.  If a <CR>
  692.  *  is processed, handle any
  693.  */
  694.  
  695. void
  696. HandleRequestMsg (struct Message *msg)
  697. {
  698.     FHan *han = (FHan *) msg->mn_Node.ln_Name;
  699.  
  700.     if (msg == &han->ff_WrMsg) {
  701.     han->ff_Flags &= ~FHF_WAVAIL;
  702.     while (msg = (struct Message *) RemHead ((struct List *) &han->ff_WrWait))  /*    retry operation */
  703.         PutMsg (PktPort, msg);
  704.  
  705.     /*
  706.      *  if we were blocked trying to echo, then read data pending,
  707.      *  make sure read-request is queued and will be retried.
  708.      */
  709.  
  710.     if (han->ff_Flags & FHF_COOKECHOBLK) {
  711.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  712.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  713.         han->ff_Flags |= FHF_RPEND;
  714.         }
  715.         han->ff_Flags &= ~FHF_COOKECHOBLK;
  716.     }
  717.     } else if (msg == &han->ff_RdMsg) {
  718.     han->ff_Flags &= ~FHF_RPEND;
  719.     if (han->ff_Flags & FHF_COOKED) {
  720.         long n;
  721.         long i;
  722.         short rwakeup = 0;
  723.         char *ptr;
  724.  
  725.         n = ReadFifo(han->ff_FifoR, &ptr, 0);
  726.  
  727.         if (n < 0) {
  728.         han->ff_Flags |= FHF_REOF;
  729.         rwakeup = 1;
  730.         }
  731.  
  732.         for (i = 0; i < n; ++i) {
  733.         switch(ptr[i]) {
  734.         case 13:
  735.         case 10:
  736.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  737.             han->ff_Flags |= FHF_COOKBFUL;
  738.             n = --i;
  739.             break;
  740.             }
  741.             if (han->ff_FifoW) {
  742.             if (WriteFifo(han->ff_FifoW, "\r\n", 2) != 2) {
  743.                 han->ff_Flags |= FHF_COOKECHOBLK;
  744.                 n = --i;
  745.                 break;
  746.             }
  747.             }
  748.             han->ff_CookBuf[han->ff_CookIdx++] = 0;
  749.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  750.             han->ff_LRet = 1;
  751.             rwakeup = 1;
  752.             break;
  753.         case 8:
  754.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] != 0) {
  755.             if (han->ff_FifoW) {
  756.                 if (WriteFifo(han->ff_FifoW, "\010 \010", 3) != 3) {
  757.                 han->ff_Flags |= FHF_COOKECHOBLK;
  758.                 n = --i;
  759.                 break;
  760.                 }
  761.             }
  762.             han->ff_CookBuf[--han->ff_CookIdx] = 0;
  763.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] == 0)
  764.                 han->ff_LRet = 1;
  765.             }
  766.             break;
  767.         default:
  768.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  769.             han->ff_Flags |= FHF_COOKBFUL;
  770.             n = --i;
  771.             break;
  772.             }
  773.             if (han->ff_FifoW) {
  774.             if (WriteFifo(han->ff_FifoW, ptr + i, 1) != 1) {
  775.                 han->ff_Flags |= FHF_COOKECHOBLK;
  776.                 n = --i;
  777.                 break;
  778.             }
  779.             }
  780.             han->ff_CookBuf[han->ff_CookIdx++] = ptr[i];
  781.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  782.             han->ff_LRet = 0;
  783.             break;
  784.         }
  785.         }
  786.  
  787.         /*
  788.          *    if output was held due to cooked input pending, and the
  789.          *    case is no longer true, then restart output
  790.          */
  791.  
  792.         if ((han->ff_Flags & FHF_WIHOLD) && (han->ff_LRet || han->ff_CookIdx == 0)) {
  793.         han->ff_Flags &= ~FHF_WIHOLD;
  794.         while (msg = (struct Message *) RemHead ((struct List *) &han->ff_WrWait))
  795.             PutMsg (PktPort, msg);
  796.         }
  797.  
  798.         if (i > 0) {
  799.         if (ReadFifo(han->ff_FifoR, &ptr, i) < 0) {
  800.             han->ff_Flags |= FHF_REOF;
  801.             rwakeup = 1;
  802.         }
  803.         }
  804.         if (n >= 0 && !(han->ff_Flags & (FHF_COOKECHOBLK|FHF_COOKBFUL|FHF_REOF))) {
  805.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  806.         han->ff_Flags |= FHF_RPEND;
  807.         }
  808.         if (!rwakeup)
  809.         return;
  810.     }
  811.     while (msg = (struct Message *) RemHead ((struct List *) &han->ff_RdWait))  /*    retry operation */
  812.         PutMsg (PktPort, msg);
  813.     }
  814. }
  815.  
  816. void
  817. WaitMsg (struct Message *msg)
  818. {
  819.     while (msg->mn_Node.ln_Type == NT_MESSAGE)
  820.     Wait(1 << msg->mn_ReplyPort->mp_SigBit);
  821.     Forbid();
  822.     Remove(&msg->mn_Node);
  823.     Permit();
  824. }
  825.  
  826. void
  827. SigHandles (char *name, long sigs)
  828. {
  829.     FHan *han;
  830.  
  831.     for (han = (FHan *)HanList.mlh_Head; han->ff_Node.ln_Succ; han = (FHan *)han->ff_Node.ln_Succ) {
  832.     if (strcmp(han->ff_Node.ln_Name, name) == 0 && han->ff_Task)
  833.         Signal(han->ff_Task, sigs);
  834.     }
  835. }
  836.  
  837. /*
  838.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  839.  *  can see by this and how the PACKET structure is extracted in the
  840.  *  GetMsg() of the main routine.
  841.  */
  842.  
  843. void
  844. returnpacket (DosPacket *packet)
  845. {
  846.     Message *mess;
  847.     MsgPort *replyPort;
  848.  
  849.     replyPort             = packet->dp_Port;
  850.     mess             = packet->dp_Link;
  851.     packet->dp_Port         = PktPort;
  852.     mess->mn_Node.ln_Name    = (char *)packet;
  853.     PutMsg(replyPort, mess);
  854. }
  855.  
  856. void
  857. Initialize (void)
  858. {
  859.     struct Process
  860.     *proc = (struct Process *) FindTask (NULL);
  861. #ifndef CLI_START
  862.     DeviceNode
  863.     *dn;
  864.     DosPacket
  865.     *packet;
  866. #endif
  867.  
  868.     /*
  869.      *    Initialize port
  870.      */
  871.  
  872.     {
  873.     IoSink = CreatePort("FIFO-PORT", 0);
  874.     FreeSignal(IoSink->mp_SigBit);
  875.     IoSink->mp_SigBit = SIGBREAKB_CTRL_F;
  876.     }
  877.     PktPort = CreatePort(NULL, 0);
  878.     PktPortMask = 1 << PktPort->mp_SigBit;
  879.  
  880. #ifdef CLI_START
  881.  
  882.     /*
  883.      *    create DOS node
  884.      */
  885.  
  886.     MkDevice("FIFO");
  887.  
  888.     FifoBase = OpenLibrary("fifo.library", 0);
  889.  
  890. #else
  891.  
  892.     /*
  893.      *    Handle initial message.  We pull the message off the port before
  894.      *    calling OpenLibrary() so if OpenLibrary() makes a DOS call it
  895.      *    doesn't crash the machine (due to an unexpected packet).  This
  896.      *    will happen if the library needs to be loaded.    There is no other
  897.      *    safe time to do this.
  898.      */
  899.  
  900.     {
  901.     Message *msg;
  902.  
  903.     WaitPort(&proc->pr_MsgPort);
  904.     msg = GetMsg(&proc->pr_MsgPort);
  905.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  906.     }
  907.  
  908.     /*
  909.      *    Fifo Library
  910.      */
  911.  
  912.     FifoBase = OpenLibrary("fifo.library", 0);
  913.  
  914.     {
  915.     DevNode = dn = BTOC(packet->dp_Arg3);
  916.  
  917.     dn->dn_Task = PktPort;
  918.     packet->dp_Res1 = (FifoBase) ? DOS_TRUE : DOS_FALSE;
  919.     packet->dp_Res2 = 0;
  920.     returnpacket(packet);
  921.     }
  922.  
  923. #endif
  924.  
  925.     if (FifoBase == NULL)
  926.     myexit(1);
  927. }
  928.  
  929. void
  930. myexit (int code)
  931. {
  932. #ifdef CLI_START
  933.     DelDevice();
  934. #else
  935.  
  936.     /*
  937.      *    Device Node
  938.      */
  939.  
  940.     {
  941.     DeviceNode *dn = DevNode;
  942.  
  943.     dn->dn_Task = NULL;
  944.     dn->dn_SegList = NULL;
  945.     }
  946. #endif
  947.  
  948.     /*
  949.      *    delete ports
  950.      */
  951.  
  952.     if (IoSink) {
  953.     IoSink->mp_SigBit = AllocSignal(-1);
  954.     DeletePort(IoSink);
  955.     }
  956.  
  957.     if (PktPort)
  958.     DeletePort(PktPort);
  959.  
  960. #ifdef DEBUG
  961.     if (DBFifo) {
  962.     CloseFifo(DBFifo, FIFOF_EOF);
  963.     DBFifo = NULL;
  964.     }
  965. #endif
  966.     if (FifoBase) {
  967.     CloseLibrary(FifoBase);
  968.     FifoBase = NULL;
  969.     }
  970.     _exit(code);
  971. }
  972.  
  973.  
  974. MsgPort *
  975. SpecPort (FHan *han)
  976. {
  977.     MsgPort *port = AllocMem(sizeof(MsgPort) + sizeof(Interrupt), MEMF_CLEAR|MEMF_PUBLIC);
  978.     Interrupt *xint = (Interrupt *)(port + 1);
  979.     extern void AIntCode();
  980.  
  981.     NewList(&port->mp_MsgList);
  982.     port->mp_Node.ln_Name = (char *)han;
  983.     port->mp_Node.ln_Type = NT_MSGPORT;
  984.     port->mp_Flags = PA_SOFTINT;
  985.     port->mp_SigTask = (void *)xint;
  986.     xint->is_Node.ln_Type = NT_INTERRUPT;
  987.     xint->is_Node.ln_Pri  = -32;
  988.     xint->is_Data = (APTR)port;
  989.     xint->is_Code = AIntCode;
  990.     return(port);
  991. }
  992.  
  993. __geta4 __stkargs void
  994. IntCode (MsgPort *port)
  995. {
  996.     Message *msg;
  997.     DosPacket *packet;
  998.     FileHandle *fh;
  999.  
  1000. #ifdef DEBUG
  1001.     if (DDebug)
  1002.     xprintf("port %08lx\n", port);
  1003. #endif
  1004.     while (msg = GetMsg(port)) {
  1005.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1006.  
  1007. #ifdef DEBUG
  1008.     if (DDebug)
  1009.         xprintf("type %08lx\n", packet->dp_Type);
  1010. #endif
  1011.  
  1012.  
  1013.     switch(packet->dp_Type) {
  1014.     case ACTION_FINDUPDATE:
  1015.     case ACTION_FINDINPUT:
  1016.     case ACTION_FINDOUTPUT:
  1017.         fh = BTOC(packet->dp_Arg1);
  1018.         fh->fh_Port = port;
  1019.         break;
  1020.     case ACTION_SCREEN_MODE:
  1021.     case ACTION_WAIT_CHAR:        /* DAV 3Sep92 */
  1022.         packet->dp_Arg2 = (LONG) port;
  1023.         break;
  1024.     }
  1025.     PutMsg(PktPort, msg);
  1026.     }
  1027. }
  1028.  
  1029. #ifdef DEBUG
  1030.  
  1031. void
  1032. xprintf (char *ctl, ...)
  1033. {
  1034.     va_list va;
  1035.     static char buf[256];
  1036.     int n;
  1037.  
  1038.     if (DBFifo) {
  1039.     va_start(va, ctl);
  1040.     n = vsprintf(buf, ctl, va);
  1041.     if (n > 0)
  1042.         WriteFifo(DBFifo, buf, n);
  1043.     va_end(va);
  1044.     }
  1045. }
  1046.  
  1047. #endif
  1048.  
  1049. #ifdef CLI_START
  1050.  
  1051. /*
  1052.  *  DEVICE CREATION AND DELETION
  1053.  */
  1054.  
  1055. DosList *Dl;
  1056.  
  1057. void
  1058. MkDevice (char *devName)
  1059. {
  1060.     DosList *dl;
  1061.     RootNode *root;
  1062.     DosInfo *info;
  1063.  
  1064.     Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
  1065.     strcpy((char *)(dl+1) + 1, devName);
  1066.     *(char *)(dl + 1) = strlen(devName);
  1067.     dl->dol_Type = DLT_DEVICE;
  1068.     dl->dol_Task = PktPort;
  1069.     dl->dol_Name = MKBADDR((char *)(dl+1));
  1070.  
  1071.     Forbid();
  1072.     root  = (struct RootNode *)DOSBase->dl_Root;
  1073.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1074.     dl->dol_Next = info->di_DevInfo;
  1075.     info->di_DevInfo = MKBADDR(dl);
  1076.     Permit();
  1077. }
  1078.  
  1079. void
  1080. DelDevice (void)
  1081. {
  1082.     DosList *dl;
  1083.     DosInfo *info;
  1084.     RootNode *root;
  1085.     DosList *dls;
  1086.     BPTR    *bpp;
  1087.  
  1088.     if (dl = Dl) {
  1089.     Forbid();
  1090.     root  = (struct RootNode *)DOSBase->dl_Root;
  1091.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1092.  
  1093.     for (bpp = &info->di_DevInfo; dls = BADDR(*bpp); bpp = &dls->dol_Next) {
  1094.         if (dls == dl)
  1095.         break;
  1096.     }
  1097.     if (dls == dl) {
  1098.         *bpp = dls->dol_Next;
  1099.     } else {
  1100.         Alert(0x07AAAAAA|AT_Recovery);
  1101.     }
  1102.     Permit();
  1103.     DosFree(dl);
  1104.     Dl = NULL;
  1105.     }
  1106. }
  1107.  
  1108. void *
  1109. DosAllocMem (long bytes)
  1110. {
  1111.     long *ptr;
  1112.  
  1113.     bytes += 4;
  1114.  
  1115.     if (ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR)) {
  1116.     *ptr++ = bytes;
  1117.     return((void *)ptr);
  1118.     }
  1119.     Alert(AG_NoMemory|AT_DeadEnd);
  1120. }
  1121.  
  1122. void
  1123. DosFree (void *vptr)
  1124. {
  1125.     long *ptr = vptr;
  1126.     --ptr;
  1127.     FreeMem(ptr, *ptr);
  1128. }
  1129.  
  1130. #endif
  1131.