home *** CD-ROM | disk | FTP | other *** search
/ Creative Computers / CreativeComputers.iso / shareware / telecom / term_4.1 / extras / hydracom / hydracom-source.lha / amiga.c < prev    next >
C/C++ Source or Header  |  1994-07-02  |  42KB  |  1,865 lines

  1. /*
  2. **    Amiga support module for HYDRA protocol sample implementation.
  3. **
  4. **    Written by    Olaf Barthel
  5. **            Brabeckstrasse 35
  6. **            D-30559 Hannover
  7. **
  8. **            eMail: olsen@sourcery.han.de
  9. **
  10. **    Freely distributable.
  11. */
  12.  
  13.     /* System includes. */
  14.  
  15. #include <intuition/intuitionbase.h>
  16.  
  17. #include <libraries/gadtools.h>
  18.  
  19. #include <graphics/gfxbase.h>
  20.  
  21. #include <utility/date.h>
  22.  
  23. #include <devices/conunit.h>
  24. #include <devices/serial.h>
  25. #include <devices/timer.h>
  26.  
  27. #include <hardware/cia.h>
  28.  
  29. #include <dos/dosextens.h>
  30. #include <dos/filehandler.h>
  31. #include <dos/dosasl.h>
  32.  
  33. #include <exec/memory.h>
  34.  
  35.     /* Correct a nasty bug in the prototypes. */
  36.  
  37. #define CheckIO foo21234
  38.  
  39. #include <clib/intuition_protos.h>
  40. #include <clib/gadtools_protos.h>
  41. #include <clib/graphics_protos.h>
  42. #include <clib/utility_protos.h>
  43. #include <clib/timer_protos.h>
  44. #include <clib/exec_protos.h>
  45. #include <clib/dos_protos.h>
  46. #include <clib/macros.h>
  47.  
  48.     /* Get the CheckIO prototype right. */
  49.  
  50. #undef CheckIO
  51.  
  52. struct IORequest *CheckIO(struct IORequest *);
  53.  
  54. #include "Rendezvous.h"
  55.  
  56. #include "hydracom.h"
  57.  
  58.     /* Serial buffer size. */
  59.  
  60. #define BUFFER_SIZE 8192
  61.  
  62.     /* A handy macro. */
  63.  
  64. #define ClrSignal(s)    SetSignal(0,s)
  65.  
  66.     /* Signal masks. */
  67.  
  68. #define SIG_SERREAD    (1UL << ReadPort -> mp_SigBit)
  69. #define SIG_SERWRITE    (1UL << WritePort -> mp_SigBit)
  70. #define SIG_CONREAD    (1UL << ConsoleReadPort -> mp_SigBit)
  71. #define SIG_TIMER    (1UL << TimePort -> mp_SigBit)
  72. #define SIG_WINDOW    (1UL << LocalWindow -> UserPort -> mp_SigBit)
  73.  
  74.     /* A serial buffer structure. */
  75.  
  76. struct SerialBuffer
  77. {
  78.     struct IOExtSer    *SerialRequest;
  79.     UBYTE        *SerialBuffer,
  80.             *SerialIndex,
  81.             *SerialTop;
  82.     LONG         SerialSize,
  83.              SerialFilled;
  84.     BOOL         IsClone,
  85.              IsBusy;
  86. };
  87.  
  88. STATIC struct RendezvousData        *RendezvousData;
  89. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  90.  
  91.     /* Library bases. */
  92.  
  93. struct IntuitionBase    *IntuitionBase;
  94. struct GfxBase        *GfxBase;
  95. struct Library        *GadToolsBase,
  96.             *UtilityBase,
  97.             *TimerBase;
  98.  
  99.     /* Timer data. */
  100.  
  101. struct MsgPort        *TimePort;
  102. struct timerequest    *TimeRequest;
  103.  
  104.     /* Serial data. */
  105.  
  106. struct MsgPort        *ReadPort,
  107.             *WritePort;
  108.  
  109. struct SerialBuffer    *ThisBuffer,
  110.             *NextBuffer,
  111.             *ReadBuffer;
  112.  
  113.     /* Console data. */
  114.  
  115. struct Window        *FileWindow,
  116.             *RemoteWindow,
  117.             *LocalWindow,
  118.             *LogWindow;
  119.  
  120. struct MsgPort        *ConsoleWritePort,
  121.             *ConsoleReadPort;
  122. struct IOStdReq        *ConsoleReadRequest;
  123. UBYTE             ConsoleChar;
  124. BOOL             ConsoleReady = FALSE,
  125.              WindowReady = FALSE;
  126.  
  127. struct IOStdReq        *FileRequest,
  128.             *RemoteRequest,
  129.             *LocalRequest,
  130.             *LogRequest;
  131.  
  132.     /* DOS Data. */
  133.  
  134. struct Process        *ThisProcess;
  135. APTR             OldPtr;
  136.  
  137. struct AnchorPath    *Anchor;
  138. BOOL             AnchorUsed = FALSE;
  139.  
  140.     /* Screen data. */
  141.  
  142. struct Screen        *PublicScreen,
  143.             *Screen;
  144.  
  145.     /* Menu data. */
  146.  
  147. APTR             VisualInfo;
  148. struct Menu        *Menu;
  149.  
  150. struct NewMenu MenuTemplate[] =
  151. {
  152.     { NM_TITLE, "Project",             0 ,    0,    0,    (APTR)0},
  153.     {  NM_ITEM, "Toggle chat",        "C",    0,    0,    (APTR)Alt_C},
  154.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  155.     {  NM_ITEM, "Hang up",            "H",    0,    0,    (APTR)Alt_H},
  156.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  157.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  158.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  159.     {  NM_ITEM, "Start upload",        "U",    0,    0,    (APTR)PgUp},
  160.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  161.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  162.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  163.     { NM_END,   0,                 0 ,    0,    0,    (APTR)0}
  164. };
  165.  
  166.     /* OpenConsole():
  167.      *
  168.      *    Open a console window.
  169.      */
  170.  
  171. STATIC BOOL __inline
  172. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  173. {
  174.     struct Window *Window;
  175.  
  176.     if(Window = OpenWindowTags(NULL,
  177.         WA_Left,        0,
  178.         WA_Top,            Top,
  179.         WA_Width,        Screen -> Width,
  180.         WA_Height,        Height,
  181.         WA_Title,        Title,
  182.         WA_SimpleRefresh,    TRUE,
  183.         WA_DepthGadget,        TRUE,
  184.         WA_DragBar,        TRUE,
  185.         WA_SizeGadget,        Resize,
  186.         WA_SizeBRight,        TRUE,
  187.         WA_CustomScreen,    Screen,
  188.         WA_RMBTrap,        TRUE,
  189.         WA_NewLookMenus,    TRUE,
  190.     TAG_DONE))
  191.     {
  192.         struct IOStdReq *ConsoleRequest;
  193.  
  194.         if(Window -> RPort -> Font -> tf_Flags & FPF_PROPORTIONAL)
  195.             SetFont(Window -> RPort,GfxBase -> DefaultFont);
  196.  
  197.         if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  198.         {
  199.             ConsoleRequest -> io_Data = Window;
  200.  
  201.             if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  202.             {
  203.                 WindowLimits(Window,Window -> BorderLeft + 10 * Window -> RPort -> Font -> tf_XSize * 10 + Window -> BorderRight,Window -> BorderTop + 2 * Window -> RPort -> Font -> tf_YSize + Window -> BorderBottom,Screen -> Width,Screen -> Height);
  204.  
  205.                     /* Turn off the cursor. */
  206.  
  207.                 ConPrintf(ConsoleRequest,"\033[0 p");
  208.  
  209.                 *WindowPtr    = Window;
  210.                 *ConsolePtr    = ConsoleRequest;
  211.  
  212.                 return(TRUE);
  213.             }
  214.  
  215.             DeleteIORequest(ConsoleRequest);
  216.         }
  217.  
  218.         CloseWindow(Window);
  219.     }
  220.  
  221.     return(FALSE);
  222. }
  223.  
  224.     /* CloseConsole():
  225.      *
  226.      *    Close a console window.
  227.      */
  228.  
  229. STATIC VOID __inline
  230. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  231. {
  232.     if(*ConsolePtr)
  233.     {
  234.         CloseDevice(*ConsolePtr);
  235.  
  236.         DeleteIORequest(*ConsolePtr);
  237.  
  238.         *ConsolePtr = NULL;
  239.     }
  240.  
  241.     if(*WindowPtr)
  242.     {
  243.         CloseWindow(*WindowPtr);
  244.  
  245.         *WindowPtr = NULL;
  246.     }
  247. }
  248.  
  249.     /* CloneSerialBuffer():
  250.      *
  251.      *    Clone a SerialBuffer structure.
  252.      */
  253.  
  254. STATIC struct SerialBuffer * __regargs
  255. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  256. {
  257.     struct SerialBuffer *Buffer;
  258.  
  259.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source -> SerialSize,MEMF_ANY | MEMF_PUBLIC))
  260.     {
  261.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  262.         Buffer -> SerialFilled    = 0;
  263.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Source -> SerialSize;
  264.         Buffer -> SerialSize    = Source -> SerialSize;
  265.         Buffer -> IsClone    = TRUE;
  266.         Buffer -> IsBusy    = FALSE;
  267.  
  268.         if(Buffer -> SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  269.         {
  270.             CopyMem(Source -> SerialRequest,Buffer -> SerialRequest,sizeof(struct IOExtSer));
  271.  
  272.             Buffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = MsgPort;
  273.  
  274.             return(Buffer);
  275.         }
  276.         else
  277.             cprint("Could not create serial request\n");
  278.  
  279.         FreeVec(Buffer);
  280.     }
  281.     else
  282.         cprint("Could not create serial buffer\n");
  283.  
  284.     return(NULL);
  285. }
  286.  
  287.     /* DeleteSerialBuffer():
  288.      *
  289.      *    Delete a SerialBuffer structure.
  290.      */
  291.  
  292. STATIC VOID __regargs
  293. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  294. {
  295.     if(Buffer)
  296.     {
  297.         if(Buffer -> IsBusy)
  298.         {
  299.             if(!CheckIO(Buffer -> SerialRequest))
  300.                 AbortIO(Buffer -> SerialRequest);
  301.  
  302.             WaitIO(Buffer -> SerialRequest);
  303.         }
  304.  
  305.         if(Buffer -> IsClone)
  306.             FreeVec(Buffer -> SerialRequest);
  307.         else
  308.         {
  309.             CloseDevice(Buffer -> SerialRequest);
  310.  
  311.             DeleteIORequest(Buffer -> SerialRequest);
  312.         }
  313.  
  314.         FreeVec(Buffer);
  315.     }
  316. }
  317.  
  318.     /* CreateSerialBuffer():
  319.      *
  320.      *    Create a serial buffer structure.
  321.      */
  322.  
  323. STATIC struct SerialBuffer * __regargs
  324. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  325. {
  326.     struct SerialBuffer *Buffer;
  327.  
  328.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  329.     {
  330.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  331.         Buffer -> SerialFilled    = 0;
  332.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Size;
  333.         Buffer -> SerialSize    = Size;
  334.         Buffer -> IsClone    = FALSE;
  335.         Buffer -> IsBusy    = FALSE;
  336.  
  337.         if(Buffer -> SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  338.         {
  339.             if(!OpenDevice(Device,Unit,Buffer -> SerialRequest,NULL))
  340.                 return(Buffer);
  341.             else
  342.             {
  343.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  344.  
  345.                 DeleteIORequest(Buffer -> SerialRequest);
  346.             }
  347.         }
  348.         else
  349.             cprint("Could not create serial request\n");
  350.  
  351.         FreeVec(Buffer);
  352.     }
  353.     else
  354.         cprint("Could not create serial buffer\n");
  355.  
  356.     return(NULL);
  357. }
  358.  
  359.     /* OpenAll():
  360.      *
  361.      *    Allocate all the resources required.
  362.      */
  363.  
  364. STATIC BOOL
  365. OpenAll(STRPTR Device,LONG Unit)
  366. {
  367.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  368.     UWORD Pens = (UWORD)~0;
  369.  
  370.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  371.     {
  372.         cprint("Could not open intuition.library v37\n");
  373.  
  374.         return(FALSE);
  375.     }
  376.  
  377.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  378.     {
  379.         cprint("Could not open graphics.library v37\n");
  380.  
  381.         return(FALSE);
  382.     }
  383.  
  384.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  385.     {
  386.         cprint("Could not open gadtools.library v37\n");
  387.  
  388.         return(FALSE);
  389.     }
  390.  
  391.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  392.     {
  393.         cprint("Could not open utility.library v37\n");
  394.  
  395.         return(FALSE);
  396.     }
  397.  
  398.     if(!(TimePort = CreateMsgPort()))
  399.     {
  400.         cprint("Could not create timer port\n");
  401.  
  402.         return(FALSE);
  403.     }
  404.  
  405.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  406.     {
  407.         cprint("Could not create timer request\n");
  408.  
  409.         return(FALSE);
  410.     }
  411.  
  412.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  413.     {
  414.         cprint("Could not open timer\n");
  415.  
  416.         return(FALSE);
  417.     }
  418.  
  419.     TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  420.  
  421.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  422.     {
  423.         cprint("Could not allocate pattern matching buffe\n");
  424.  
  425.         return(FALSE);
  426.     }
  427.  
  428.     Anchor -> ap_Strlen = 512;
  429.  
  430.     if(!(ReadPort = CreateMsgPort()))
  431.     {
  432.         cprint("Could not create serial read port\n");
  433.  
  434.         return(FALSE);
  435.     }
  436.  
  437.     if(!(WritePort = CreateMsgPort()))
  438.     {
  439.         cprint("Could not create serial write port\n");
  440.  
  441.         return(FALSE);
  442.     }
  443.  
  444.     Forbid();
  445.  
  446.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  447.     {
  448.         ObtainSemaphore(RendezvousSemaphore);
  449.  
  450.         if(!(RendezvousData = (*RendezvousSemaphore -> rs_Login)(ReadPort,WritePort,NULL)))
  451.         {
  452.             Permit();
  453.  
  454.             ReleaseSemaphore(RendezvousSemaphore);
  455.  
  456.             RendezvousSemaphore = NULL;
  457.  
  458.             cprint("Could not link to `term'\n");
  459.  
  460.             return(FALSE);
  461.         }
  462.     }
  463.  
  464.     Permit();
  465.  
  466.     if(!(ConsoleReadPort = CreateMsgPort()))
  467.     {
  468.         cprint("Could not create console read port\n");
  469.  
  470.         return(FALSE);
  471.     }
  472.  
  473.     if(!(ConsoleWritePort = CreateMsgPort()))
  474.     {
  475.         cprint("Could not create console write port\n");
  476.  
  477.         return(FALSE);
  478.     }
  479.  
  480.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  481.     {
  482.         cprint("Could not create console read request\n");
  483.  
  484.         return(FALSE);
  485.     }
  486.  
  487.     if(!RendezvousData)
  488.     {
  489.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  490.             return(FALSE);
  491.     }
  492.     else
  493.     {
  494.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  495.         {
  496.             ReadBuffer -> SerialBuffer    = ReadBuffer -> SerialIndex = (UBYTE *)(ReadBuffer + 1);
  497.             ReadBuffer -> SerialFilled    = 0;
  498.             ReadBuffer -> SerialTop        = ReadBuffer -> SerialBuffer + BUFFER_SIZE;
  499.             ReadBuffer -> SerialSize    = BUFFER_SIZE;
  500.             ReadBuffer -> IsClone        = TRUE;
  501.             ReadBuffer -> IsBusy        = FALSE;
  502.             ReadBuffer -> SerialRequest    = &RendezvousData -> rd_ReadRequest;
  503.         }
  504.         else
  505.         {
  506.             cprint("Could not create serial ReadBuffer\n");
  507.  
  508.             return(FALSE);
  509.         }
  510.     }
  511.  
  512.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  513.         return(FALSE);
  514.  
  515.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  516.         return(FALSE);
  517.  
  518.     if(!(PublicScreen = LockPubScreen(NULL)))
  519.     {
  520.         cprint("Could not find default public screen\n");
  521.  
  522.         return(FALSE);
  523.     }
  524.  
  525.     if(RendezvousData)
  526.     {
  527.         if(!(Screen = RendezvousData -> rd_Screen))
  528.             Screen = PublicScreen;
  529.     }
  530.     else
  531.     {
  532.         if(!(Screen = OpenScreenTags(NULL,
  533.             SA_DisplayID,    GetVPModeID(&PublicScreen -> ViewPort),
  534.             SA_Overscan,    OSCAN_TEXT,
  535.             SA_Depth,    2,
  536.             SA_Title,    PRGNAME " " VERSION " " HC_OS " Amiga rev 2, ported by Olaf `Olsen' Barthel",
  537.             SA_Behind,    TRUE,
  538.             SA_SysFont,    1,
  539.             SA_Pens,    &Pens,
  540.         TAG_DONE)))
  541.         {
  542.             cprint("Could not open screen\n");
  543.  
  544.             return(FALSE);
  545.         }
  546.     }
  547.  
  548.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  549.     {
  550.         cprint("Could not obtain screen visual info\n");
  551.  
  552.         return(FALSE);
  553.     }
  554.  
  555.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  556.     {
  557.         cprint("Could not create menus\n");
  558.  
  559.         return(FALSE);
  560.     }
  561.  
  562.     if(!LayoutMenus(Menu,VisualInfo,
  563.         GTMN_TextAttr,        Screen -> Font,
  564.         GTMN_NewLookMenus,    TRUE,
  565.     TAG_DONE))
  566.     {
  567.         cprint("Could not layout menus\n");
  568.  
  569.         return(FALSE);
  570.     }
  571.  
  572.     Top        = Screen -> BarHeight + 1;
  573.     BorderSize    = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + Screen -> WBorBottom;
  574.     FontSize    = GfxBase -> DefaultFont -> tf_YSize;
  575.     TotalHeight    = Screen -> Height - Top;
  576.     Lines        = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  577.     ExtraLines    = Lines > 25 ? (Lines - 25) / 3 : 0;
  578.     RemainingLines    = Lines > 25 + ExtraLines * 3 ? Lines - (25 + ExtraLines * 3) : 0;
  579.  
  580.     if(Lines < 25)
  581.     {
  582.         cprint("Screen size too small (need at least 25 text lines, can get only %d)\n",Lines);
  583.  
  584.         return(FALSE);
  585.     }
  586.  
  587.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  588.     {
  589.         cprint("Could not open console window #1\n");
  590.  
  591.         return(FALSE);
  592.     }
  593.  
  594.     TotalHeight    -= LogWindow -> Height + 1;
  595.     Top        += LogWindow -> Height + 1;
  596.  
  597.     if(!OpenConsole(Screen,Top,BorderSize + 3 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  598.     {
  599.         cprint("Could not open console window #2\n");
  600.  
  601.         return(FALSE);
  602.     }
  603.  
  604.     TotalHeight    -= FileWindow -> Height + 1;
  605.     Top        += FileWindow -> Height + 1;
  606.  
  607.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  608.     {
  609.         cprint("Could not open console window #3\n");
  610.  
  611.         return(FALSE);
  612.     }
  613.  
  614.     TotalHeight    -= RemoteWindow -> Height + 1;
  615.     Top        += RemoteWindow -> Height + 1;
  616.  
  617.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press Amiga+X to start/end chat mode)",TRUE,&LocalWindow,&LocalRequest))
  618.     {
  619.         cprint("Could not open console window #4\n");
  620.  
  621.         return(FALSE);
  622.     }
  623.  
  624.     SetMenuStrip(LocalWindow,Menu);
  625.  
  626.     if(!ModifyIDCMP(LocalWindow,IDCMP_MENUPICK))
  627.     {
  628.         cprint("Could not modify IDCMP flags\n");
  629.  
  630.         return(FALSE);
  631.     }
  632.  
  633.     LocalWindow -> Flags &= ~WFLG_RMBTRAP;
  634.  
  635.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  636.  
  637.     ConsoleReadRequest -> io_Message . mn_ReplyPort = ConsoleReadPort;
  638.  
  639.         /* Turn the cursors back on. */
  640.  
  641.     ConPrintf(LocalRequest,"\33[ p");
  642.     ConPrintf(RemoteRequest,"\33[ p");
  643.  
  644.     ConsoleReadRequest -> io_Command    = CMD_READ;
  645.     ConsoleReadRequest -> io_Data        = &ConsoleChar;
  646.     ConsoleReadRequest -> io_Length        = 1;
  647.  
  648.     ClrSignal(SIG_CONREAD);
  649.     SendIO(ConsoleReadRequest);
  650.  
  651.     ThisProcess = (struct Process *)FindTask(NULL);
  652.  
  653.     OldPtr = ThisProcess -> pr_WindowPtr;
  654.  
  655.     ThisProcess -> pr_WindowPtr = (APTR)LocalWindow;
  656.  
  657.     ScreenToFront(Screen);
  658.  
  659.     ActivateWindow(LocalWindow);
  660.  
  661.     UnlockPubScreen(NULL,PublicScreen);
  662.  
  663.     PublicScreen = NULL;
  664.  
  665.     return(TRUE);
  666. }
  667.  
  668.     /* CloseAll():
  669.      *
  670.      *    Close all the resources.
  671.      */
  672.  
  673. STATIC VOID
  674. CloseAll(VOID)
  675. {
  676.     if(LocalWindow)
  677.         ClearMenuStrip(LocalWindow);
  678.  
  679.     if(Menu)
  680.         FreeMenus(Menu);
  681.  
  682.     if(VisualInfo)
  683.         FreeVisualInfo(VisualInfo);
  684.  
  685.     if(AnchorUsed)
  686.         MatchEnd(Anchor);
  687.  
  688.     if(Anchor)
  689.         FreeVec(Anchor);
  690.  
  691.     if(ThisProcess)
  692.         ThisProcess -> pr_WindowPtr = OldPtr;
  693.  
  694.     if(ConsoleReadRequest)
  695.     {
  696.         if(ConsoleReadRequest -> io_Device)
  697.         {
  698.             if(!CheckIO(ConsoleReadRequest))
  699.                 AbortIO(ConsoleReadRequest);
  700.  
  701.             WaitIO(ConsoleReadRequest);
  702.         }
  703.  
  704.         FreeVec(ConsoleReadRequest);
  705.     }
  706.  
  707.     CloseConsole(&LocalWindow,&LocalRequest);
  708.     CloseConsole(&RemoteWindow,&RemoteRequest);
  709.     CloseConsole(&FileWindow,&FileRequest);
  710.     CloseConsole(&LogWindow,&LogRequest);
  711.  
  712.     if(!RendezvousData && Screen)
  713.         CloseScreen(Screen);
  714.  
  715.     if(PublicScreen)
  716.         UnlockPubScreen(NULL,PublicScreen);
  717.  
  718.     DeleteSerialBuffer(NextBuffer);
  719.     DeleteSerialBuffer(ThisBuffer);
  720.  
  721.     if(RendezvousData)
  722.     {
  723.         if(ReadBuffer -> IsBusy)
  724.         {
  725.             if(!CheckIO(ReadBuffer -> SerialRequest))
  726.                 AbortIO(ReadBuffer -> SerialRequest);
  727.  
  728.             WaitIO(ReadBuffer -> SerialRequest);
  729.         }
  730.  
  731.         FreeVec(ReadBuffer);
  732.     }
  733.     else
  734.         DeleteSerialBuffer(ReadBuffer);
  735.  
  736.     if(ConsoleWritePort)
  737.         DeleteMsgPort(ConsoleWritePort);
  738.  
  739.     if(ConsoleReadPort)
  740.         DeleteMsgPort(ConsoleReadPort);
  741.  
  742.     if(WritePort)
  743.         DeleteMsgPort(WritePort);
  744.  
  745.     if(ReadPort)
  746.         DeleteMsgPort(ReadPort);
  747.  
  748.     if(TimeRequest)
  749.     {
  750.         if(TimeRequest -> tr_node . io_Device)
  751.             CloseDevice(TimeRequest);
  752.  
  753.         DeleteIORequest(TimeRequest);
  754.     }
  755.  
  756.     if(TimePort)
  757.         DeleteMsgPort(TimePort);
  758.  
  759.     if(UtilityBase)
  760.         CloseLibrary(UtilityBase);
  761.  
  762.     if(GadToolsBase)
  763.         CloseLibrary(GadToolsBase);
  764.  
  765.     if(GfxBase)
  766.         CloseLibrary(GfxBase);
  767.  
  768.     if(IntuitionBase)
  769.         CloseLibrary(IntuitionBase);
  770.  
  771.     if(RendezvousData)
  772.     {
  773.         (*RendezvousSemaphore -> rs_Logoff)(RendezvousData);
  774.  
  775.         RendezvousData = NULL;
  776.     }
  777.  
  778.     if(RendezvousSemaphore)
  779.     {
  780.         ReleaseSemaphore(RendezvousSemaphore);
  781.  
  782.         RendezvousSemaphore = NULL;
  783.     }
  784. }
  785.  
  786.     /* ConPutc():
  787.      *
  788.      *    Output a single character.
  789.      */
  790.  
  791. VOID __stdargs
  792. ConPutc(struct IOStdReq *Request,UBYTE Char)
  793. {
  794.     Request -> io_Command    = CMD_WRITE;
  795.     Request -> io_Data    = &Char;
  796.     Request -> io_Length    = 1;
  797.  
  798.     DoIO(Request);
  799. }
  800.  
  801.     /* ConPuts():
  802.      *
  803.      *    Output a string.
  804.      */
  805.  
  806. VOID
  807. ConPuts(struct IOStdReq *Request,STRPTR String)
  808. {
  809.     Request -> io_Command    = CMD_WRITE;
  810.     Request -> io_Data    = String;
  811.     Request -> io_Length    = strlen(String);
  812.  
  813.     DoIO(Request);
  814. }
  815.  
  816.     /* ConPrintf():
  817.      *
  818.      *    Formatted console output.
  819.      */
  820.  
  821. VOID __stdargs
  822. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  823. {
  824.     STATIC UBYTE Buffer[512];
  825.  
  826.     va_list VarArgs;
  827.  
  828.     va_start(VarArgs,Format);
  829.     vsprintf(Buffer,Format,VarArgs);
  830.     va_end(VarArgs);
  831.  
  832.     Request -> io_Command    = CMD_WRITE;
  833.     Request -> io_Data    = Buffer;
  834.     Request -> io_Length    = strlen(Buffer);
  835.  
  836.     DoIO(Request);
  837. }
  838.  
  839.     /* ConMove():
  840.      *
  841.      *    Move the cursor to a new position.
  842.      */
  843.  
  844. VOID
  845. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  846. {
  847.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  848. }
  849.  
  850.     /* ConClear():
  851.      *
  852.      *    Clear the console window.
  853.      */
  854.  
  855. VOID
  856. ConClear(struct IOStdReq *Request)
  857. {
  858.     struct ConUnit *ConUnit = (struct ConUnit *)Request -> io_Device;
  859.     LONG x,y;
  860.  
  861.     x = ConUnit -> cu_XCCP;
  862.     y = ConUnit -> cu_YCCP;
  863.  
  864.     ConPrintf(Request,"\f\33[%ld;%ldH",y,x);
  865. }
  866.  
  867.     /* ConGetKey():
  868.      *
  869.      *    Read a character from a console window.
  870.      */
  871.  
  872. int
  873. ConGetKey()
  874. {
  875.     if(ConsoleReady)
  876.     {
  877.         int Result = ConsoleChar;
  878.  
  879.         ConsoleReady = FALSE;
  880.  
  881.         ConsoleReadRequest -> io_Command    = CMD_READ;
  882.         ConsoleReadRequest -> io_Data        = &ConsoleChar;
  883.         ConsoleReadRequest -> io_Length        = 1;
  884.  
  885.         ClrSignal(SIG_CONREAD);
  886.         SendIO(ConsoleReadRequest);
  887.  
  888.         return(Result);
  889.     }
  890.     else
  891.     {
  892.         int Result = 0;
  893.  
  894.         if(WindowReady)
  895.         {
  896.             struct IntuiMessage *IntuiMessage;
  897.             ULONG MsgClass;
  898.             UWORD MsgCode;
  899.  
  900.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
  901.             {
  902.                 MsgClass    = IntuiMessage -> Class;
  903.                 MsgCode        = IntuiMessage -> Code;
  904.  
  905.                 ReplyMsg(IntuiMessage);
  906.  
  907.                 if(MsgClass == IDCMP_MENUPICK)
  908.                 {
  909.                     struct MenuItem *Item;
  910.  
  911.                     while(MsgCode != MENUNULL)
  912.                     {
  913.                         if(Item = ItemAddress(Menu,MsgCode))
  914.                         {
  915.                             if(MENU_USERDATA(Item))
  916.                             {
  917.                                 if(!Result)
  918.                                     Result = (int)MENU_USERDATA(Item);
  919.                             }
  920.  
  921.                             MsgCode = Item -> NextSelect;
  922.                         }
  923.                         else
  924.                             break;
  925.                     }
  926.                 }
  927.             }
  928.  
  929.             WindowReady = FALSE;
  930.         }
  931.  
  932.         return(Result);
  933.     }
  934. }
  935.  
  936.     /* ConScanKey():
  937.      *
  938.      *    Check for a keyboard event.
  939.      */
  940.  
  941. int
  942. ConScanKey()
  943. {
  944.     if(ConsoleReady || WindowReady)
  945.         return(1);
  946.     else
  947.     {
  948.         int Result = 0;
  949.  
  950.         if(CheckSignal(SIG_WINDOW))
  951.         {
  952.             WindowReady = TRUE;
  953.  
  954.             Result = 1;
  955.         }
  956.  
  957.         if(CheckIO(ConsoleReadRequest))
  958.         {
  959.             if(!WaitIO(ConsoleReadRequest))
  960.             {
  961.                 ConsoleReady = TRUE;
  962.  
  963.                 return(1);
  964.             }
  965.             else
  966.             {
  967.                 ConsoleReadRequest -> io_Command    = CMD_READ;
  968.                 ConsoleReadRequest -> io_Data        = &ConsoleChar;
  969.                 ConsoleReadRequest -> io_Length        = 1;
  970.  
  971.                 ClrSignal(SIG_CONREAD);
  972.                 SendIO(ConsoleReadRequest);
  973.             }
  974.         }
  975.  
  976.         return(Result);
  977.     }
  978.  
  979.     return(0);
  980. }
  981.  
  982.     /* dtr_out(byte flag):
  983.      *
  984.      *    If flag == 0 -> drop DTR signal, else set it.
  985.      */
  986.  
  987. VOID
  988. dtr_out(byte flag)
  989. {
  990.     if(!flag && !RendezvousData)
  991.     {
  992.         if(ThisBuffer -> IsBusy)
  993.         {
  994.             WaitIO(ThisBuffer -> SerialRequest);
  995.  
  996.             ThisBuffer -> IsBusy        = FALSE;
  997.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  998.         }
  999.  
  1000.         if(ReadBuffer -> IsBusy)
  1001.         {
  1002.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1003.                 AbortIO(ReadBuffer -> SerialRequest);
  1004.  
  1005.             WaitIO(ReadBuffer -> SerialRequest);
  1006.  
  1007.             ReadBuffer -> IsBusy        = FALSE;
  1008.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1009.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1010.  
  1011.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1012.  
  1013.             DoIO(ReadBuffer -> SerialRequest);
  1014.  
  1015.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1016.             {
  1017.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1018.  
  1019.                 if(Size > 0)
  1020.                 {
  1021.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1022.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1023.  
  1024.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1025.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1026.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1027.  
  1028.                     DoIO(ReadBuffer -> SerialRequest);
  1029.  
  1030.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1031.                 }
  1032.             }
  1033.         }
  1034.  
  1035.         CloseDevice(ReadBuffer -> SerialRequest);
  1036.  
  1037.         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1038.         TimeRequest -> tr_time . tv_secs    = 1;
  1039.         TimeRequest -> tr_time . tv_micro    = 0;
  1040.  
  1041.         DoIO(TimeRequest);
  1042.  
  1043.         if(OpenDevice(device,port,ReadBuffer -> SerialRequest,NULL))
  1044.         {
  1045.             CloseAll();
  1046.  
  1047.             exit(10);
  1048.         }
  1049.         else
  1050.         {
  1051.             ReadBuffer -> SerialRequest -> io_Baud        = ThisBuffer -> SerialRequest -> io_Baud;
  1052.             ReadBuffer -> SerialRequest -> io_ReadLen    = ThisBuffer -> SerialRequest -> io_ReadLen;
  1053.             ReadBuffer -> SerialRequest -> io_WriteLen    = ThisBuffer -> SerialRequest -> io_WriteLen;
  1054.             ReadBuffer -> SerialRequest -> io_SerFlags    = ThisBuffer -> SerialRequest -> io_SerFlags;
  1055.  
  1056.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1057.  
  1058.             DoIO(ReadBuffer -> SerialRequest);
  1059.  
  1060.             CopyMem(ReadBuffer -> SerialRequest,ThisBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1061.  
  1062.             ThisBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1063.  
  1064.             CopyMem(ReadBuffer -> SerialRequest,NextBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1065.  
  1066.             NextBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1067.         }
  1068.     }
  1069. }
  1070.  
  1071.     /* com_flow(byte flags):
  1072.      *
  1073.      *    The bit mask `flags' determines the style(s) of
  1074.      *    handshaking:
  1075.      *
  1076.      *    if (flags & 9) -> enable xON/xOFF software handshaking,
  1077.      *    if (flags & 2) -> enable RTS/CTS hardware handshaking
  1078.      */
  1079.  
  1080. VOID
  1081. com_flow(byte flags)
  1082. {
  1083.     if(ThisBuffer -> IsBusy)
  1084.     {
  1085.         WaitIO(ThisBuffer -> SerialRequest);
  1086.  
  1087.         ThisBuffer -> IsBusy        = FALSE;
  1088.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1089.     }
  1090.  
  1091.     if(ReadBuffer -> IsBusy)
  1092.     {
  1093.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1094.             AbortIO(ReadBuffer -> SerialRequest);
  1095.  
  1096.         WaitIO(ReadBuffer -> SerialRequest);
  1097.  
  1098.         ReadBuffer -> IsBusy        = FALSE;
  1099.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1100.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1101.  
  1102.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1103.  
  1104.         DoIO(ReadBuffer -> SerialRequest);
  1105.  
  1106.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1107.         {
  1108.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1109.  
  1110.             if(Size > 0)
  1111.             {
  1112.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1113.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1114.  
  1115.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1116.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1117.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1118.  
  1119.                 DoIO(ReadBuffer -> SerialRequest);
  1120.  
  1121.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1122.             }
  1123.         }
  1124.     }
  1125.  
  1126.     if(flags & 2)
  1127.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_7WIRE;
  1128.     else
  1129.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_7WIRE;
  1130.  
  1131.     if(flags & 9)
  1132.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_XDISABLED;
  1133.     else
  1134.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_XDISABLED;
  1135.  
  1136.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1137.  
  1138.     DoIO(ReadBuffer -> SerialRequest);
  1139.  
  1140.     ThisBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1141.     NextBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1142. }
  1143.  
  1144.     /* com_setspeed(word speed):
  1145.      *
  1146.      *    Set the transfer speed (in bits/second).
  1147.      */
  1148.  
  1149. VOID
  1150. com_setspeed(word speed)
  1151. {
  1152.     if(ThisBuffer -> IsBusy)
  1153.     {
  1154.         WaitIO(ThisBuffer -> SerialRequest);
  1155.  
  1156.         ThisBuffer -> IsBusy        = FALSE;
  1157.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1158.     }
  1159.  
  1160.     if(ReadBuffer -> IsBusy)
  1161.     {
  1162.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1163.             AbortIO(ReadBuffer -> SerialRequest);
  1164.  
  1165.         WaitIO(ReadBuffer -> SerialRequest);
  1166.  
  1167.         ReadBuffer -> IsBusy        = FALSE;
  1168.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1169.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1170.  
  1171.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1172.  
  1173.         DoIO(ReadBuffer -> SerialRequest);
  1174.  
  1175.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1176.         {
  1177.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1178.  
  1179.             if(Size > 0)
  1180.             {
  1181.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1182.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1183.  
  1184.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1185.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1186.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1187.  
  1188.                 DoIO(ReadBuffer -> SerialRequest);
  1189.  
  1190.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1191.             }
  1192.         }
  1193.     }
  1194.  
  1195.     ReadBuffer -> SerialRequest -> io_Baud = speed;
  1196.  
  1197.     if(parity)
  1198.     {
  1199.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 7;
  1200.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_PARTY_ON;
  1201.     }
  1202.     else
  1203.     {
  1204.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 8;
  1205.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_PARTY_ON;
  1206.     }
  1207.  
  1208.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1209.  
  1210.     DoIO(ReadBuffer -> SerialRequest);
  1211.  
  1212.     ThisBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1213.     ThisBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1214.     ThisBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1215.     ThisBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1216.  
  1217.     NextBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1218.     NextBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1219.     NextBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1220.     NextBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1221. }
  1222.  
  1223.     /* com_putblock(byte *s,word len):
  1224.      *
  1225.      *    Send a data block asynchronously.
  1226.      */
  1227.  
  1228. VOID
  1229. com_putblock(byte *s,word len)
  1230. {
  1231.     struct SerialBuffer *Swap = ThisBuffer;
  1232.  
  1233.     if(ThisBuffer -> IsBusy)
  1234.         WaitIO(ThisBuffer -> SerialRequest);
  1235.     else
  1236.     {
  1237.         if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1238.         {
  1239.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1240.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1241.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1242.  
  1243.             DoIO(ThisBuffer -> SerialRequest);
  1244.         }
  1245.     }
  1246.  
  1247.     ThisBuffer -> IsBusy        = FALSE;
  1248.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1249.  
  1250.     ThisBuffer = NextBuffer;
  1251.     NextBuffer = Swap;
  1252.  
  1253.     if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1254.     {
  1255.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1256.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1257.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1258.  
  1259.         DoIO(ThisBuffer -> SerialRequest);
  1260.     }
  1261.  
  1262.     ThisBuffer -> IsBusy        = FALSE;
  1263.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1264.  
  1265.     while(len > 2 * ThisBuffer -> SerialSize)
  1266.     {
  1267.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1268.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = s;
  1269.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialSize;
  1270.  
  1271.         s    += ThisBuffer -> SerialSize;
  1272.         len    -= ThisBuffer -> SerialSize;
  1273.  
  1274.         DoIO(ThisBuffer -> SerialRequest);
  1275.     }
  1276.  
  1277.     CopyMem(s,ThisBuffer -> SerialBuffer,MIN(len,ThisBuffer -> SerialSize));
  1278.  
  1279.     ThisBuffer -> IsBusy                    = TRUE;
  1280.     ThisBuffer -> SerialIndex                = ThisBuffer -> SerialBuffer + MIN(len,ThisBuffer -> SerialSize);
  1281.     ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1282.     ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1283.     ThisBuffer -> SerialRequest -> IOSer . io_Length    = MIN(len,ThisBuffer -> SerialSize);
  1284.  
  1285.     len    -= ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1286.     s    += ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1287.  
  1288.     ClrSignal(SIG_SERWRITE);
  1289.     SendIO(ThisBuffer -> SerialRequest);
  1290.  
  1291.     if(len > 0)
  1292.     {
  1293.         CopyMem(s,NextBuffer -> SerialBuffer,len);
  1294.  
  1295.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer + len;
  1296.     }
  1297. }
  1298.  
  1299.     /* breakfunc():
  1300.      *
  1301.      *    Cleanup routine for SAS/C.
  1302.      */
  1303.  
  1304. static int
  1305. breakfunc(void)
  1306. {
  1307.     CloseAll();
  1308.  
  1309.     return(1);
  1310. }
  1311.  
  1312.     /* sys_init(VOID):
  1313.      *
  1314.      *    Initialize this driver implementation.
  1315.      */
  1316.  
  1317. VOID
  1318. sys_init(VOID)
  1319. {
  1320.     if(!OpenAll(device,port))
  1321.     {
  1322.         CloseAll();
  1323.  
  1324.         endprog(2);
  1325.     }
  1326.  
  1327.     onbreak(breakfunc);
  1328. }
  1329.  
  1330.     /* sys_reset(VOID):
  1331.      *
  1332.      *    Perform cleanup for this driver implementation.
  1333.      */
  1334.  
  1335. VOID
  1336. sys_reset(VOID)
  1337. {
  1338.     CloseAll();
  1339. }
  1340.  
  1341.     /* sys_idle(VOID):
  1342.      *
  1343.      *    This routine gets called when the system is idle.
  1344.      *    That's a nice one. We are supposed to call the
  1345.      *    system scheduler, etc.
  1346.      */
  1347.  
  1348. VOID
  1349. sys_idle(VOID)
  1350. {
  1351.     ULONG Signals;
  1352.  
  1353.     if(ReadBuffer -> SerialFilled <= 0 && !ReadBuffer -> IsBusy)
  1354.     {
  1355.         ReadBuffer -> IsBusy                    = TRUE;
  1356.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1357.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1358.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1359.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1360.  
  1361.         ClrSignal(SIG_SERREAD);
  1362.         SendIO(ReadBuffer -> SerialRequest);
  1363.     }
  1364.  
  1365.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1366.     TimeRequest -> tr_time . tv_secs    = 1;
  1367.     TimeRequest -> tr_time . tv_micro    = 0;
  1368.  
  1369.     ClrSignal(SIG_TIMER);
  1370.     SendIO(TimeRequest);
  1371.  
  1372.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1373.  
  1374.     if(!(Signals & SIG_TIMER))
  1375.     {
  1376.         if(!CheckIO(TimeRequest))
  1377.             AbortIO(TimeRequest);
  1378.     }
  1379.  
  1380.     WaitIO(TimeRequest);
  1381.  
  1382.     if(Signals & SIG_SERREAD)
  1383.     {
  1384.         WaitIO(ReadBuffer -> SerialRequest);
  1385.  
  1386.         ReadBuffer -> IsBusy        = FALSE;
  1387.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1388.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1389.  
  1390.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1391.  
  1392.         DoIO(ReadBuffer -> SerialRequest);
  1393.  
  1394.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1395.         {
  1396.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1397.  
  1398.             if(Size > 0)
  1399.             {
  1400.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1401.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1402.  
  1403.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1404.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1405.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1406.  
  1407.                 DoIO(ReadBuffer -> SerialRequest);
  1408.  
  1409.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1410.             }
  1411.         }
  1412.     }
  1413.  
  1414.     if(Signals & SIG_SERWRITE)
  1415.     {
  1416.         struct SerialBuffer *Swap = ThisBuffer;
  1417.  
  1418.         WaitIO(ThisBuffer -> SerialRequest);
  1419.  
  1420.         ThisBuffer -> IsBusy        = FALSE;
  1421.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1422.  
  1423.         ThisBuffer = NextBuffer;
  1424.         NextBuffer = Swap;
  1425.     }
  1426.  
  1427.     if(Signals & SIG_CONREAD)
  1428.     {
  1429.         WaitIO(ConsoleReadRequest);
  1430.  
  1431.         ConsoleReady = TRUE;
  1432.     }
  1433.  
  1434.     if(Signals & SIG_WINDOW)
  1435.         WindowReady = TRUE;
  1436. }
  1437.  
  1438.     /* com_outfull(VOID):
  1439.      *
  1440.      *    Return number of bytes still to be transferred.
  1441.      */
  1442.  
  1443. int
  1444. com_outfull(VOID)
  1445. {
  1446.     return(ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer + NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer);
  1447. }
  1448.  
  1449.     /* carrier(VOID):
  1450.      *
  1451.      *    Return current carrier status.
  1452.      */
  1453.  
  1454. int
  1455. carrier(VOID)
  1456. {
  1457.     if(nocarrier)
  1458.         return(1);
  1459.     else
  1460.     {
  1461.         if(!ThisBuffer -> IsBusy)
  1462.         {
  1463.             ThisBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1464.  
  1465.             DoIO(ThisBuffer -> SerialRequest);
  1466.  
  1467.             if(ThisBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1468.                 return(0);
  1469.             else
  1470.                 return(1);
  1471.         }
  1472.         else
  1473.         {
  1474.             NextBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1475.  
  1476.             DoIO(NextBuffer -> SerialRequest);
  1477.  
  1478.             if(NextBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1479.                 return(0);
  1480.             else
  1481.                 return(1);
  1482.         }
  1483.     }
  1484. }
  1485.  
  1486.     /* com_flush(VOID):
  1487.      *
  1488.      *    Make sure all pending data gets written.
  1489.      */
  1490.  
  1491. VOID
  1492. com_flush(VOID)
  1493. {
  1494.     if(ThisBuffer -> IsBusy)
  1495.     {
  1496.         WaitIO(ThisBuffer -> SerialRequest);
  1497.  
  1498.         ThisBuffer -> IsBusy        = FALSE;
  1499.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1500.     }
  1501.  
  1502.     if(NextBuffer -> SerialIndex > NextBuffer -> SerialBuffer)
  1503.     {
  1504.         NextBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1505.         NextBuffer -> SerialRequest -> IOSer . io_Data        = NextBuffer -> SerialBuffer;
  1506.         NextBuffer -> SerialRequest -> IOSer . io_Length    = NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer;
  1507.  
  1508.         DoIO(NextBuffer -> SerialRequest);
  1509.  
  1510.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer;
  1511.     }
  1512. }
  1513.  
  1514.     /* com_putbyte(byte c):
  1515.      *
  1516.      *    Transmit a single byte, queueing it if necessary.
  1517.      */
  1518.  
  1519. VOID
  1520. com_putbyte(byte c)
  1521. {
  1522.     if(ThisBuffer -> IsBusy)
  1523.     {
  1524.         if(NextBuffer -> SerialIndex + 1 >= NextBuffer -> SerialTop)
  1525.         {
  1526.             struct SerialBuffer *Swap = ThisBuffer;
  1527.  
  1528.             WaitIO(ThisBuffer -> SerialRequest);
  1529.  
  1530.             ThisBuffer -> IsBusy        = FALSE;
  1531.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1532.  
  1533.             ThisBuffer = NextBuffer;
  1534.             NextBuffer = Swap;
  1535.  
  1536.             ThisBuffer -> IsBusy                    = TRUE;
  1537.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1538.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1539.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1540.  
  1541.             ClrSignal(SIG_SERWRITE);
  1542.             SendIO(ThisBuffer -> SerialRequest);
  1543.         }
  1544.  
  1545.         *NextBuffer -> SerialIndex++ = c;
  1546.     }
  1547.     else
  1548.     {
  1549.         if(ThisBuffer -> SerialIndex + 1 < ThisBuffer -> SerialTop)
  1550.         {
  1551.             *ThisBuffer -> SerialIndex++ = c;
  1552.  
  1553.             ThisBuffer -> IsBusy                    = TRUE;
  1554.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1555.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1556.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1557.  
  1558.             ClrSignal(SIG_SERWRITE);
  1559.             SendIO(ThisBuffer -> SerialRequest);
  1560.         }
  1561.         else
  1562.         {
  1563.             ThisBuffer -> IsBusy                    = TRUE;
  1564.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1565.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1566.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1567.  
  1568.             ClrSignal(SIG_SERWRITE);
  1569.             SendIO(ThisBuffer -> SerialRequest);
  1570.  
  1571.             *NextBuffer -> SerialIndex++ = c;
  1572.         }
  1573.     }
  1574. }
  1575.  
  1576.     /* com_purge(VOID):
  1577.      *
  1578.      *    Clear the read/write buffers.
  1579.      */
  1580.  
  1581. VOID
  1582. com_purge(VOID)
  1583. {
  1584.     if(ThisBuffer -> IsBusy)
  1585.     {
  1586.         if(!CheckIO(ThisBuffer -> SerialRequest))
  1587.             AbortIO(ThisBuffer -> SerialRequest);
  1588.  
  1589.         WaitIO(ThisBuffer -> SerialRequest);
  1590.     }
  1591.  
  1592.     ThisBuffer -> IsBusy        = FALSE;
  1593.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1594.  
  1595.     NextBuffer -> IsBusy        = FALSE;
  1596.     NextBuffer -> SerialIndex    = NextBuffer -> SerialBuffer;
  1597.  
  1598.     if(ReadBuffer -> IsBusy)
  1599.     {
  1600.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1601.             AbortIO(ReadBuffer -> SerialRequest);
  1602.  
  1603.         WaitIO(ReadBuffer -> SerialRequest);
  1604.     }
  1605.  
  1606.     ReadBuffer -> IsBusy        = FALSE;
  1607.     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1608.     ReadBuffer -> SerialFilled    = 0;
  1609.  
  1610.     ThisBuffer -> SerialRequest -> IOSer . io_Command = CMD_CLEAR;
  1611.     DoIO(ThisBuffer -> SerialRequest);
  1612. }
  1613.  
  1614.     /* com_dump(VOID):
  1615.      *
  1616.      *    Wait for asynchronous write request to terminate.
  1617.      */
  1618.  
  1619. VOID
  1620. com_dump(VOID)
  1621. {
  1622.     com_flush();
  1623. }
  1624.  
  1625.     /* com_getbyte(VOID):
  1626.      *
  1627.      *    Read a single byte from the serial line. If not available,
  1628.      *    return EOF.
  1629.      */
  1630.  
  1631. int
  1632. com_getbyte(VOID)
  1633. {
  1634.     int Result;
  1635.  
  1636.     if(ReadBuffer -> SerialFilled <= 0)
  1637.     {
  1638.         if(ReadBuffer -> IsBusy)
  1639.         {
  1640.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1641.                 return(EOF);
  1642.             else
  1643.                 WaitIO(ReadBuffer -> SerialRequest);
  1644.  
  1645.             ReadBuffer -> IsBusy        = FALSE;
  1646.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1647.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1648.  
  1649.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1650.  
  1651.             DoIO(ReadBuffer -> SerialRequest);
  1652.  
  1653.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1654.             {
  1655.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1656.  
  1657.                 if(Size > 0)
  1658.                 {
  1659.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1660.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1661.  
  1662.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1663.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1664.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1665.  
  1666.                     DoIO(ReadBuffer -> SerialRequest);
  1667.  
  1668.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1669.                 }
  1670.             }
  1671.         }
  1672.         else
  1673.         {
  1674.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1675.  
  1676.             DoIO(ReadBuffer -> SerialRequest);
  1677.  
  1678.             if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1679.                 return(EOF);
  1680.             else
  1681.             {
  1682.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1683.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1684.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = MIN(ReadBuffer -> SerialRequest -> IOSer . io_Actual,ReadBuffer -> SerialSize);
  1685.  
  1686.                 DoIO(ReadBuffer -> SerialRequest);
  1687.  
  1688.                 if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1689.                     return(EOF);
  1690.                 else
  1691.                 {
  1692.                     ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1693.                     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1694.                 }
  1695.             }
  1696.         }
  1697.     }
  1698.  
  1699.     Result = *ReadBuffer -> SerialIndex++;
  1700.  
  1701.     ReadBuffer -> SerialFilled--;
  1702.  
  1703.     if(ReadBuffer -> SerialFilled <= 0)
  1704.     {
  1705.         ReadBuffer -> IsBusy                    = TRUE;
  1706.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1707.  
  1708.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1709.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1710.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1711.  
  1712.         ClrSignal(SIG_SERREAD);
  1713.         SendIO(ReadBuffer -> SerialRequest);
  1714.     }
  1715.  
  1716.     return(Result);
  1717. }
  1718.  
  1719.     /* setstamp(STRPTR Name,LONG Time):
  1720.      *
  1721.      *    Set time/date of a file.
  1722.      */
  1723.  
  1724. VOID
  1725. setstamp(char *Name,long Time)
  1726. {
  1727.         struct tm *t;
  1728.     struct ClockData ClockData;
  1729.     ULONG Seconds;
  1730.     struct DateStamp Date;
  1731.  
  1732.         t = localtime(&Time);
  1733.  
  1734.     ClockData . sec        = t -> tm_sec;
  1735.     ClockData . min        = t -> tm_min;
  1736.     ClockData . hour    = t -> tm_hour;
  1737.     ClockData . mday    = t -> tm_mday;
  1738.     ClockData . month    = t -> tm_mon;
  1739.     ClockData . year    = t -> tm_year + 1900;
  1740.  
  1741.     Seconds = Date2Amiga(&ClockData);
  1742.  
  1743.     Date . ds_Days        = Seconds / (24 * 60 * 60);
  1744.     Date . ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  1745.     Date . ds_Tick        = (Seconds % 60) * TICKS_PER_SECOND;
  1746.  
  1747.     SetFileDate(Name,&Date);
  1748. }
  1749.  
  1750.     /* freespace(STRPTR DrivePath):
  1751.      *
  1752.      *    Get free disk space for specified drive.
  1753.      */
  1754.  
  1755. long
  1756. freespace(char *DrivePath)
  1757. {
  1758.     struct DevProc    *DevProc = GetDeviceProc(DrivePath,NULL);
  1759.     struct DosList    *DosList;
  1760.     BOOL         GoodDevice = FALSE;
  1761.     LONG         Size = (LONG)((ULONG)~0 >> 2);
  1762.  
  1763.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  1764.     {
  1765.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  1766.         {
  1767.             if(DosList -> dol_Task == DevProc -> dvp_Port)
  1768.             {
  1769.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList -> dol_misc . dol_handler . dol_Startup);
  1770.  
  1771.                 if(TypeOfMem(FSSM))
  1772.                 {
  1773.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM -> fssm_Environ);
  1774.                     STRPTR Name = (STRPTR)BADDR(FSSM -> fssm_Device);
  1775.  
  1776.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  1777.                     {
  1778.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  1779.                         {
  1780.                             struct IOStdReq __aligned IORequest;
  1781.  
  1782.                             if(!OpenDevice(Name + 1,FSSM -> fssm_Unit,&IORequest,FSSM -> fssm_Unit))
  1783.                             {
  1784.                                 CloseDevice(&IORequest);
  1785.  
  1786.                                 if(DosEnvec -> de_TableSize > 0 && DosEnvec -> de_LowCyl <= DosEnvec -> de_HighCyl)
  1787.                                     GoodDevice = TRUE;
  1788.                             }
  1789.                         }
  1790.                     }
  1791.                 }
  1792.             }
  1793.         }
  1794.  
  1795.         UnLockDosList(LDF_DEVICES | LDF_READ);
  1796.     }
  1797.  
  1798.     FreeDeviceProc(DevProc);
  1799.  
  1800.     if(GoodDevice)
  1801.     {
  1802.         struct InfoData *InfoData;
  1803.  
  1804.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  1805.         {
  1806.             UBYTE NewName[256],*Index;
  1807.             BPTR FileLock;
  1808.  
  1809.             memcpy(NewName,DrivePath,255);
  1810.  
  1811.             NewName[255] = 0;
  1812.  
  1813.             Index = PathPart(NewName);
  1814.  
  1815.             *Index = 0;
  1816.  
  1817.             FileLock = Lock(NewName,ACCESS_READ);
  1818.  
  1819.             if(FileLock)
  1820.             {
  1821.                 if(Info(FileLock,InfoData))
  1822.                     Size = InfoData -> id_BytesPerBlock * (InfoData -> id_NumBlocks - InfoData -> id_NumBlocksUsed);
  1823.  
  1824.                 UnLock(FileLock);
  1825.             }
  1826.  
  1827.             FreeVec(InfoData);
  1828.         }
  1829.     }
  1830.  
  1831.     return(Size);
  1832. }
  1833.  
  1834.     /* ffirst(char *FileSpec):
  1835.      *
  1836.      *    Return name of first file matching the given specs.
  1837.      */
  1838.  
  1839. char *
  1840. ffirst(char *filespec)
  1841. {
  1842.     AnchorUsed = TRUE;
  1843.  
  1844.     if(MatchFirst(filespec,Anchor))
  1845.         return(NULL);
  1846.     else
  1847.         return((char *)Anchor -> ap_Buf);
  1848. }
  1849.  
  1850.     /* fnext(VOID):
  1851.      *
  1852.      *    Return name of next file matching the given specs.
  1853.      */
  1854.  
  1855. char *
  1856. fnext(VOID)
  1857. {
  1858.     AnchorUsed = TRUE;
  1859.  
  1860.     if(MatchNext(Anchor))
  1861.         return(NULL);
  1862.     else
  1863.         return((char *)Anchor -> ap_Buf);
  1864. }
  1865.