home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / fifolib-38.3-src.tgz / tar.out / contrib / fifolib / fifo-handler.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  37KB  |  1,425 lines

  1.  
  2. /*
  3.  *  FIFO-HANDLER.C    V38.2
  4.  *
  5.  *  Provide an interface to the fifo.library
  6.  *  Provide remote shell support, including "*", interactive and 2.0 support.
  7.  *
  8.  *  !!! MUST BE RUN, CANNOT USE MOUNT !!!
  9.  *
  10.  *  FIFO:fifo_name/flags
  11.  *           r    for reading
  12.  *           w    for writing
  13.  *           c    cooked (else raw)
  14.  *           e    EOF on close (if a writer)
  15.  *           k    allows writer to close before reader opens without
  16.  *            any data lost.
  17.  *           K    a reader MUST exist or write(s) will fail
  18.  *           q    QUIT (debugging)
  19.  *           m    master
  20.  *           t    tee off the read stream (no interference with other
  21.  *            readers)
  22.  *           s    shell
  23.  *
  24.  *           d    debug mode (read by running 'RemCLI DBFifo')
  25.  *           x    exit debug mode
  26.  */
  27.  
  28. #define CLI_START
  29.  
  30. #include "handler.h"
  31.  
  32. /*  These packets are strictly internal to the handler */
  33. #define FACTION_SCREEN_MODE    ACTION_WRITE_RETURN
  34. #define FACTION_WAIT_CHAR    ACTION_READ_RETURN
  35. #define ACTION_WAIT_TIMEOUT    ACTION_TIMER
  36.  
  37. int myexit(int);
  38. void Initialize(void);
  39. void HandleRequestMsg(Message *);
  40. void WaitMsg(Message *);
  41. void SigHandles(char *, unsigned long);
  42. void returnpacket(DosPacket *);
  43. static inline char not_console(char *, unsigned char);
  44. static inline short line1_length(FHan *);
  45. void xprintf(char *, ...);
  46. FHan *OpenHandle(char *, char *, long, long);
  47. void CloseHandle(FHan *);
  48. MsgPort *SpecPort(FHan *);
  49. static inline void *DosAllocMem(long);
  50. static inline void DosFree(void *);
  51. void MkDevice(char *);
  52. void DelDevice(void);
  53. WaitTreq *AllocTimerequest(unsigned long timeout);
  54.  
  55. struct Library  * FifoBase;
  56. MsgPort        *IoSink;
  57. MsgPort        *PktPort, *TimerPort;
  58. long        PortsMask;        /*  could be local ... */
  59. #ifndef CLI_START
  60. DeviceNode  *DevNode;
  61. #endif
  62. WaitTreq    *TimerIO;
  63. List        HanList;
  64. #ifdef DEBUG
  65. FifoHan        DBFifo;
  66. short        DDebug;
  67. #define D(x)  if (DDebug) x ;
  68. #define ebug  xprintf
  69. #else
  70. #define D(x)  ;
  71. #endif
  72. short        Done;    /*  could be local, but DICE2.06 uses up a register */
  73.  
  74. const char verstring[] = "\0$VER: fifo-handler 38.3 (28.8.96)\r\n";
  75.  
  76.  
  77. #ifdef DEBUG
  78.  
  79. #if defined(__GNUC__)
  80. /*  Do not use vsprintf from Libnix, it requires all of stdio.
  81.  *  Builtin vsprintf has the advantage that htag.S can still be used.
  82.  */
  83. __asm(".even;_put1char:;"
  84.       "movel a3@,a0; moveb d0,a0@+; movel a0,a3@; rts");
  85.  
  86. static inline
  87. int
  88. romvsprintf(char *buf, char *ctl, void *args)
  89. {
  90.   extern void put1char();
  91.   char *bufptr = buf;
  92.   RawDoFmt(ctl, args, put1char, &bufptr);
  93.   return bufptr - buf;
  94. }
  95. #define vsprintf romvsprintf
  96. #define romvsprintf romvsprintf
  97. #endif
  98.  
  99. void
  100. xprintf(char *ctl, ...)
  101. {
  102.     va_list va;
  103.     static char buf[256];
  104.     int n;
  105.  
  106.     if (DBFifo) {
  107.     va_start(va, ctl);
  108.     n = vsprintf(buf, ctl, va);
  109.     if (n > 0)
  110.         WriteFifo(DBFifo, buf, n);
  111.     va_end(va);
  112.     }
  113. }
  114.  
  115. #endif /*  DEBUG */
  116.  
  117. static inline char
  118. not_console(char *bas, unsigned char len)
  119. {
  120.     short n = 7;
  121.     if (len == 1)
  122.     return ('*' - *bas);
  123.     if (len <= (unsigned char) n)
  124.     return n;
  125.     {
  126.     const char *console = "CONSOLE:";
  127.     char r1, r2;
  128.  
  129.     while(!(r1=*console++ - (char)((r2=*bas++) >= 'a' ? r2 - ('a' - 'A') : r2))
  130.           /* && r2 */ && --n != -1) ;
  131.     return r1;
  132.     }
  133. }
  134.  
  135. static inline short
  136. line1_length(FHan *han)
  137. {
  138.     short m = 0;
  139.     short n = han->ff_CookIdx;
  140.     if (n != 0) {
  141.     --n;
  142.     do { char c = han->ff_CookBuf[m];
  143.          if (c == CHAR_EOF) return m;
  144.          m++;
  145.          if (c == '\n') return m;
  146.     } while (--n != -1);    /*  make GCC generate dbra */
  147.     }
  148.     return -1;
  149. }
  150.  
  151. #if !defined(__GNUC__)
  152. __stkargs int            /*  changed from void (jch) */
  153. _main(char *arg, long len)
  154. #else
  155. int _main(void)            /*  my special startup since libnix is >=2.0 */
  156. #endif
  157. {
  158.     DosPacket  *packet;
  159.  
  160.     NewList((MaxList *)&HanList);
  161.  
  162.     Initialize();
  163.     if (FifoBase == NULL)
  164.     return myexit(RETURN_FAIL);
  165.  
  166.     /*
  167.      *    Main Loop
  168.      */
  169.  
  170.     while (!Done || HanList.mlh_TailPred != (Node *)&HanList) {
  171.     {
  172.         Message *msg;
  173.  
  174.         while ((msg = GetMsg(IoSink)))
  175.         HandleRequestMsg(msg);
  176.         if ((msg = GetMsg(PktPort)) == NULL) {
  177.         /*  handler depends on TimerPort being used last */
  178.         if ((msg = GetMsg(TimerPort)) == NULL) {
  179.             if (Wait(SIGS | PortsMask) & SIGBREAKF_CTRL_C)
  180.             Done = 1;
  181.             continue;
  182.         } else {
  183.             /*  Got a timeout from timer.device */
  184.             packet = ((WaitTreq *)msg)->wt_packet;
  185.             ((WaitTreq *)msg)->wt_packet = NULL; /*  means timeout */
  186.         }
  187.         } else
  188.         packet = (DosPacket *)msg->mn_Node.ln_Name;
  189.     }
  190.     switch(packet->dp_Type) {
  191.     case ACTION_WRITE:
  192.     case FACTION_SCREEN_MODE:
  193.     case FACTION_WAIT_CHAR:
  194.     case ACTION_WAIT_TIMEOUT:
  195.         break;        /*  use dp_Res1 for temporary storage */
  196.     default:
  197.         packet->dp_Res1 = DOS_TRUE;
  198.     }
  199.     packet->dp_Res2 = DOS_FALSE;
  200.  
  201.     D(ebug("packet %ld\n", packet->dp_Type));
  202.  
  203.     switch(packet->dp_Type) {
  204.     case ACTION_DIE:
  205.         Done = 1;
  206.         break;
  207.     case ACTION_FINDUPDATE:        /*    FileHandle,Lock,Name        Bool    */
  208.     case ACTION_FINDINPUT:        /*    FileHandle,Lock,Name        Bool    */
  209.     case ACTION_FINDOUTPUT:        /*    FileHandle,Lock,Name        Bool    */
  210.         {
  211.         FileHandle *fh = BTOC(packet->dp_Arg1);
  212.         char fifo_name_m[128];
  213.         char fifo_name_s[128];
  214.         long han_flags = 0;
  215.         long opn_flags = FIFOF_NORMAL | FIFOF_NBIO;
  216.         short error = 0;
  217.  
  218.         {
  219.             char *bas = BTOC(packet->dp_Arg3);
  220.             char *ptr;
  221.             unsigned char len = *(unsigned char *)bas++;
  222.  
  223. #if defined(DEBUG) && defined(romvsprintf)
  224.             /*  RawDoFmt() does not understand the * flag */
  225.             if (DDebug) {
  226.             char format[18];
  227.             long args[2];
  228.             args[1] = args[0] = len;
  229.             romvsprintf(format, "open: %%%ld.%lds\n", args);
  230.             xprintf(format, bas);
  231.             }
  232. #else
  233.             D(ebug("open: %*.*s\n", len, len, bas));
  234. #endif
  235.             if (!not_console(bas, len)) { /*  either "*" or "Console:" */
  236.             if (fh->fh_Port && (long)fh->fh_Port != -1) {
  237.                 FHan *han;
  238.                 /*  assume IntCode() filled fh_Port with port */
  239.                 /*  ln_name was filled with FHan by SpecPort() */
  240.                 han = (FHan *)fh->fh_Port->mp_Node.ln_Name;
  241.                 ++han->ff_Refs;
  242.                 fh->fh_Arg1 = (LONG)han;
  243.                 fh->fh_Port = (MsgPort *)DOS_TRUE; /*  means interactive */
  244.                 break;
  245.             }
  246.             /* fh->fh_Port = (MsgPort *)DOS_FALSE; */
  247.             packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  248.             break;
  249.             }
  250.  
  251.             /*  skip "fifo:" part */
  252.             for (ptr = bas; len && *ptr != ':'; ++ptr, --len) ;
  253.             if (len && *ptr == ':') {
  254.             bas = ptr + 1;
  255.             --len;
  256.             } else {
  257.             len = ptr - bas; /*  restore len */
  258.             }
  259.             for (ptr = bas; len && *ptr != '/'; ++ptr, --len) ;
  260.             {
  261.             short i = ptr - bas;
  262.             if (/* i && */ i < 126) {
  263.                 strncpy(fifo_name_m, bas, i);
  264.                 strncpy(fifo_name_s, bas, i);
  265.                 /*  GCC can optimize these into MOVEB sequences */
  266.                 strcpy(fifo_name_m + i, "_m");
  267.                 strcpy(fifo_name_s + i, "_s");
  268.             } else
  269.                 error = 1; /*  nevertheless get flags */
  270.             }
  271.             /*  get flags */
  272.             if (len && *ptr == '/') {
  273.             unsigned long sigs = 0;
  274.             for (++ptr, --len; len; ++ptr, --len) {
  275.                 switch(*ptr) {
  276.                 case 'q':
  277.                 Done = 1;
  278.                 break;
  279.                 case 'e':
  280.                 han_flags |= FHF_CLOSEEOF;
  281.                 break;
  282.                 case 'c':
  283.                 han_flags |= FHF_COOKED|FHF_STARTCOOK;
  284.                 break;
  285.                 case 's':
  286.                 han_flags |= FHF_SHELL;
  287.                 break;
  288.                 case 'r':
  289.                 han_flags |= FHF_READ;
  290.                 break;
  291.                 case 'w':
  292.                 han_flags |= FHF_WRITE;
  293.                 break;
  294.                 case 'k':
  295.                 opn_flags |= FIFOF_KEEPIFD;
  296.                 break;
  297.                 case 'K':
  298.                 opn_flags |= FIFOF_RREQUIRED;
  299.                 break;
  300.                 case 'm':
  301.                 han_flags |= FHF_MASTER;
  302.                 break;
  303.                 case 't':
  304.                 han_flags |= FHF_TEE;
  305.                 break;
  306.                 case 'd':
  307. #ifdef DEBUG
  308.                 if (DDebug == 0) {
  309.                     DDebug = 1;
  310.                     DBFifo = OpenFifo("DBFifo_s", 1024, FIFOF_WRITE | FIFOF_NORMAL);
  311.                 }
  312. #endif
  313.                 break;
  314.                 case 'x':
  315. #ifdef DEBUG
  316.                 if (DDebug) {
  317.                     DDebug = 0;
  318.                     if (DBFifo)
  319.                     CloseFifo(DBFifo, FIFOF_EOF);
  320.                     DBFifo = NULL;
  321.                 }
  322. #endif
  323.                 break;
  324.                 case 'C':
  325.                 sigs |= SIGBREAKF_CTRL_C;
  326.                 break;
  327.                 case 'D':
  328.                 sigs |= SIGBREAKF_CTRL_D;
  329.                 break;
  330.                 case 'E':
  331.                 sigs |= SIGBREAKF_CTRL_E;
  332.                 break;
  333.                 case 'F':
  334.                 sigs |= SIGBREAKF_CTRL_F;
  335.                 break;
  336.                 default:
  337.                 error = 1;
  338.                 break;
  339.                 }
  340.             }
  341.             if (sigs)
  342.                 SigHandles((han_flags & FHF_MASTER)
  343.                        ? fifo_name_m : fifo_name_s, sigs);
  344.             }
  345.         }
  346.         if (((han_flags & FHF_COOKED) &&
  347.              ((han_flags & FHF_MASTER) ||    /*  as documented */
  348.               !(han_flags & FHF_READ)))        /*  necessary     */
  349.             || !(han_flags & (FHF_READ | FHF_WRITE)))
  350.             error = 1;
  351.         /*
  352.          *  To handle the stderr channel, "*", an interactive
  353.          *  shell must be opened with the 's' flag, which causes
  354.          *  a special message port to be created for the interactive
  355.          *  shell (and thus the pr_ConsoleTask field)
  356.          *
  357.          *  To handle COOKED data mode, FIFO: itself must processed
  358.          *  received data before the slave device, echoing it back
  359.          *  on the master channel and doing other cooked processing.
  360.          */
  361.  
  362.         if (!error) {
  363.             FHan *han;
  364.             if (NULL != (han = OpenHandle(fifo_name_s, fifo_name_m, han_flags, opn_flags))) {
  365.             if (han_flags & FHF_SHELL) {
  366.                 fh->fh_Type = han->ff_Port;    /*  special port */
  367.             }
  368.             fh->fh_Arg1 = (LONG)han;
  369.             fh->fh_Port = (MsgPort *)DOS_TRUE; /*  means interactive */
  370.             han->ff_SigPort = packet->dp_Port; /*  for SIGBREAKF_CTRL_* */
  371.             break;
  372.             } else {
  373.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  374.             break;
  375.             }
  376.         }
  377.         packet->dp_Res2 = ERROR_BAD_STREAM_NAME;
  378.         }
  379.         break;
  380.     case ACTION_READ:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  381.         /*
  382.          *    read from fifo.     If we are in cooked mode this action is
  383.          *    only able to read from the cooked buffer, and then only
  384.          *    if a line is complete.
  385.          */
  386.  
  387.         {
  388.         FHan *han = (FHan *)packet->dp_Arg1;
  389.         long n;
  390.  
  391.         if (!(han->ff_Flags & FHF_READ)) {
  392.             packet->dp_Res1 = -1;
  393.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  394.             returnpacket(packet); /*  or loose dp_Res1 */
  395.             packet = NULL;
  396.             break;
  397.         }
  398.         if (han->ff_Flags & FHF_REOF) {
  399.             han->ff_Flags &= ~FHF_REOF;
  400.             packet->dp_Res1 = 0;
  401.             break;
  402.         }
  403.  
  404.         han->ff_Flags &= ~FHF_STARTCOOK; /*  restarted below */
  405.         if (han->ff_CookBuf
  406.           && ((han->ff_Flags & FHF_COOKED)
  407.               ? (0 <= han->ff_CookLen1)
  408.               : han->ff_CookIdx)) {
  409.             /*
  410.              *    cooked input is available
  411.              *    do not read too much in raw mode, a line at a time
  412.              *    this code will fail for dp_Arg3 (# to read) == 0 in raw mode
  413.              */
  414.  
  415.             n = han->ff_CookLen1; /*  0 means EOF */
  416.             D(ebug("Can read %ld chars\n", n));
  417.             if (n > packet->dp_Arg3)
  418.             n = packet->dp_Arg3;
  419.             {
  420.             long m = n;
  421.             /*
  422.              *  CON: sends EOF in raw mode for a cooked EOF read
  423.              *  I choose to transmit ctrl-\ because FIFO: is
  424.              *  likely to receive pre-"typed", non-manual input
  425.              */
  426.             if (m == 0 && !(han->ff_Flags & FHF_COOKED)) m = 1;
  427.  
  428.             packet->dp_Res1 = m;
  429.             memmove((void *)packet->dp_Arg2, han->ff_CookBuf, m);
  430.             }
  431.             if (n == 0) n = 1; /*  skip EOF marker */
  432.             han->ff_CookIdx -= n;
  433.             /*  overlapping memory! */
  434.             memmove(han->ff_CookBuf, han->ff_CookBuf + n, han->ff_CookIdx);
  435.  
  436.             if (n < han->ff_CookLen1) {
  437.             han->ff_CookLen1 -= n;
  438.             } else {
  439.             han->ff_CookLen1 = line1_length(han);
  440.             }
  441.             /*
  442.              *    if we blocked on reading the fifo to cook more
  443.              *    data, we unblock it here.
  444.              */
  445.  
  446.             han->ff_Flags &= ~FHF_COOKBFUL;
  447.  
  448.             if (han->ff_Flags & FHF_COOKED &&
  449.             !(han->ff_Flags & FHF_RPEND)) {
  450.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  451.             han->ff_Flags |= FHF_RPEND;
  452.             }
  453.             break;
  454.         }
  455.         if (!(han->ff_Flags & FHF_COOKED)) {
  456.             char *ptr;
  457.  
  458.             n = ReadFifo(han->ff_FifoR, &ptr, 0);
  459.             D(ebug("%ld chars available\n", n));
  460.             if (n < 0 /* || (n == 0 && (han->ff_Flags & FHF_REOF)--impossible)*/) {
  461.             han->ff_Flags &= ~FHF_REOF;
  462.             packet->dp_Res1 = 0;
  463.             break;
  464.             }
  465.             if (n > 0) {
  466.             /*  Hans Verkuil introduced a patch to only read upto \n,
  467.              *  however RAW: does not exhibit this behaviour.
  468.              */
  469.             if (n > packet->dp_Arg3)
  470.                 n = packet->dp_Arg3;
  471.             CopyMem(ptr, (void *)packet->dp_Arg2, n);
  472.             packet->dp_Res1 = n;
  473.  
  474.             if (ReadFifo(han->ff_FifoR, &ptr, n) < 0)
  475.                 han->ff_Flags |= FHF_REOF;
  476.             /*
  477.              *  Concatenating data when last result is > 0 gives
  478.              *  not much, as with the way packets are sequenced
  479.              *  here, it is usually only possible once when
  480.              *  unblocking from a full buffer.
  481.              */
  482.             break;
  483.             }
  484.         }
  485.  
  486.         /*
  487.          *  blocked
  488.          */
  489.  
  490.         AddTail((MaxList *)&han->ff_RdWait, &packet->dp_Link->mn_Node);
  491.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  492.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  493.             han->ff_Flags |= FHF_RPEND;
  494.         }
  495.         packet = NULL;
  496.         }
  497.         break;
  498.     case ACTION_WRITE:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  499.         {
  500.         FHan *han = (FHan *)packet->dp_Arg1;
  501.         long n;
  502.         long i;
  503.  
  504.         if (!(han->ff_Flags & FHF_WRITE)) {
  505.             packet->dp_Res1 = -1;
  506.             packet->dp_Res2 = ERROR_WRITE_PROTECTED;
  507.             returnpacket(packet); /*  or loose dp_Res1 */
  508.             packet = NULL;
  509.             break;
  510.         }
  511.  
  512.         i = packet->dp_Arg3;
  513.         if (i < 0) {    /*  re-scan    */
  514.             i = -i;
  515.             packet->dp_Arg3 = i;
  516.         } else {    /*  initial pkt */
  517.             packet->dp_Res1 = 0;
  518.         }
  519.  
  520.         /*
  521.          *  check for output stopped due to pending input line
  522.          *
  523.          *  dp_Arg3 < 0 indicates a re-scan (so we do not clear
  524.          *  our dp_Res1 field that is tracking the amnt written)
  525.          */
  526.  
  527.         if ((han->ff_Flags & FHF_COOKED) && (han->ff_Flags & FHF_WISTOP)) {
  528.             packet->dp_Arg3 = -packet->dp_Arg3;
  529.             AddTail((MaxList *)&han->ff_WrWait, &packet->dp_Link->mn_Node);
  530.             han->ff_Flags |= FHF_WIHOLD;
  531.             packet = NULL;
  532.             break;
  533.         }
  534.  
  535.         /*
  536.          *  limit size of writes to fifo to something the fifo can
  537.          *  handle.  If cooked mode writer, prepend CR to LF's.
  538.          */
  539.  
  540.         if (i > han->ff_FHBufSiz)
  541.             i = han->ff_FHBufSiz;
  542.  
  543.         if (han->ff_Flags & FHF_COOKED) {
  544.             char *ptr = (char *)packet->dp_Arg2;
  545.             long j;
  546.  
  547.             /*  n is always initialized because i >= 0 */
  548.             for (j = 0; j < i; ++j) {
  549.             if (ptr[j] == '\n') {
  550.                 if (j == 0) {
  551.                 n = WriteFifo(han->ff_FifoW, "\r\n", 2);
  552.                 if (n == 2)
  553.                     n = 1;    /*  skip LF */
  554.                 break;
  555.                 }
  556.                 n = WriteFifo(han->ff_FifoW, ptr, j);
  557.                 break;
  558.             }
  559.             }
  560.             if (i == j)
  561.             n = WriteFifo(han->ff_FifoW, ptr, i);
  562.         } else
  563.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  564.  
  565.         /*
  566.          *  object too large or broken pipe
  567.          */
  568.  
  569.         if (n < 0) {    /*  most probably for FIFO_RREQUIRED */
  570.             packet->dp_Res1 = -1;
  571.             packet->dp_Res2 = (n == -2)
  572.               ? ERROR_OBJECT_TOO_LARGE /*  can this really happen? */
  573.               : ERROR_WRITE_PROTECTED;
  574.             returnpacket(packet); /*  or loose dp_Res1 */
  575.             packet = NULL;
  576.             break;
  577.         }
  578.  
  579.         packet->dp_Res1 += n;
  580.         if (n == packet->dp_Arg3)
  581.             break;
  582.  
  583.         packet->dp_Arg3 = -(packet->dp_Arg3 - n);
  584.         packet->dp_Arg2 += n;
  585.  
  586.         /*
  587.          *  blocked (n == 0)
  588.          *  or splitted
  589.          */
  590.  
  591.         AddTail((MaxList *)&han->ff_WrWait, &packet->dp_Link->mn_Node);
  592.         if ((han->ff_Flags & FHF_WAVAIL) == 0) {
  593.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  594.             han->ff_Flags |= FHF_WAVAIL;
  595.         }
  596.         packet = NULL;
  597.         }
  598.         break;
  599.     case ACTION_REQUEST:        /*    FHArg1, msg, how        Bool    */
  600.         {
  601.         FHan *han = (FHan *)packet->dp_Arg1;
  602.  
  603.         if ((unsigned short)packet->dp_Arg3 == FREQ_RPEND) {
  604.             if (han->ff_FifoR) {
  605.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  606.             break;
  607.             }
  608.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_WAVAIL) {
  609.             if (han->ff_FifoW) {
  610.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  611.             break;
  612.             }
  613.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_ABORT) {
  614.             if (han->ff_FifoR)
  615.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  616.             if (han->ff_FifoW)
  617.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  618.             break;
  619.         }
  620.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  621.         }
  622.         break;
  623.     case ACTION_END:        /*    FHArg1                Bool:TRUE    */
  624.         {
  625.         FHan *han = (FHan *)packet->dp_Arg1;
  626.  
  627.         if (--han->ff_Refs == 0) {
  628.             if (han->ff_Flags & FHF_RPEND) {
  629.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  630.             WaitMsg(&han->ff_RdMsg);
  631.             }
  632.             if (han->ff_Flags & FHF_WAVAIL) {
  633.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_ABORT);
  634.             WaitMsg(&han->ff_WrMsg);
  635.             }
  636.             /*  no need to do bookkeeping for ACTION_WAIT_CHAR */
  637.             returnpacket(packet);   /*  before ff_Port goes away */
  638.             packet = NULL;
  639.             CloseHandle(han);
  640.         }
  641.         }
  642.         break;
  643.     /*  Added for 37.5 and 38.0 */
  644.     case FACTION_WAIT_CHAR:        /*    timeout                Bool    */
  645.         /*
  646.          *  as ACTION_WAIT_CHAR does not give a filehandle, we get it
  647.          *  indirectly through the special port. Fold packet type for safety.
  648.          */
  649.         packet->dp_Type = ACTION_WAIT_CHAR;
  650.         {
  651.         FHan *han = (FHan *) (((MsgPort *) packet->dp_Res1)->mp_Node.ln_Name);
  652.         unsigned long timeout = packet->dp_Arg1;
  653.         WaitTreq *treq;
  654.  
  655.         if (!(han->ff_Flags & FHF_READ)) {
  656.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  657.             break;
  658.         }
  659.         if (han->ff_Flags & FHF_REOF) {
  660.             packet->dp_Res1 = DOS_TRUE;
  661.             break;
  662.         }
  663.         if (han->ff_Flags & FHF_COOKED) {
  664.             if (0 <= han->ff_CookLen1) {
  665.             packet->dp_Res1 = DOS_TRUE;
  666.             break;
  667.             }
  668.         } else {
  669.             char *ptr;
  670.             if ((han->ff_CookBuf && han->ff_CookIdx)
  671.             /*  cooked input is available */
  672.               || ReadFifo(han->ff_FifoR, &ptr, 0)) {
  673.             packet->dp_Res1 = DOS_TRUE;
  674.             break;
  675.             }
  676.         }
  677.         /*  always queue if cooked processing must be started */
  678.         if (timeout <= 50 /* microseconds */ && !(han->ff_Flags & FHF_STARTCOOK)) {
  679.             packet->dp_Res1 = DOS_FALSE;
  680.             break;
  681.         }
  682.  
  683.         /*
  684.          *  queue packet
  685.          */
  686.  
  687.         if (NULL != (treq = AllocTimerequest(timeout))) {
  688.             treq->wt_packet = packet;
  689.             packet->dp_Type = ACTION_WAIT_TIMEOUT;
  690.             packet->dp_Res1 = (LONG)treq;
  691.             han->ff_Flags &= ~FHF_STARTCOOK;
  692.             AddTail((MaxList *)&han->ff_RdWait, &packet->dp_Link->mn_Node);
  693.             if (!(han->ff_Flags & FHF_RPEND)) {
  694.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  695.             han->ff_Flags |= FHF_RPEND;
  696.             }
  697.             SendIO(&treq->wt_timereq.tr_node);
  698.             packet = NULL;
  699.             break;
  700.         } else
  701.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  702.         }
  703.         break;
  704.     case ACTION_WAIT_TIMEOUT:
  705.         packet->dp_Type = ACTION_WAIT_CHAR;
  706.         if (((WaitTreq *)packet->dp_Res1)->wt_packet) {
  707.         /*  input is available */
  708.         struct IORequest *ior = (struct IORequest *)packet->dp_Res1;
  709.  
  710.         if (!CheckIO(ior))
  711.             AbortIO(ior);
  712.         WaitIO(ior);
  713.         FreeMem((void *)ior, sizeof(WaitTreq));
  714.         packet->dp_Res1 = DOS_TRUE;
  715.         } else {
  716.         /*  timer.device timeout */
  717.  
  718.         /*
  719.          *  we know that node is still in han->ff_RdWait
  720.          *  because TimerPort is checked last
  721.          */
  722.         Remove(&packet->dp_Link->mn_Node);
  723.         /*  no need to try to abort the read request */
  724.         FreeMem((void *)packet->dp_Res1, sizeof(WaitTreq));
  725.         packet->dp_Res1 = DOS_FALSE;
  726.         }
  727.         break;
  728.     case FACTION_SCREEN_MODE:   /*    Mode                Bool:TRUE */
  729.         /*  As ACTION_SCREEN_MODE does not give a filehandle, we get it
  730.          *  indirectly through the special port. Fold packet type for safety.
  731.          */
  732.         packet->dp_Type = ACTION_SCREEN_MODE;
  733.         D(ebug("SCREEN_MODE %ld\n", packet->dp_Arg1));
  734.         {
  735.         /*  special port passed in dp->Res1 */
  736.         FHan *han = (FHan *)(((MsgPort *)packet->dp_Res1)->mp_Node.ln_Name);
  737.  
  738.         if (han->ff_CookBuf == NULL) {    /*  also NULL when !FHF_READ */
  739.             /*  Normally a shell uses cooked mode and programs might
  740.              *  also set cooked mode at exit. Thus if the
  741.              *  application did not open FIFO: in cooked mode, it
  742.              *  had good reasons to do so and we refuse any change.
  743.              *  At least this is good for GNUEmacs (uses "rwesK").
  744.              */
  745.             packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
  746.             break;
  747.         }
  748.  
  749.         packet->dp_Res1 = DOS_TRUE;
  750.         if (DOSFALSE != packet->dp_Arg1) {    /*  RAW */
  751.             if (han->ff_Flags & FHF_COOKED) {
  752.             /*
  753.              *  this differs from CON: which unblocks neither
  754.              *  readers nor writers until the next character is read
  755.              */
  756.             han->ff_Flags &= ~(FHF_COOKED|FHF_STARTCOOK|FHF_WIHOLD|FHF_WISTOP|FHF_COOKECHOBLK /*|FHF_COOKBFUL --still full */);
  757.  
  758.             /*  cooked input is available, unblock readers and timers */
  759.             if (han->ff_CookIdx && (han->ff_Flags & FHF_RPEND)) {
  760.                 D(ebug("Restarting readers\n"));
  761.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  762.                 /* han->ff_Flags |= FHF_RPEND; --already set */
  763.             }
  764.             /*  unblock writers probably in FHF_WIHOLD */
  765.             if ((han->ff_Flags & FHF_WRITE) && !(han->ff_Flags & FHF_WAVAIL)) {
  766.                 RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  767.                 han->ff_Flags |= FHF_WAVAIL;
  768.             }
  769.             }
  770.         } else {    /*    COOKED    */
  771.             if (!(han->ff_Flags & FHF_COOKED)) {
  772.             /*  but ff->CookBuf is NULL if not opened with 'c' flag! */
  773.             han->ff_Flags |= FHF_COOKED|FHF_STARTCOOK;
  774.             /*  cooked processing depends on a read request being active. */
  775.             /*  Since 38.2, cooked processing is only started when
  776.              *  ACTION_READ and ACTION_WAIT_CHAR actually occur, thus
  777.              *  pretyped input is not mangled should the application
  778.              *  switch to raw mode before reading
  779.              *  (like GDB when controlled by dejagnu+expect)
  780.              *
  781.             if ((han->ff_Flags & FHF_READ) && !(han->ff_Flags & FHF_RPEND)) {
  782.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  783.                 han->ff_Flags |= FHF_RPEND;
  784.             }
  785.              */
  786.             }
  787.         }
  788.         }
  789.         break;
  790.     /*  Added for 38.1 */
  791.     case ACTION_CHANGE_SIGNAL:    /*  Filehandle,port|NULL    Bool,port */
  792.         {
  793.         FHan *han = (FHan *)packet->dp_Arg1;
  794.         packet->dp_Res2 = (LONG)han->ff_SigPort;
  795.         D(ebug("Signal Port change %08lx\n", packet->dp_Arg2));
  796.         if (packet->dp_Arg2)
  797.             han->ff_SigPort = (MsgPort *)packet->dp_Arg2;
  798.         returnpacket(packet);    /*  or loose dp_Res1 */
  799.         packet = NULL;
  800.         }
  801.         break;
  802.     /*  Added for 38.1 */
  803.     case ACTION_IS_FILESYSTEM:  /*                    Bool */
  804.         packet->dp_Res1 = DOS_FALSE;
  805.         break;
  806.     /*  Added for 38.1 */
  807.     case ACTION_SEEK:        /*    FHArg1,Position,Mode        OldPosition */
  808.         packet->dp_Res1 = -1;   /*  do not return 0 */
  809.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  810.         returnpacket(packet);    /*  or loose dp_Res1 */
  811.         packet = NULL;
  812.         break;
  813.     default:
  814.         D(ebug("UNKNOWN packet\nArg1 %08lx Arg2 %08lx\n",
  815.            packet->dp_Arg1, packet->dp_Arg2));
  816.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  817.         break;
  818.     }
  819.     if (packet) {
  820.         if (packet->dp_Res2)
  821.         packet->dp_Res1 = DOS_FALSE;
  822.         returnpacket(packet);
  823.     }
  824.     }
  825.     return myexit(RETURN_OK);
  826. }
  827.  
  828. FHan *
  829. OpenHandle(r_name, w_name, han_flags, opn_flags)
  830. char *r_name;    /*  slave name    */
  831. char *w_name;    /*  master name */
  832. long han_flags;
  833. long opn_flags;
  834. {
  835.     FHan *han;
  836.  
  837.     if (NULL == (han = (FHan *)AllocMem(sizeof(FHan) + strlen(r_name) +1,
  838.                     MEMF_CLEAR | MEMF_PUBLIC)))
  839.     return NULL;
  840.     if (!(han_flags & FHF_MASTER)) {
  841.     char *swap = r_name;
  842.     r_name = w_name;
  843.     w_name = swap;
  844.     }
  845.     han->ff_Node.ln_Name = (char *)(han + 1);
  846.     strcpy(han->ff_Node.ln_Name, w_name);
  847.  
  848.     if ((han_flags & FHF_TEE) == 0 && (han_flags & FHF_READ)) {
  849.     FHan *h2;
  850.     for (h2 = (FHan *)HanList.mlh_Head; h2->ff_Node.ln_Succ; h2 = (FHan *)h2->ff_Node.ln_Succ) {
  851.         if (strcmp(h2->ff_Node.ln_Name, han->ff_Node.ln_Name) == 0) {
  852.         if ((h2->ff_Flags & FHF_TEE) == 0 && h2->ff_SRead) {
  853.             han->ff_SRead = h2->ff_SRead;
  854.             ++han->ff_SRead->sr_Refs;
  855.             break;
  856.         }
  857.         }
  858.     }
  859.     }
  860.     AddTail((MaxList *)&HanList, &han->ff_Node);
  861.  
  862.     if ((han_flags & FHF_READ) && han->ff_SRead == NULL) {
  863.     if (NULL == (han->ff_SRead = AllocMem(sizeof(SharRead), MEMF_CLEAR | MEMF_PUBLIC)))
  864.         goto fail;
  865.     han->ff_SRead->sr_Refs    = 1;
  866.     if (NULL == (han->ff_SRead->sr_FifoR = OpenFifo(r_name, FIFO_SIZE, opn_flags | FIFOF_READ)))
  867.         goto fail;
  868.     }
  869.     if (han_flags & FHF_WRITE) {
  870.     if (NULL == (han->ff_FifoW = OpenFifo(w_name, FIFO_SIZE, opn_flags | FIFOF_WRITE)))
  871.         goto fail;
  872.     han->ff_FHBufSiz = (BufSizeFifo(han->ff_FifoW) >> 1) -1;
  873.     }
  874.     if (han_flags & FHF_SHELL) {
  875.     if (NULL == (han->ff_Port = SpecPort(han)))
  876.         goto fail;
  877.     }
  878.  
  879.     han->ff_Flags = han_flags;
  880.     han->ff_Refs = 1;
  881.     han->ff_RdMsg.mn_ReplyPort = IoSink;
  882.     han->ff_RdMsg.mn_Node.ln_Name = (char *)han;
  883.     han->ff_WrMsg.mn_ReplyPort = IoSink;
  884.     han->ff_WrMsg.mn_Node.ln_Name = (char *)han;
  885.     NewList((MaxList *)&han->ff_RdWait);
  886.     NewList((MaxList *)&han->ff_WrWait);
  887.  
  888.     if (han_flags & FHF_COOKED) {
  889.     /*  allocation need not be public, fifo-handler use only */
  890.     if (NULL == (han->ff_CookBuf = AllocMem(CB_SIZE, MEMF_CLEAR)))
  891.         goto fail;
  892.     han->ff_CookLen1 = -1;
  893.     /*  lookahead for efficiency */
  894.     /*  Don't start cooked processing, application may switch to raw mode
  895.      *
  896.     RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  897.     han->ff_Flags |= FHF_RPEND;
  898.      */
  899.     }
  900.     return han;
  901.  
  902.     fail:
  903.     CloseHandle(han);
  904.     return NULL;
  905. }
  906.  
  907. void
  908. CloseHandle(han)
  909. FHan *han;
  910. {
  911.     /*  zero fields to protect against buggy programs */
  912.     Remove(&han->ff_Node);
  913.     if (han->ff_SRead) {
  914.     if (--han->ff_SRead->sr_Refs == 0) {
  915.         if (han->ff_FifoR) {
  916.         CloseFifo(han->ff_FifoR, 0);
  917.         /* han->ff_FifoR = NULL; */
  918.         }
  919.         FreeMem(han->ff_SRead, sizeof(SharRead));
  920.     }
  921.     han->ff_SRead = NULL;
  922.     }
  923.     if (han->ff_FifoW) {
  924.     CloseFifo(han->ff_FifoW, (han->ff_Flags & FHF_CLOSEEOF) ? FIFOF_EOF : 0);
  925.     han->ff_FifoW = NULL;
  926.     }
  927.     if (han->ff_Port) {
  928.     FreeMem(han->ff_Port, sizeof(MsgPort) + sizeof(Interrupt));
  929.     han->ff_Port = NULL;
  930.     }
  931.     if (han->ff_CookBuf) {
  932.     FreeMem(han->ff_CookBuf, CB_SIZE);
  933.     han->ff_CookBuf = NULL;
  934.     }
  935.     FreeMem(han, sizeof(FHan) + strlen(han->ff_Node.ln_Name) + 1);
  936. }
  937.  
  938.  
  939. /*
  940.  *  handle cooked data by actually reading it from the fifo, echoing it
  941.  *  to the return channel (if it exists), and processing it.  If a <CR>
  942.  *  is processed, handle any
  943.  */
  944.  
  945. void
  946. HandleRequestMsg(Message *msg)
  947. {
  948.     FHan *han = (FHan *)msg->mn_Node.ln_Name;
  949.  
  950.     if (msg == &han->ff_WrMsg) {
  951.     han->ff_Flags &= ~FHF_WAVAIL;
  952.     while ((msg = (Message *)RemHead((MaxList *)&han->ff_WrWait))) /*  retry operation */
  953.         PutMsg(PktPort, msg);
  954.  
  955.     /*
  956.      *  if we were blocked trying to echo, then read data pending,
  957.      *  make sure read-request is queued and will be retried.
  958.      */
  959.  
  960.     if (han->ff_Flags & FHF_COOKECHOBLK) {
  961.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  962.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  963.         han->ff_Flags |= FHF_RPEND;
  964.         }
  965.         han->ff_Flags &= ~FHF_COOKECHOBLK;
  966.     }
  967.     } else if (msg == &han->ff_RdMsg) {
  968.     han->ff_Flags &= ~FHF_RPEND;
  969.     if (han->ff_Flags & FHF_COOKED) {
  970.         long n;
  971.         long i;
  972.         short rwakeup = 0;
  973.         short eof = 0;
  974.         char *ptr;
  975.  
  976.         n = ReadFifo(han->ff_FifoR, &ptr, 0);
  977.  
  978.         if (n < 0) {
  979.         han->ff_Flags |= FHF_REOF;
  980.         rwakeup = 1;
  981.         }
  982.  
  983.         for (i = 0; i < n; ++i) {
  984.         switch(ptr[i]) {
  985.         case 28:    /*  28 is ctrl-\ is EOF */
  986.             eof = 1;
  987.             /*  special marker. Fall through to save some code */
  988.         case 13:
  989.         case 10:
  990.             if (han->ff_CookIdx >= CB_SIZE - 1) {
  991.             han->ff_Flags |= FHF_COOKBFUL;
  992.             n = --i;
  993.             break;
  994.             }
  995.             if (han->ff_FifoW) {
  996.             if (WriteFifo(han->ff_FifoW, "\r\n", 2) != 2) {
  997.                 han->ff_Flags |= FHF_COOKECHOBLK;
  998.                 n = --i;
  999.                 break;
  1000.             }
  1001.             }
  1002.             han->ff_CookBuf[han->ff_CookIdx++] = (eof ? CHAR_EOF : '\n');
  1003.             if (0 > han->ff_CookLen1) {
  1004.             /*  first line is ready, include \n but don't count EOF */
  1005.             han->ff_CookLen1 = han->ff_CookIdx - eof;
  1006.             }
  1007.             han->ff_Flags &= ~FHF_WISTOP;
  1008.             eof = 0;
  1009.             rwakeup = 1;
  1010.             break;
  1011.         case 8:
  1012.             if (han->ff_CookIdx
  1013.               && han->ff_CookBuf[han->ff_CookIdx-1] != '\n'
  1014.               && han->ff_CookBuf[han->ff_CookIdx-1] != CHAR_EOF) {
  1015.             if (han->ff_FifoW) {
  1016.                 if (WriteFifo(han->ff_FifoW, "\010 \010", 3) != 3) {
  1017.                 han->ff_Flags |= FHF_COOKECHOBLK;
  1018.                 n = --i;
  1019.                 break;
  1020.                 }
  1021.             }
  1022.             --han->ff_CookIdx;
  1023.             if (han->ff_CookIdx==0
  1024.               || han->ff_CookBuf[han->ff_CookIdx-1] == '\n'
  1025.               || han->ff_CookBuf[han->ff_CookIdx-1] == CHAR_EOF)
  1026.                 han->ff_Flags &= ~FHF_WISTOP;
  1027.             }
  1028.             break;
  1029. #if 0
  1030.         case 26:    /*  test signals */
  1031.             SigHandles(han->ff_Node.ln_Name, SIGBREAKF_CTRL_C);
  1032.             break;
  1033. #endif
  1034. #if SIGBREAKB_CTRL_F - SIGBREAKB_CTRL_C == 3
  1035.         case 3: case 4: case 5: case 6:
  1036.             SigHandles(han->ff_Node.ln_Name, 1L<<(ptr[i]-3+SIGBREAKB_CTRL_C));
  1037.             break;
  1038. #else
  1039.         /*  who says the above is not portable? */
  1040.         case 3:
  1041.             SigHandles(han->ff_Node.ln_Name, SIGBREAKF_CTRL_C);
  1042.             break;
  1043.         case 4:
  1044.             SigHandles(han->ff_Node.ln_Name, SIGBREAKF_CTRL_D);
  1045.             break;
  1046.         case 5:
  1047.             SigHandles(han->ff_Node.ln_Name, SIGBREAKF_CTRL_E);
  1048.             break;
  1049.         case 6:
  1050.             SigHandles(han->ff_Node.ln_Name, SIGBREAKF_CTRL_F);
  1051.             break;
  1052. #endif
  1053.         default:
  1054.             if (han->ff_CookIdx >= CB_SIZE - 1) {
  1055.             han->ff_Flags |= FHF_COOKBFUL;
  1056.             n = --i;
  1057.             break;
  1058.             }
  1059.             if (han->ff_FifoW) {
  1060.             if (WriteFifo(han->ff_FifoW, ptr + i, 1) != 1) {
  1061.                 han->ff_Flags |= FHF_COOKECHOBLK;
  1062.                 n = --i;
  1063.                 break;
  1064.             }
  1065.             }
  1066.             han->ff_CookBuf[han->ff_CookIdx++] = ptr[i];
  1067.             han->ff_Flags |= FHF_WISTOP;
  1068.             break;
  1069.         }
  1070.         }
  1071.  
  1072.         /*
  1073.          *    if output was held due to cooked input pending, and the
  1074.          *    case is no longer true, then restart output
  1075.          */
  1076.  
  1077.         if ((han->ff_Flags & FHF_WIHOLD) && !(han->ff_Flags & FHF_WISTOP)) {
  1078.         han->ff_Flags &= ~FHF_WIHOLD;
  1079.         while ((msg = (Message *)RemHead((MaxList *)&han->ff_WrWait)))
  1080.             PutMsg(PktPort, msg);
  1081.         }
  1082.  
  1083.         if (i > 0) {
  1084.         if (ReadFifo(han->ff_FifoR, &ptr, i) < 0) {
  1085.             han->ff_Flags |= FHF_REOF;
  1086.             rwakeup = 1;
  1087.         }
  1088.         }
  1089.         if (n >= 0 && !(han->ff_Flags & (FHF_COOKECHOBLK|FHF_COOKBFUL|FHF_REOF))) {
  1090.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  1091.         han->ff_Flags |= FHF_RPEND;
  1092.         }
  1093.         if (!rwakeup)
  1094.         return;
  1095.     }
  1096.     while ((msg = (Message *)RemHead((MaxList *)&han->ff_RdWait))) /*  retry operation */
  1097.         PutMsg(PktPort, msg);
  1098.     }
  1099. }
  1100.  
  1101. void
  1102. WaitMsg(Message *msg)
  1103. {
  1104.     while (msg->mn_Node.ln_Type == NT_MESSAGE)
  1105.     Wait(1 << msg->mn_ReplyPort->mp_SigBit);
  1106.     Forbid();
  1107.     Remove(&msg->mn_Node);
  1108.     Permit();
  1109. }
  1110.  
  1111. void
  1112. SigHandles(char *name, unsigned long sigs)
  1113. {
  1114.     FHan *han;
  1115.  
  1116.     for (han = (FHan *)HanList.mlh_Head; han->ff_Node.ln_Succ; han = (FHan *)han->ff_Node.ln_Succ) {
  1117.     if (strcmp(han->ff_Node.ln_Name, name) == 0) {
  1118.         MsgPort *mp = han->ff_SigPort;
  1119.         D(ebug("Maybe signal port %08lx %s\n", mp, name));
  1120.         if ((mp->mp_Flags & PF_ACTION) == PA_SIGNAL)
  1121.         Signal(mp->mp_SigTask, sigs);
  1122.     }
  1123.     }
  1124. }
  1125.  
  1126.  
  1127. /*
  1128.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  1129.  *  can see by this and how the PACKET structure is extracted in the
  1130.  *  GetMsg() of the main routine.
  1131.  */
  1132.  
  1133. void
  1134. returnpacket(DosPacket *packet)
  1135. {
  1136.     MsgPort *replyPort         = packet->dp_Port;
  1137.     Message *mess         = packet->dp_Link;
  1138.     packet->dp_Port         = PktPort;    /*  not possibly special port? */
  1139.     mess->mn_Node.ln_Name    = (char *)packet;
  1140.     D(ebug("Return type=%ld, res1=%ld, res2=%ld\n", packet->dp_Type, packet->dp_Res1, packet->dp_Res2));
  1141.     PutMsg(replyPort, mess);
  1142. }
  1143.  
  1144. void
  1145. Initialize(void)
  1146. {
  1147. #ifndef CLI_START
  1148.     Process *proc = FindTask(NULL);
  1149.     DosPacket *packet;
  1150. #endif
  1151.  
  1152.     /*
  1153.      *    Initialize port
  1154.      */
  1155.     {
  1156.     IoSink = CreatePort("FIFO-PORT", -10);
  1157.     FreeSignal(IoSink->mp_SigBit);
  1158.     IoSink->mp_SigBit = SIGBREAKB_CTRL_F; /*  why? (jch) */
  1159.     }
  1160.     PktPort = CreatePort(NULL, 0);
  1161.     TimerPort = CreatePort(NULL, 0);
  1162.     TimerIO = (WaitTreq *) CreateExtIO(TimerPort, sizeof(WaitTreq));
  1163.     OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0);
  1164.     TimerIO->wt_timereq.tr_node.io_Command = TR_ADDREQUEST;
  1165.     PortsMask = (1 << PktPort->mp_SigBit) | (1 << TimerPort->mp_SigBit);
  1166.  
  1167. #ifdef CLI_START
  1168.  
  1169.     /*
  1170.      *    create DOS node
  1171.      */
  1172.  
  1173.     MkDevice("FIFO");
  1174.  
  1175.     FifoBase = OpenLibrary(FIFONAME, 0);
  1176.  
  1177. #else
  1178.  
  1179.     /*
  1180.      *    Handle initial message.     We pull the message off the port before
  1181.      *    calling OpenLibrary() so if OpenLibrary() makes a DOS call it
  1182.      *    doesn't crash the machine (due to an unexpected packet).  This
  1183.      *    will happen if the library needs to be loaded.    There is no other
  1184.      *    safe time to do this.
  1185.      */
  1186.  
  1187.     {
  1188.     Message *msg;
  1189.  
  1190.     WaitPort(&proc->pr_MsgPort);
  1191.     msg = GetMsg(&proc->pr_MsgPort);
  1192.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1193.     }
  1194.  
  1195.     /*
  1196.      *    Fifo Library
  1197.      */
  1198.  
  1199.     FifoBase = OpenLibrary(FIFONAME, 0);
  1200.  
  1201.     {
  1202.     DeviceNode *dn;
  1203.     DevNode = dn = BTOC(packet->dp_Arg3);
  1204.  
  1205.     dn->dn_Task = PktPort;
  1206.     packet->dp_Res1 = (FifoBase) ? DOS_TRUE : DOS_FALSE;
  1207.     packet->dp_Res2 = 0;
  1208.     returnpacket(packet);
  1209.     }
  1210.  
  1211. #endif
  1212. }
  1213.  
  1214.  
  1215. int
  1216. myexit(int code)
  1217. {
  1218. #ifdef CLI_START
  1219.     DelDevice();
  1220. #else
  1221.  
  1222.     /*
  1223.      *    Device Node
  1224.      */
  1225.  
  1226.     {
  1227.     DeviceNode *dn = DevNode;
  1228.  
  1229.     dn->dn_Task = NULL;
  1230.     dn->dn_SegList = NULL;
  1231.     }
  1232. #endif
  1233.  
  1234.     /*
  1235.      *    delete ports
  1236.      */
  1237.  
  1238.     CloseDevice((struct IORequest *) TimerIO);
  1239.     DeleteExtIO((struct IORequest *) TimerIO);
  1240.     DeletePort(TimerPort);
  1241.  
  1242.     if (PktPort)
  1243.     DeletePort(PktPort);
  1244.  
  1245.     if (IoSink) {
  1246.     IoSink->mp_SigBit = AllocSignal(-1);
  1247.     DeletePort(IoSink);
  1248.     }
  1249.  
  1250. #ifdef DEBUG
  1251.     if (DBFifo) {
  1252.     CloseFifo(DBFifo, FIFOF_EOF);
  1253.     }
  1254. #endif
  1255.     if (FifoBase) {
  1256.     CloseLibrary(FifoBase);
  1257.     /* FifoBase = NULL; */
  1258.     }
  1259.     _exit(code);        /*  some startups always return 0 from main */
  1260.     return code;
  1261. }
  1262.  
  1263.  
  1264. MsgPort *
  1265. SpecPort(FHan *han)
  1266. {
  1267.     MsgPort *port = AllocMem(sizeof(MsgPort) + sizeof(Interrupt), MEMF_CLEAR | MEMF_PUBLIC);
  1268.     Interrupt *xint = (Interrupt *)(port + 1);
  1269.     extern void AIntCode();
  1270.     if (NULL == port) return NULL;
  1271.  
  1272.     NewList(&port->mp_MsgList);
  1273.     port->mp_Node.ln_Name = (char *)han; /*  ln_name holds local data */
  1274.     port->mp_Node.ln_Type = NT_MSGPORT;
  1275.     port->mp_Flags = PA_SOFTINT;
  1276.     port->mp_SigTask = (void *)xint;
  1277.     xint->is_Node.ln_Type = NT_INTERRUPT;
  1278.     xint->is_Node.ln_Pri  = -32;
  1279.     xint->is_Data = (APTR)port;
  1280.     xint->is_Code = AIntCode;
  1281.     return(port);
  1282. }
  1283.  
  1284. #if !defined(__GNUC__)
  1285. __geta4 __stkargs
  1286. #endif
  1287. void
  1288. IntCode(port)
  1289. MsgPort *port;
  1290. {
  1291.     Message *msg;
  1292.     DosPacket *packet;
  1293.     FileHandle *fh;
  1294.  
  1295.     while ((msg = GetMsg(port))) {
  1296.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1297.     D(ebug("Port %08lx, type %ld\n", port, packet->dp_Type));
  1298.  
  1299.     switch(packet->dp_Type) {
  1300.     case ACTION_FINDUPDATE:
  1301.     case ACTION_FINDINPUT:
  1302.     case ACTION_FINDOUTPUT:
  1303.         fh = BTOC(packet->dp_Arg1);
  1304.         fh->fh_Port = port;    /*  temporary storage */
  1305.         break;
  1306.     case ACTION_SCREEN_MODE:
  1307.         packet->dp_Type = FACTION_SCREEN_MODE;
  1308.         packet->dp_Res1 = (LONG)port; /*  we are not allowed to change dp->Arg2 */
  1309.         break;
  1310.     case ACTION_WAIT_CHAR:
  1311.         packet->dp_Type = FACTION_WAIT_CHAR;
  1312.         packet->dp_Res1 = (LONG)port; /*  we are not allowed to change dp->Arg2 */
  1313.         break;
  1314.     }
  1315.     PutMsg(PktPort, msg);
  1316.     }
  1317. }
  1318.  
  1319.  
  1320. #ifdef CLI_START
  1321.  
  1322. /*
  1323.  *  DEVICE CREATION AND DELETION
  1324.  */
  1325.  
  1326. static inline
  1327. void *
  1328. DosAllocMem(bytes)
  1329. long bytes;
  1330. {
  1331.     long *ptr;
  1332.  
  1333.     bytes += 4;
  1334.  
  1335.     if ((ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR))) {
  1336.     *ptr++ = bytes;
  1337.     return((void *)ptr);
  1338.     }
  1339.     Alert(AG_NoMemory|AT_DeadEnd);
  1340.     return NULL;        /*  NOTREACHED */
  1341. }
  1342.  
  1343. static inline
  1344. void
  1345. DosFree(void *vptr)
  1346. {
  1347.     long *ptr = vptr;
  1348.     --ptr;
  1349.     FreeMem(ptr, *ptr);
  1350. }
  1351.  
  1352. DosList *Dl;
  1353.  
  1354. void
  1355. MkDevice(char *devName)
  1356. {
  1357.     DosList *dl;
  1358.     RootNode *root;
  1359.     DosInfo *info;
  1360.  
  1361.     Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
  1362.     strcpy((char *)(dl+1) + 1, devName);
  1363.     *(char *)(dl + 1) = strlen(devName);
  1364.     dl->dol_Type = DLT_DEVICE;
  1365.     dl->dol_Task = PktPort;
  1366.     dl->dol_Name = MKBADDR((char *)(dl+1));
  1367.  
  1368.     Forbid();
  1369.     root  = (struct RootNode *)DOSBase->dl_Root;
  1370.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1371.     dl->dol_Next = info->di_DevInfo;
  1372.     info->di_DevInfo = MKBADDR(dl);
  1373.     Permit();
  1374. }
  1375.  
  1376. void
  1377. DelDevice(void)
  1378. {
  1379.     DosList *dl;
  1380.     DosInfo *info;
  1381.     RootNode *root;
  1382.     DosList *dls;
  1383.     BPTR    *bpp;
  1384.  
  1385.     if ((dl = Dl)) {
  1386.     Forbid();
  1387.     root  = (struct RootNode *)DOSBase->dl_Root;
  1388.     info  = (struct DosInfo     *)BADDR(root->rn_Info);
  1389.  
  1390.     for (bpp = &info->di_DevInfo; (dls = BADDR(*bpp)); bpp = &dls->dol_Next) {
  1391.         if (dls == dl)
  1392.         break;
  1393.     }
  1394.     if (dls == dl) {
  1395.         *bpp = dls->dol_Next;
  1396.     } else {
  1397.         Alert(0x07AAAAAA|AT_Recovery);
  1398.     }
  1399.     Permit();
  1400.     DosFree(dl);
  1401.     Dl = NULL;
  1402.     }
  1403. }
  1404.  
  1405. #endif
  1406.  
  1407. WaitTreq *
  1408. AllocTimerequest(unsigned long timeout)
  1409. {
  1410.   struct WaitTreq *tr = (struct WaitTreq *)AllocMem(sizeof(WaitTreq), MEMF_PUBLIC);
  1411.  
  1412.   if (NULL != tr) {
  1413.       memmove(tr, TimerIO, sizeof(tr->wt_timereq));
  1414.       tr->wt_timereq.tr_time.tv_secs = 0;
  1415.       if (timeout < 10 && SysBase->LibNode.lib_Version < 36)
  1416.       timeout = 10; /*  work around bug in <2.0 timer.device */
  1417.       while (timeout >= 1000000) {
  1418.       tr->wt_timereq.tr_time.tv_secs++;
  1419.       timeout -= 1000000;
  1420.       }
  1421.       tr->wt_timereq.tr_time.tv_micro = timeout;
  1422.   }
  1423.   return tr;
  1424. }
  1425.