home *** CD-ROM | disk | FTP | other *** search
/ The AGA Experience 2 / agavol2.iso / software / utilities / comms / term / extras / hydracom / hydracom-source.lha / amiga.c < prev    next >
C/C++ Source or Header  |  1995-08-18  |  56KB  |  2,598 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. #include <libraries/locale.h>
  19. #include <libraries/asl.h>
  20.  
  21. #include <graphics/gfxbase.h>
  22.  
  23. #include <utility/date.h>
  24.  
  25. #include <devices/conunit.h>
  26. #include <devices/serial.h>
  27. #include <devices/timer.h>
  28.  
  29. #include <hardware/cia.h>
  30.  
  31. #include <dos/dosextens.h>
  32. #include <dos/filehandler.h>
  33. #include <dos/dostags.h>
  34. #include <dos/dosasl.h>
  35.  
  36. #include <exec/memory.h>
  37.  
  38.     /* Correct a nasty bug in the prototypes. */
  39.  
  40. #define CheckIO foo21234
  41.  
  42. #include <clib/intuition_protos.h>
  43. #include <clib/gadtools_protos.h>
  44. #include <clib/graphics_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/locale_protos.h>
  47. #include <clib/timer_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50. #include <clib/asl_protos.h>
  51. #include <clib/macros.h>
  52.  
  53. #include <errno.h>
  54.  
  55. //#define DB(x)    x
  56. #define DB(x)
  57.  
  58. void __stdargs kprintf(STRPTR,...);
  59.  
  60.     /* Get the CheckIO prototype right. */
  61.  
  62. #undef CheckIO
  63.  
  64. struct IORequest *CheckIO(struct IORequest *);
  65.  
  66. #include "Rendezvous.h"
  67.  
  68. #include "hydracom.h"
  69.  
  70.     /* Difference between UTC and Amiga time. */
  71.  
  72. #define UTC_OFFSET    252482400
  73.  
  74.     /* Minimum of lines to reserve for local input. */
  75.  
  76. #define MIN_LINES    3
  77.  
  78.     /* Serial buffer size. */
  79.  
  80. #define BUFFER_SIZE    8192
  81.  
  82.     /* A handy macro. */
  83.  
  84. #define ClrSignal(s)    SetSignal(0,s)
  85.  
  86.     /* Signal masks. */
  87.  
  88. #define SIG_SERREAD    (1UL << ReadPort -> mp_SigBit)
  89. #define SIG_SERWRITE    (1UL << WritePort -> mp_SigBit)
  90. #define SIG_CONREAD    (1UL << ConsoleReadPort -> mp_SigBit)
  91. #define SIG_TIMER    (1UL << TimePort -> mp_SigBit)
  92. #define SIG_WINDOW    (1UL << WindowPort -> mp_SigBit)
  93. #define SIG_HANDSHAKE    SIGF_SINGLE
  94. #define SIG_KILL    SIGBREAKF_CTRL_C
  95.  
  96.     /* A serial buffer structure. */
  97.  
  98. struct SerialBuffer
  99. {
  100.     struct IOExtSer    *SerialRequest;
  101.     UBYTE        *SerialBuffer,
  102.             *SerialIndex,
  103.             *SerialTop;
  104.     LONG         SerialSize,
  105.              SerialFilled;
  106.     BOOL         IsClone,
  107.              IsBusy;
  108. };
  109.  
  110.     /* Special rendezvous data. */
  111.  
  112. STATIC struct RendezvousData        *RendezvousData;
  113. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  114.  
  115.     /* Library bases. */
  116.  
  117. struct IntuitionBase    *IntuitionBase;
  118. struct GfxBase        *GfxBase;
  119. struct LocaleBase    *LocaleBase;
  120. struct Library        *GadToolsBase,
  121.             *UtilityBase,
  122.             *TimerBase,
  123.             *AslBase;
  124.  
  125.     /* Timer data. */
  126.  
  127. struct MsgPort        *TimePort;
  128. struct timerequest    *TimeRequest;
  129.  
  130.     /* Serial data. */
  131.  
  132. struct MsgPort        *ReadPort,
  133.             *WritePort;
  134.  
  135. struct SerialBuffer    *ThisBuffer,
  136.             *NextBuffer,
  137.             *ReadBuffer;
  138.  
  139.     /* Console data. */
  140.  
  141. struct MsgPort        *WindowPort;
  142.  
  143. struct Window        *FileWindow,
  144.             *RemoteWindow,
  145.             *LocalWindow,
  146.             *LogWindow;
  147.  
  148. struct MsgPort        *ConsoleWritePort,
  149.             *ConsoleReadPort;
  150. struct IOStdReq        *ConsoleReadRequest;
  151. UBYTE             ConsoleChar;
  152. BOOL             ConsoleReady = FALSE,
  153.              WindowReady = FALSE;
  154.  
  155. struct IOStdReq        *FileRequest,
  156.             *RemoteRequest,
  157.             *LocalRequest,
  158.             *LogRequest;
  159.  
  160.     /* DOS Data. */
  161.  
  162. struct Process        *ThisProcess;
  163. APTR             OldPtr;
  164. LONG             OldPri;
  165.  
  166. struct AnchorPath    *Anchor;
  167. BOOL             AnchorUsed = FALSE;
  168.  
  169.     /* File requester data. */
  170.  
  171. struct Process        *FileRequesterProcess;
  172. struct MsgPort        *FileRequesterPort;
  173.  
  174.     /* Screen data. */
  175.  
  176. struct Screen        *PublicScreen,
  177.             *Screen;
  178.  
  179.     /* Menu data. */
  180.  
  181. APTR             VisualInfo;
  182. struct Menu        *Menu;
  183.  
  184. struct NewMenu MenuTemplate[] =
  185. {
  186.     { NM_TITLE, "Project",             0 ,    0,    0,    (APTR)0},
  187.     {  NM_ITEM, "Toggle chat",        "C",    0,    0,    (APTR)Alt_C},
  188.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  189.     {  NM_ITEM, "Hang up",            "H",    0,    0,    (APTR)Alt_H},
  190.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  191.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  192.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  193.     {  NM_ITEM, "Start upload",        "U",    0,    0,    (APTR)PgUp},
  194.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  195.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  196.     {  NM_ITEM, "Abort Hydra session",    ".",    0,    0,    (APTR)Esc},
  197.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  198.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  199.     { NM_END,   0,                 0 ,    0,    0,    (APTR)0}
  200. };
  201.  
  202.     /* Time data. */
  203.  
  204. LONG             GMT_Offset = UTC_OFFSET;
  205.  
  206.     /* Version ID. */
  207.  
  208. STRPTR VersionTag = "$VER: hydracom 1.0r7 (18.08.95)\r\n";
  209.  
  210.     /* CloseWindowSafely(struct Window *Window):
  211.      *
  212.      *    Close a window sharing its UserPort with other
  213.      *    windows.
  214.      */
  215.  
  216. STATIC VOID
  217. CloseWindowSafely(struct Window *Window)
  218. {
  219.     struct IntuiMessage    *IntuiMessage;
  220.     struct Node        *Successor;
  221.  
  222.     Forbid();
  223.  
  224.     if(Window -> UserPort)
  225.     {
  226.         IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
  227.  
  228.         while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
  229.         {
  230.             if(IntuiMessage -> IDCMPWindow == Window)
  231.             {
  232.                 Remove((struct Node *)IntuiMessage);
  233.  
  234.                 ReplyMsg((struct Message *)IntuiMessage);
  235.             }
  236.  
  237.             IntuiMessage = (struct IntuiMessage *)Successor;
  238.         }
  239.  
  240.         Window -> UserPort = NULL;
  241.     }
  242.  
  243.     ModifyIDCMP(Window,NULL);
  244.  
  245.     Permit();
  246.  
  247.     CloseWindow(Window);
  248. }
  249.  
  250.     /* UpdateTime(struct timeval *Now):
  251.      *
  252.      *    Get the current time and/or update the current
  253.      *    time offset data.
  254.      */
  255.  
  256. STATIC VOID
  257. UpdateTime(struct timeval *Now)
  258. {
  259.     if(Now)
  260.         Now -> tv_secs = Now -> tv_micro = 0;
  261.  
  262.     if(TimePort = CreateMsgPort())
  263.     {
  264.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  265.         {
  266.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  267.             {
  268.                 TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  269.  
  270.                 if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  271.                 {
  272.                     struct Locale *Locale;
  273.  
  274.                     if(Locale = OpenLocale(NULL))
  275.                     {
  276.                         GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  277.  
  278.                         CloseLocale(Locale);
  279.                     }
  280.  
  281.                     CloseLibrary(LocaleBase);
  282.  
  283.                     LocaleBase = NULL;
  284.                 }
  285.  
  286.                 if(Now)
  287.                     GetSysTime(Now);
  288.  
  289.                 TimerBase = NULL;
  290.  
  291.                 CloseDevice(TimeRequest);
  292.             }
  293.  
  294.             DeleteIORequest(TimeRequest);
  295.  
  296.             TimeRequest = NULL;
  297.         }
  298.  
  299.         DeleteMsgPort(TimePort);
  300.  
  301.         TimePort = NULL;
  302.     }
  303. }
  304.  
  305.     /* FileRequestEntry(VOID):
  306.      *
  307.      *    Asynchronous file request process entry.
  308.      */
  309.  
  310. STATIC VOID
  311. FileRequestEntry(VOID)
  312. {
  313.     struct FileRequester *FileRequester;
  314.  
  315.     geta4();
  316.  
  317.     if(FileRequester = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  318.         ASLFR_TitleText,    "Select file(s) to upload",
  319.         ASLFR_InitialPattern,    "#?",
  320.         ASLFR_Flags1,        FRF_PRIVATEIDCMP | FRF_DOMULTISELECT | FRF_DOPATTERNS,
  321.     TAG_DONE))
  322.     {
  323.         if(FileRequesterPort = CreateMsgPort())
  324.         {
  325.             struct Message    *Message;
  326.             ULONG         Signals;
  327.             BOOL         Done = FALSE;
  328.  
  329.             FileRequesterProcess = (struct Process *)FindTask(NULL);
  330.  
  331.             Signal(ThisProcess,SIG_HANDSHAKE);
  332.  
  333.             do
  334.             {
  335.                 Signals = Wait((1L << FileRequesterPort -> mp_SigBit) | SIG_KILL);
  336.  
  337.                 if(Signals & (1L << FileRequesterPort -> mp_SigBit))
  338.                 {
  339.                     LONG MaxLen;
  340.  
  341.                     while(Message = GetMsg(FileRequesterPort))
  342.                     {
  343.                         MaxLen = (LONG)Message -> mn_Node . ln_Name;
  344.  
  345.                         if(AslRequestTags(FileRequester,
  346.                             ASLFR_Window,        LocalWindow,
  347.                             ASLFR_SleepWindow,    TRUE,
  348.                         TAG_DONE))
  349.                         {
  350.                             if(FileRequester -> fr_NumArgs > 0)
  351.                             {
  352.                                 UBYTE     LocalBuffer[256];
  353.                                 char    *String;
  354.                                 LONG     Len,Count,i;
  355.  
  356.                                 for(i = Len = 0 ; i < FileRequester -> fr_NumArgs ; i++)
  357.                                 {
  358.                                     if(FileRequester -> fr_ArgList[i] . wa_Lock)
  359.                                     {
  360.                                         if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  361.                                             Len += strlen(LocalBuffer) + 1;
  362.                                     }
  363.                                     else
  364.                                         Len += strlen(FileRequester -> fr_Drawer) + 1;
  365.  
  366.                                     Len += strlen(FileRequester -> fr_ArgList[i] . wa_Name) + 1 + 2;
  367.                                 }
  368.  
  369.                                 Len++;
  370.  
  371.                                 if(String = AllocVec(Len,MEMF_ANY))
  372.                                 {
  373.                                     *String = 0;
  374.  
  375.                                     for(i = Count = 0 ; Count < MaxLen && i < FileRequester -> fr_NumArgs ; i++)
  376.                                     {
  377.                                         if(FileRequester -> fr_ArgList[i] . wa_Lock)
  378.                                         {
  379.                                             if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  380.                                             {
  381.                                                 if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  382.                                                 {
  383.                                                     if(Count + strlen(LocalBuffer) + 2 < MaxLen)
  384.                                                     {
  385.                                                         strcat(String,"\"");
  386.                                                         strcat(String,LocalBuffer);
  387.                                                         strcat(String,"\"");
  388.  
  389.                                                         Count += strlen(LocalBuffer) + 2;
  390.                                                     }
  391.                                                     else
  392.                                                         break;
  393.                                                 }
  394.                                             }
  395.                                         }
  396.                                         else
  397.                                         {
  398.                                             strcpy(LocalBuffer,FileRequester -> fr_Drawer);
  399.  
  400.                                             if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  401.                                             {
  402.                                                 if(Count + strlen(LocalBuffer) + 2 < MaxLen)
  403.                                                 {
  404.                                                     strcat(String,"\"");
  405.                                                     strcat(String,LocalBuffer);
  406.                                                     strcat(String,"\"");
  407.  
  408.                                                     Count += strlen(LocalBuffer) + 2;
  409.                                                 }
  410.                                                 else
  411.                                                     break;
  412.                                             }
  413.                                         }
  414.  
  415.                                         if(i != FileRequester -> fr_NumArgs - 1)
  416.                                         {
  417.                                             strcat(String," ");
  418.                                             Count++;
  419.                                         }
  420.                                     }
  421.  
  422.                                     Message -> mn_Node . ln_Name = String;
  423.  
  424.                                     ReplyMsg(Message);
  425.  
  426.                                     Message = NULL;
  427.                                 }
  428.                             }
  429.                             else
  430.                             {
  431.                                 if(FileRequester -> fr_File[0])
  432.                                 {
  433.                                     LONG Len;
  434.  
  435.                                     Len = strlen(FileRequester -> fr_Drawer) + strlen(FileRequester -> fr_File) + 2 + 2;
  436.  
  437.                                     if(Len <= MaxLen)
  438.                                     {
  439.                                         char *String;
  440.  
  441.                                         if(String = AllocVec(Len,MEMF_ANY))
  442.                                         {
  443.                                             strcpy(String + 1,FileRequester -> fr_Drawer);
  444.  
  445.                                             if(AddPart(String + 1,FileRequester -> fr_File,Len))
  446.                                             {
  447.                                                 String[0] = '\"';
  448.                                                 strcat(String,"\"");
  449.  
  450.                                                 Message -> mn_Node . ln_Name = String;
  451.  
  452.                                                 ReplyMsg(Message);
  453.  
  454.                                                 Message = NULL;
  455.                                             }
  456.                                             else
  457.                                                 FreeVec(String);
  458.                                         }
  459.                                     }
  460.                                 }
  461.                             }
  462.                         }
  463.  
  464.                         if(Message)
  465.                         {
  466.                             Message -> mn_Node . ln_Name = NULL;
  467.  
  468.                             ReplyMsg(Message);
  469.                         }
  470.                     }
  471.                 }
  472.  
  473.                 if(Signals & SIG_KILL)
  474.                     Done = TRUE;
  475.             }
  476.             while(!Done);
  477.  
  478.             while(Message = GetMsg(FileRequesterPort))
  479.             {
  480.                 Message -> mn_Node . ln_Name = NULL;
  481.  
  482.                 ReplyMsg(Message);
  483.             }
  484.  
  485.             DeleteMsgPort(FileRequesterPort);
  486.         }
  487.  
  488.         FreeAslRequest(FileRequester);
  489.     }
  490.  
  491.     Forbid();
  492.  
  493.     FileRequesterProcess = NULL;
  494.  
  495.     Signal(ThisProcess,SIG_HANDSHAKE);
  496. }
  497.  
  498.     /* GetFiles(char *Buffer,int MaxLen):
  499.      *
  500.      *    Get a list of file names, asynchronously please.
  501.      */
  502.  
  503. char *
  504. GetFiles(char *Buffer,int MaxLen)
  505. {
  506.     struct MsgPort    *ReplyPort;
  507.     char        *Result = NULL;
  508.  
  509.     if(ReplyPort = CreateMsgPort())
  510.     {
  511.         struct Message *Message;
  512.  
  513.         if(Message = AllocVec(sizeof(struct Message),MEMF_ANY | MEMF_CLEAR))
  514.         {
  515.             Message -> mn_Length        = sizeof(struct Message);
  516.             Message -> mn_ReplyPort        = ReplyPort;
  517.             Message -> mn_Node . ln_Name    = (STRPTR)MaxLen;
  518.  
  519.             PutMsg(FileRequesterPort,Message);
  520.  
  521.             FOREVER
  522.             {
  523.                 if(SetSignal(0,(1L << ReplyPort -> mp_SigBit)) & (1L << ReplyPort -> mp_SigBit))
  524.                 {
  525.                     GetMsg(ReplyPort);
  526.  
  527.                     break;
  528.                 }
  529.  
  530.                 sys_idle();
  531.             }
  532.  
  533.             if(Message -> mn_Node . ln_Name)
  534.             {
  535.                 strcpy(Buffer,Message -> mn_Node . ln_Name);
  536.  
  537.                 FreeVec(Message -> mn_Node . ln_Name);
  538.  
  539.                 Result = Buffer;
  540.             }
  541.  
  542.             FreeVec(Message);
  543.         }
  544.  
  545.         DeleteMsgPort(ReplyPort);
  546.     }
  547.  
  548.     return(Result);
  549. }
  550.  
  551.     /* OpenConsole():
  552.      *
  553.      *    Open a console window.
  554.      */
  555.  
  556. STATIC BOOL
  557. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  558. {
  559.     struct Window *Window;
  560.  
  561.     if(Window = OpenWindowTags(NULL,
  562.         WA_Left,        0,
  563.         WA_Top,            Top,
  564.         WA_Width,        Screen -> Width,
  565.         WA_Height,        Height,
  566.         WA_Title,        Title,
  567.         WA_SimpleRefresh,    TRUE,
  568.         WA_DepthGadget,        TRUE,
  569.         WA_DragBar,        TRUE,
  570.         WA_SizeGadget,        Resize,
  571.         WA_SizeBRight,        TRUE,
  572.         WA_CustomScreen,    Screen,
  573.         WA_NewLookMenus,    TRUE,
  574.     TAG_DONE))
  575.     {
  576.         Window -> UserPort = WindowPort;
  577.  
  578.         SetMenuStrip(Window,Menu);
  579.  
  580.         if(ModifyIDCMP(Window,IDCMP_MENUPICK))
  581.         {
  582.             struct IOStdReq *ConsoleRequest;
  583.  
  584.             if(Window -> RPort -> Font -> tf_Flags & FPF_PROPORTIONAL)
  585.                 SetFont(Window -> RPort,GfxBase -> DefaultFont);
  586.  
  587.             if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  588.             {
  589.                 ConsoleRequest -> io_Data = Window;
  590.  
  591.                 if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  592.                 {
  593.                     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);
  594.  
  595.                         /* Turn off the cursor. */
  596.  
  597.                     ConPrintf(ConsoleRequest,"\033[0 p");
  598.  
  599.                     *WindowPtr    = Window;
  600.                     *ConsolePtr    = ConsoleRequest;
  601.  
  602.                     return(TRUE);
  603.                 }
  604.  
  605.                 DeleteIORequest(ConsoleRequest);
  606.             }
  607.         }
  608.  
  609.         ClearMenuStrip(Window);
  610.  
  611.         CloseWindowSafely(Window);
  612.     }
  613.  
  614.     return(FALSE);
  615. }
  616.  
  617.     /* CloseConsole():
  618.      *
  619.      *    Close a console window.
  620.      */
  621.  
  622. STATIC VOID
  623. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  624. {
  625.     if(*ConsolePtr)
  626.     {
  627.         CloseDevice(*ConsolePtr);
  628.  
  629.         DeleteIORequest(*ConsolePtr);
  630.  
  631.         *ConsolePtr = NULL;
  632.     }
  633.  
  634.     if(*WindowPtr)
  635.     {
  636.         ClearMenuStrip(*WindowPtr);
  637.  
  638.         CloseWindowSafely(*WindowPtr);
  639.  
  640.         *WindowPtr = NULL;
  641.     }
  642. }
  643.  
  644.     /* CloneSerialBuffer():
  645.      *
  646.      *    Clone a SerialBuffer structure.
  647.      */
  648.  
  649. STATIC struct SerialBuffer *
  650. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  651. {
  652.     struct SerialBuffer *Buffer;
  653.  
  654.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source -> SerialSize,MEMF_ANY | MEMF_PUBLIC))
  655.     {
  656.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  657.         Buffer -> SerialFilled    = 0;
  658.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Source -> SerialSize;
  659.         Buffer -> SerialSize    = Source -> SerialSize;
  660.         Buffer -> IsClone    = TRUE;
  661.         Buffer -> IsBusy    = FALSE;
  662.  
  663.         if(Buffer -> SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  664.         {
  665.             CopyMem(Source -> SerialRequest,Buffer -> SerialRequest,sizeof(struct IOExtSer));
  666.  
  667.             Buffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = MsgPort;
  668.  
  669.             return(Buffer);
  670.         }
  671.         else
  672.             cprint("Could not create serial request\n");
  673.  
  674.         FreeVec(Buffer);
  675.     }
  676.     else
  677.         cprint("Could not create serial buffer\n");
  678.  
  679.     return(NULL);
  680. }
  681.  
  682.     /* DeleteSerialBuffer():
  683.      *
  684.      *    Delete a SerialBuffer structure.
  685.      */
  686.  
  687. STATIC VOID
  688. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  689. {
  690.     if(Buffer)
  691.     {
  692.         if(Buffer -> IsBusy)
  693.         {
  694.             if(!CheckIO(Buffer -> SerialRequest))
  695.                 AbortIO(Buffer -> SerialRequest);
  696.  
  697.             WaitIO(Buffer -> SerialRequest);
  698.         }
  699.  
  700.         if(Buffer -> IsClone)
  701.             FreeVec(Buffer -> SerialRequest);
  702.         else
  703.         {
  704.             CloseDevice(Buffer -> SerialRequest);
  705.  
  706.             DeleteIORequest(Buffer -> SerialRequest);
  707.         }
  708.  
  709.         FreeVec(Buffer);
  710.     }
  711. }
  712.  
  713.     /* CreateSerialBuffer():
  714.      *
  715.      *    Create a serial buffer structure.
  716.      */
  717.  
  718. STATIC struct SerialBuffer *
  719. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  720. {
  721.     struct SerialBuffer *Buffer;
  722.  
  723.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  724.     {
  725.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  726.         Buffer -> SerialFilled    = 0;
  727.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Size;
  728.         Buffer -> SerialSize    = Size;
  729.         Buffer -> IsClone    = FALSE;
  730.         Buffer -> IsBusy    = FALSE;
  731.  
  732.         if(Buffer -> SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  733.         {
  734.             Buffer -> SerialRequest -> io_SerFlags = SERF_SHARED;
  735.  
  736.             if(!OpenDevice(Device,Unit,Buffer -> SerialRequest,NULL))
  737.                 return(Buffer);
  738.             else
  739.             {
  740.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  741.  
  742.                 DeleteIORequest(Buffer -> SerialRequest);
  743.             }
  744.         }
  745.         else
  746.             cprint("Could not create serial request\n");
  747.  
  748.         FreeVec(Buffer);
  749.     }
  750.     else
  751.         cprint("Could not create serial buffer\n");
  752.  
  753.     return(NULL);
  754. }
  755.  
  756.     /* OpenAll():
  757.      *
  758.      *    Allocate all the resources required.
  759.      */
  760.  
  761. STATIC BOOL
  762. OpenAll(STRPTR Device,LONG Unit)
  763. {
  764.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  765.     UWORD Pens = (UWORD)~0;
  766.  
  767.     ThisProcess = (struct Process *)FindTask(NULL);
  768.  
  769.     if(pri != 1000)
  770.     {
  771.         if(pri < -128)
  772.             pri = 128;
  773.         else
  774.         {
  775.             if(pri > 127)
  776.                 pri = 127;
  777.         }
  778.  
  779.         OldPri = SetTaskPri(ThisProcess,pri);
  780.     }
  781.  
  782.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  783.     {
  784.         cprint("Could not open intuition.library v37\n");
  785.  
  786.         return(FALSE);
  787.     }
  788.  
  789.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  790.     {
  791.         cprint("Could not open graphics.library v37\n");
  792.  
  793.         return(FALSE);
  794.     }
  795.  
  796.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  797.     {
  798.         cprint("Could not open gadtools.library v37\n");
  799.  
  800.         return(FALSE);
  801.     }
  802.  
  803.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  804.     {
  805.         cprint("Could not open utility.library v37\n");
  806.  
  807.         return(FALSE);
  808.     }
  809.  
  810.     if(!(AslBase = OpenLibrary("asl.library",37)))
  811.     {
  812.         cprint("Could not open asl.library v37\n");
  813.  
  814.         return(FALSE);
  815.     }
  816.  
  817.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  818.     {
  819.         struct Locale *Locale;
  820.  
  821.         if(Locale = OpenLocale(NULL))
  822.         {
  823.             GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  824.  
  825.             CloseLocale(Locale);
  826.         }
  827.  
  828.         CloseLibrary(LocaleBase);
  829.     }
  830.  
  831.     Forbid();
  832.  
  833.     if(CreateNewProcTags(
  834.         NP_Name,    "HydraCom Filerequester Process",
  835.         NP_WindowPtr,    -1,
  836.         NP_Entry,    FileRequestEntry,
  837.     TAG_DONE))
  838.     {
  839.         ClrSignal(SIG_HANDSHAKE);
  840.  
  841.         Wait(SIG_HANDSHAKE);
  842.     }
  843.  
  844.     Permit();
  845.  
  846.     if(!FileRequesterProcess)
  847.     {
  848.         cprint("Could not create file requester process\n");
  849.  
  850.         return(FALSE);
  851.     }
  852.  
  853.     if(!(TimePort = CreateMsgPort()))
  854.     {
  855.         cprint("Could not create timer port\n");
  856.  
  857.         return(FALSE);
  858.     }
  859.  
  860.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  861.     {
  862.         cprint("Could not create timer request\n");
  863.  
  864.         return(FALSE);
  865.     }
  866.  
  867.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  868.     {
  869.         cprint("Could not open timer\n");
  870.  
  871.         return(FALSE);
  872.     }
  873.  
  874.     TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  875.  
  876.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  877.     {
  878.         cprint("Could not allocate pattern matching buffe\n");
  879.  
  880.         return(FALSE);
  881.     }
  882.  
  883.     Anchor -> ap_Strlen = 512;
  884.  
  885.     if(!(ReadPort = CreateMsgPort()))
  886.     {
  887.         cprint("Could not create serial read port\n");
  888.  
  889.         return(FALSE);
  890.     }
  891.  
  892.     if(!(WritePort = CreateMsgPort()))
  893.     {
  894.         cprint("Could not create serial write port\n");
  895.  
  896.         return(FALSE);
  897.     }
  898.  
  899.     Forbid();
  900.  
  901.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  902.     {
  903.         ObtainSemaphore(RendezvousSemaphore);
  904.  
  905.         if(!(RendezvousData = (*RendezvousSemaphore -> rs_Login)(ReadPort,WritePort,NULL)))
  906.         {
  907.             Permit();
  908.  
  909.             ReleaseSemaphore(RendezvousSemaphore);
  910.  
  911.             RendezvousSemaphore = NULL;
  912.  
  913.             cprint("Could not link to `term' port \"%s\"\n",Device);
  914.  
  915.             return(FALSE);
  916.         }
  917.     }
  918.  
  919.     Permit();
  920.  
  921.     if(!(ConsoleReadPort = CreateMsgPort()))
  922.     {
  923.         cprint("Could not create console read port\n");
  924.  
  925.         return(FALSE);
  926.     }
  927.  
  928.     if(!(ConsoleWritePort = CreateMsgPort()))
  929.     {
  930.         cprint("Could not create console write port\n");
  931.  
  932.         return(FALSE);
  933.     }
  934.  
  935.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  936.     {
  937.         cprint("Could not create console read request\n");
  938.  
  939.         return(FALSE);
  940.     }
  941.  
  942.     if(!RendezvousData)
  943.     {
  944.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  945.             return(FALSE);
  946.     }
  947.     else
  948.     {
  949.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  950.         {
  951.             ReadBuffer -> SerialBuffer    = ReadBuffer -> SerialIndex = (UBYTE *)(ReadBuffer + 1);
  952.             ReadBuffer -> SerialFilled    = 0;
  953.             ReadBuffer -> SerialTop        = ReadBuffer -> SerialBuffer + BUFFER_SIZE;
  954.             ReadBuffer -> SerialSize    = BUFFER_SIZE;
  955.             ReadBuffer -> IsClone        = TRUE;
  956.             ReadBuffer -> IsBusy        = FALSE;
  957.             ReadBuffer -> SerialRequest    = &RendezvousData -> rd_ReadRequest;
  958.         }
  959.         else
  960.         {
  961.             cprint("Could not create serial ReadBuffer\n");
  962.  
  963.             return(FALSE);
  964.         }
  965.     }
  966.  
  967.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  968.         return(FALSE);
  969.  
  970.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  971.         return(FALSE);
  972.  
  973.     if(!(PublicScreen = LockPubScreen(NULL)))
  974.     {
  975.         cprint("Could not find default public screen\n");
  976.  
  977.         return(FALSE);
  978.     }
  979.  
  980.     if(RendezvousData)
  981.     {
  982.         if(!(Screen = RendezvousData -> rd_Screen))
  983.             Screen = PublicScreen;
  984.     }
  985.     else
  986.     {
  987.         if(!(Screen = OpenScreenTags(NULL,
  988.             SA_DisplayID,    GetVPModeID(&PublicScreen -> ViewPort),
  989.             SA_Overscan,    OSCAN_TEXT,
  990.             SA_Depth,    2,
  991.             SA_Title,    PRGNAME " " VERSION " " HC_OS " Amiga rev 6, ported by Olaf `Olsen' Barthel",
  992.             SA_Behind,    TRUE,
  993.             SA_SysFont,    1,
  994.             SA_Pens,    &Pens,
  995.             SA_Interleaved,    TRUE,
  996.         TAG_DONE)))
  997.         {
  998.             cprint("Could not open screen\n");
  999.  
  1000.             return(FALSE);
  1001.         }
  1002.     }
  1003.  
  1004.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  1005.     {
  1006.         cprint("Could not obtain screen visual info\n");
  1007.  
  1008.         return(FALSE);
  1009.     }
  1010.  
  1011.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  1012.     {
  1013.         cprint("Could not create menus\n");
  1014.  
  1015.         return(FALSE);
  1016.     }
  1017.  
  1018.     if(!LayoutMenus(Menu,VisualInfo,
  1019.         GTMN_TextAttr,        Screen -> Font,
  1020.         GTMN_NewLookMenus,    TRUE,
  1021.     TAG_DONE))
  1022.     {
  1023.         cprint("Could not layout menus\n");
  1024.  
  1025.         return(FALSE);
  1026.     }
  1027.  
  1028.     Top        = Screen -> BarHeight + 1;
  1029.     BorderSize    = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + Screen -> WBorBottom;
  1030.     FontSize    = GfxBase -> DefaultFont -> tf_YSize;
  1031.     TotalHeight    = Screen -> Height - Top;
  1032.     Lines        = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  1033.     ExtraLines    = Lines > MIN_LINES ? (Lines - MIN_LINES) / 3 : 0;
  1034.     RemainingLines    = Lines > MIN_LINES + ExtraLines * 3 ? Lines - (MIN_LINES + ExtraLines * 3) : 0;
  1035.  
  1036.     if(Lines < MIN_LINES)
  1037.     {
  1038.         cprint("Screen size too small (need at least %d text lines, can get only %d)\n",MIN_LINES,Lines);
  1039.  
  1040.         return(FALSE);
  1041.     }
  1042.  
  1043.     if(!(WindowPort = CreateMsgPort()))
  1044.     {
  1045.         cprint("Could not create window port\n");
  1046.  
  1047.         return(FALSE);
  1048.     }
  1049.  
  1050.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  1051.     {
  1052.         cprint("Could not open console window #1\n");
  1053.  
  1054.         return(FALSE);
  1055.     }
  1056.  
  1057.     TotalHeight    -= LogWindow -> Height + 1;
  1058.     Top        += LogWindow -> Height + 1;
  1059.  
  1060.     if(!OpenConsole(Screen,Top,BorderSize + 2 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  1061.     {
  1062.         cprint("Could not open console window #2\n");
  1063.  
  1064.         return(FALSE);
  1065.     }
  1066.  
  1067.     ConPrintf(FileRequest,"\033[?7l");
  1068.  
  1069.     TotalHeight    -= FileWindow -> Height + 1;
  1070.     Top        += FileWindow -> Height + 1;
  1071.  
  1072.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  1073.     {
  1074.         cprint("Could not open console window #3\n");
  1075.  
  1076.         return(FALSE);
  1077.     }
  1078.  
  1079.     TotalHeight    -= RemoteWindow -> Height + 1;
  1080.     Top        += RemoteWindow -> Height + 1;
  1081.  
  1082.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press [Amiga+C] to start/end chat mode, [Esc] to abort Hydra session)",TRUE,&LocalWindow,&LocalRequest))
  1083.     {
  1084.         cprint("Could not open console window #4\n");
  1085.  
  1086.         return(FALSE);
  1087.     }
  1088.  
  1089.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  1090.  
  1091.     ConsoleReadRequest -> io_Message . mn_ReplyPort = ConsoleReadPort;
  1092.  
  1093.         /* Turn the cursors back on. */
  1094.  
  1095.     ConPrintf(LocalRequest,"\33[ p");
  1096.     ConPrintf(RemoteRequest,"\33[ p");
  1097.  
  1098.     ConsoleReadRequest -> io_Command    = CMD_READ;
  1099.     ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1100.     ConsoleReadRequest -> io_Length        = 1;
  1101.  
  1102.     ClrSignal(SIG_CONREAD);
  1103.     SendIO(ConsoleReadRequest);
  1104.  
  1105.     OldPtr = ThisProcess -> pr_WindowPtr;
  1106.  
  1107.     ThisProcess -> pr_WindowPtr = (APTR)LocalWindow;
  1108.  
  1109.     if(!quiet)
  1110.     {
  1111.         ScreenToFront(Screen);
  1112.  
  1113.         ActivateWindow(LocalWindow);
  1114.     }
  1115.  
  1116.     UnlockPubScreen(NULL,PublicScreen);
  1117.  
  1118.     PublicScreen = NULL;
  1119.  
  1120.     if(!RendezvousData)
  1121.         com_flow(flowflags);
  1122.  
  1123.     return(TRUE);
  1124. }
  1125.  
  1126.     /* CloseAll():
  1127.      *
  1128.      *    Close all the resources.
  1129.      */
  1130.  
  1131. STATIC VOID
  1132. CloseAll(VOID)
  1133. {
  1134.     if(FileRequesterProcess)
  1135.     {
  1136.         Forbid();
  1137.  
  1138.         ClrSignal(SIG_HANDSHAKE);
  1139.  
  1140.         Signal(FileRequesterProcess,SIG_KILL);
  1141.  
  1142.         Wait(SIG_HANDSHAKE);
  1143.  
  1144.         Permit();
  1145.     }
  1146.  
  1147.     if(LocalWindow)
  1148.         ClearMenuStrip(LocalWindow);
  1149.  
  1150.     if(Menu)
  1151.         FreeMenus(Menu);
  1152.  
  1153.     if(VisualInfo)
  1154.         FreeVisualInfo(VisualInfo);
  1155.  
  1156.     if(AnchorUsed)
  1157.         MatchEnd(Anchor);
  1158.  
  1159.     if(Anchor)
  1160.         FreeVec(Anchor);
  1161.  
  1162.     if(ThisProcess)
  1163.         ThisProcess -> pr_WindowPtr = OldPtr;
  1164.  
  1165.     if(ConsoleReadRequest)
  1166.     {
  1167.         if(ConsoleReadRequest -> io_Device)
  1168.         {
  1169.             if(!CheckIO(ConsoleReadRequest))
  1170.                 AbortIO(ConsoleReadRequest);
  1171.  
  1172.             WaitIO(ConsoleReadRequest);
  1173.         }
  1174.  
  1175.         FreeVec(ConsoleReadRequest);
  1176.     }
  1177.  
  1178.     CloseConsole(&LocalWindow,&LocalRequest);
  1179.     CloseConsole(&RemoteWindow,&RemoteRequest);
  1180.     CloseConsole(&FileWindow,&FileRequest);
  1181.     CloseConsole(&LogWindow,&LogRequest);
  1182.  
  1183.     if(WindowPort)
  1184.         DeleteMsgPort(WindowPort);
  1185.  
  1186.     if(!RendezvousData && Screen)
  1187.         CloseScreen(Screen);
  1188.  
  1189.     if(PublicScreen)
  1190.         UnlockPubScreen(NULL,PublicScreen);
  1191.  
  1192.     DeleteSerialBuffer(NextBuffer);
  1193.     DeleteSerialBuffer(ThisBuffer);
  1194.  
  1195.     if(RendezvousData)
  1196.     {
  1197.         if(ReadBuffer -> IsBusy)
  1198.         {
  1199.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1200.                 AbortIO(ReadBuffer -> SerialRequest);
  1201.  
  1202.             WaitIO(ReadBuffer -> SerialRequest);
  1203.         }
  1204.  
  1205.         FreeVec(ReadBuffer);
  1206.     }
  1207.     else
  1208.         DeleteSerialBuffer(ReadBuffer);
  1209.  
  1210.     if(ConsoleWritePort)
  1211.         DeleteMsgPort(ConsoleWritePort);
  1212.  
  1213.     if(ConsoleReadPort)
  1214.         DeleteMsgPort(ConsoleReadPort);
  1215.  
  1216.     if(WritePort)
  1217.         DeleteMsgPort(WritePort);
  1218.  
  1219.     if(ReadPort)
  1220.         DeleteMsgPort(ReadPort);
  1221.  
  1222.     if(TimeRequest)
  1223.     {
  1224.         if(TimeRequest -> tr_node . io_Device)
  1225.             CloseDevice(TimeRequest);
  1226.  
  1227.         DeleteIORequest(TimeRequest);
  1228.     }
  1229.  
  1230.     if(TimePort)
  1231.         DeleteMsgPort(TimePort);
  1232.  
  1233.     if(UtilityBase)
  1234.         CloseLibrary(UtilityBase);
  1235.  
  1236.     if(AslBase)
  1237.         CloseLibrary(AslBase);
  1238.  
  1239.     if(GadToolsBase)
  1240.         CloseLibrary(GadToolsBase);
  1241.  
  1242.     if(GfxBase)
  1243.         CloseLibrary(GfxBase);
  1244.  
  1245.     if(IntuitionBase)
  1246.         CloseLibrary(IntuitionBase);
  1247.  
  1248.     if(RendezvousData)
  1249.     {
  1250.         (*RendezvousSemaphore -> rs_Logoff)(RendezvousData);
  1251.  
  1252.         RendezvousData = NULL;
  1253.     }
  1254.  
  1255.     if(RendezvousSemaphore)
  1256.     {
  1257.         ReleaseSemaphore(RendezvousSemaphore);
  1258.  
  1259.         RendezvousSemaphore = NULL;
  1260.     }
  1261.  
  1262.     if(pri != 1000)
  1263.         OldPri = SetTaskPri(ThisProcess,OldPri);
  1264. }
  1265.  
  1266.     /* ConPutc():
  1267.      *
  1268.      *    Output a single character.
  1269.      */
  1270.  
  1271. VOID __stdargs
  1272. ConPutc(struct IOStdReq *Request,UBYTE Char)
  1273. {
  1274.     Request -> io_Command    = CMD_WRITE;
  1275.     Request -> io_Data    = &Char;
  1276.     Request -> io_Length    = 1;
  1277.  
  1278.     DoIO(Request);
  1279. }
  1280.  
  1281.     /* ConPuts():
  1282.      *
  1283.      *    Output a string.
  1284.      */
  1285.  
  1286. VOID
  1287. ConPuts(struct IOStdReq *Request,STRPTR String)
  1288. {
  1289.     Request -> io_Command    = CMD_WRITE;
  1290.     Request -> io_Data    = String;
  1291.     Request -> io_Length    = strlen(String);
  1292.  
  1293.     DoIO(Request);
  1294. }
  1295.  
  1296.     /* ConPrintf():
  1297.      *
  1298.      *    Formatted console output.
  1299.      */
  1300.  
  1301. VOID __stdargs
  1302. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  1303. {
  1304.     STATIC UBYTE Buffer[512];
  1305.  
  1306.     va_list    VarArgs;
  1307.     LONG    Len;
  1308.  
  1309.     va_start(VarArgs,Format);
  1310.     vsprintf(Buffer,Format,VarArgs);
  1311.     va_end(VarArgs);
  1312.  
  1313.     Len = strlen(Buffer);
  1314.  
  1315.     if(Buffer[0] != '\033' && Request == FileRequest)
  1316.     {
  1317.         struct ConUnit *Unit = (struct ConUnit *)Request -> io_Unit;
  1318.  
  1319.         if(Unit -> cu_XCCP + Len > Unit -> cu_XMax)
  1320.         {
  1321.             if((Len = Unit -> cu_XMax - Unit -> cu_XCCP) < 1)
  1322.                 return;
  1323.         }
  1324.     }
  1325.  
  1326.     Request -> io_Command    = CMD_WRITE;
  1327.     Request -> io_Data    = Buffer;
  1328.     Request -> io_Length    = Len;
  1329.  
  1330.     DoIO(Request);
  1331. }
  1332.  
  1333.     /* ConMove():
  1334.      *
  1335.      *    Move the cursor to a new position.
  1336.      */
  1337.  
  1338. VOID
  1339. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  1340. {
  1341.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  1342. }
  1343.  
  1344.     /* ConClear():
  1345.      *
  1346.      *    Clear the console window.
  1347.      */
  1348.  
  1349. VOID
  1350. ConClear(struct IOStdReq *Request)
  1351. {
  1352.     struct ConUnit *ConUnit = (struct ConUnit *)Request -> io_Device;
  1353.     LONG x,y;
  1354.  
  1355.     x = ConUnit -> cu_XCCP;
  1356.     y = ConUnit -> cu_YCCP;
  1357.  
  1358.     ConPrintf(Request,"\033[2J\33[%ld;%ldH",y,x);
  1359. }
  1360.  
  1361.     /* ConGetKey():
  1362.      *
  1363.      *    Read a character from a console window.
  1364.      */
  1365.  
  1366. int
  1367. ConGetKey()
  1368. {
  1369.     if(ConsoleReady)
  1370.     {
  1371.         int Result = ConsoleChar;
  1372.  
  1373.         ConsoleReady = FALSE;
  1374.  
  1375.         ConsoleReadRequest -> io_Command    = CMD_READ;
  1376.         ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1377.         ConsoleReadRequest -> io_Length        = 1;
  1378.  
  1379.         ClrSignal(SIG_CONREAD);
  1380.         SendIO(ConsoleReadRequest);
  1381.  
  1382.         return(Result);
  1383.     }
  1384.     else
  1385.     {
  1386.         int Result = 0;
  1387.  
  1388.         if(WindowReady)
  1389.         {
  1390.             struct IntuiMessage *IntuiMessage;
  1391.             ULONG MsgClass;
  1392.             UWORD MsgCode;
  1393.  
  1394.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
  1395.             {
  1396.                 MsgClass    = IntuiMessage -> Class;
  1397.                 MsgCode        = IntuiMessage -> Code;
  1398.  
  1399.                 ReplyMsg(IntuiMessage);
  1400.  
  1401.                 if(MsgClass == IDCMP_MENUPICK)
  1402.                 {
  1403.                     struct MenuItem *Item;
  1404.  
  1405.                     while(MsgCode != MENUNULL)
  1406.                     {
  1407.                         if(Item = ItemAddress(Menu,MsgCode))
  1408.                         {
  1409.                             if(MENU_USERDATA(Item))
  1410.                             {
  1411.                                 if(!Result)
  1412.                                     Result = (int)MENU_USERDATA(Item);
  1413.                             }
  1414.  
  1415.                             MsgCode = Item -> NextSelect;
  1416.                         }
  1417.                         else
  1418.                             break;
  1419.                     }
  1420.                 }
  1421.             }
  1422.  
  1423.             WindowReady = FALSE;
  1424.         }
  1425.  
  1426.         return(Result);
  1427.     }
  1428. }
  1429.  
  1430.     /* ConScanKey():
  1431.      *
  1432.      *    Check for a keyboard event.
  1433.      */
  1434.  
  1435. int
  1436. ConScanKey()
  1437. {
  1438.     if(ConsoleReady || WindowReady)
  1439.         return(1);
  1440.     else
  1441.     {
  1442.         int Result = 0;
  1443.  
  1444.         if(CheckSignal(SIG_WINDOW))
  1445.         {
  1446.             WindowReady = TRUE;
  1447.  
  1448.             Result = 1;
  1449.         }
  1450.  
  1451.         if(CheckIO(ConsoleReadRequest))
  1452.         {
  1453.             if(!WaitIO(ConsoleReadRequest))
  1454.             {
  1455.                 ConsoleReady = TRUE;
  1456.  
  1457.                 return(1);
  1458.             }
  1459.             else
  1460.             {
  1461.                 ConsoleReadRequest -> io_Command    = CMD_READ;
  1462.                 ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1463.                 ConsoleReadRequest -> io_Length        = 1;
  1464.  
  1465.                 ClrSignal(SIG_CONREAD);
  1466.                 SendIO(ConsoleReadRequest);
  1467.             }
  1468.         }
  1469.  
  1470.         return(Result);
  1471.     }
  1472.  
  1473.     return(0);
  1474. }
  1475.  
  1476.     /* dtr_out(byte flag):
  1477.      *
  1478.      *    If flag == 0 -> drop DTR signal, else set it.
  1479.      */
  1480.  
  1481. VOID
  1482. dtr_out(byte flag)
  1483. {
  1484.     if(!flag && !RendezvousData)
  1485.     {
  1486.         if(ThisBuffer -> IsBusy)
  1487.         {
  1488.             WaitIO(ThisBuffer -> SerialRequest);
  1489.  
  1490.             ThisBuffer -> IsBusy        = FALSE;
  1491.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1492.         }
  1493.  
  1494.         if(ReadBuffer -> IsBusy)
  1495.         {
  1496.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1497.                 AbortIO(ReadBuffer -> SerialRequest);
  1498.  
  1499.             WaitIO(ReadBuffer -> SerialRequest);
  1500.  
  1501.             ReadBuffer -> IsBusy        = FALSE;
  1502.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1503.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1504.  
  1505.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1506.  
  1507.             DoIO(ReadBuffer -> SerialRequest);
  1508.  
  1509.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1510.             {
  1511.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1512.  
  1513.                 if(Size > 0)
  1514.                 {
  1515.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1516.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1517.  
  1518.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1519.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1520.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1521.  
  1522.                     DoIO(ReadBuffer -> SerialRequest);
  1523.  
  1524.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1525.                 }
  1526.             }
  1527.         }
  1528.  
  1529.         CloseDevice(ReadBuffer -> SerialRequest);
  1530.  
  1531.         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1532.         TimeRequest -> tr_time . tv_secs    = 1;
  1533.         TimeRequest -> tr_time . tv_micro    = 0;
  1534.  
  1535.         DoIO(TimeRequest);
  1536.  
  1537.         if(OpenDevice(device,port,ReadBuffer -> SerialRequest,NULL))
  1538.         {
  1539.             CloseAll();
  1540.  
  1541.             exit(10);
  1542.         }
  1543.         else
  1544.         {
  1545.             ReadBuffer -> SerialRequest -> io_Baud        = ThisBuffer -> SerialRequest -> io_Baud;
  1546.             ReadBuffer -> SerialRequest -> io_ReadLen    = ThisBuffer -> SerialRequest -> io_ReadLen;
  1547.             ReadBuffer -> SerialRequest -> io_WriteLen    = ThisBuffer -> SerialRequest -> io_WriteLen;
  1548.             ReadBuffer -> SerialRequest -> io_SerFlags    = ThisBuffer -> SerialRequest -> io_SerFlags;
  1549.  
  1550.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1551.  
  1552.             DoIO(ReadBuffer -> SerialRequest);
  1553.  
  1554.             CopyMem(ReadBuffer -> SerialRequest,ThisBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1555.  
  1556.             ThisBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1557.  
  1558.             CopyMem(ReadBuffer -> SerialRequest,NextBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1559.  
  1560.             NextBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1561.         }
  1562.     }
  1563. }
  1564.  
  1565.     /* com_flow(byte flags):
  1566.      *
  1567.      *    The bit mask `flags' determines the style(s) of
  1568.      *    handshaking:
  1569.      *
  1570.      *    if (flags & 9) -> enable xON/xOFF software handshaking,
  1571.      *    if (flags & 2) -> enable RTS/CTS hardware handshaking
  1572.      */
  1573.  
  1574. VOID
  1575. com_flow(byte flags)
  1576. {
  1577.     if(ThisBuffer -> IsBusy)
  1578.     {
  1579.         WaitIO(ThisBuffer -> SerialRequest);
  1580.  
  1581.         ThisBuffer -> IsBusy        = FALSE;
  1582.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1583.     }
  1584.  
  1585.     if(ReadBuffer -> IsBusy)
  1586.     {
  1587.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1588.             AbortIO(ReadBuffer -> SerialRequest);
  1589.  
  1590.         WaitIO(ReadBuffer -> SerialRequest);
  1591.  
  1592.         ReadBuffer -> IsBusy        = FALSE;
  1593.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1594.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1595.  
  1596.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1597.  
  1598.         DoIO(ReadBuffer -> SerialRequest);
  1599.  
  1600.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1601.         {
  1602.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1603.  
  1604.             if(Size > 0)
  1605.             {
  1606.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1607.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1608.  
  1609.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1610.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1611.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1612.  
  1613.                 DoIO(ReadBuffer -> SerialRequest);
  1614.  
  1615.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1616.             }
  1617.         }
  1618.     }
  1619.  
  1620.     if(flags & 2)
  1621.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_7WIRE;
  1622.     else
  1623.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_7WIRE;
  1624.  
  1625.     if(flags & 9)
  1626.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_XDISABLED;
  1627.     else
  1628.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_XDISABLED;
  1629.  
  1630.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1631.  
  1632.     DoIO(ReadBuffer -> SerialRequest);
  1633.  
  1634.     ThisBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1635.     NextBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1636. }
  1637.  
  1638.     /* com_setspeed(word speed):
  1639.      *
  1640.      *    Set the transfer speed (in bits/second).
  1641.      */
  1642.  
  1643. VOID
  1644. com_setspeed(word speed)
  1645. {
  1646.     if(ThisBuffer -> IsBusy)
  1647.     {
  1648.         WaitIO(ThisBuffer -> SerialRequest);
  1649.  
  1650.         ThisBuffer -> IsBusy        = FALSE;
  1651.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1652.     }
  1653.  
  1654.     if(ReadBuffer -> IsBusy)
  1655.     {
  1656.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1657.             AbortIO(ReadBuffer -> SerialRequest);
  1658.  
  1659.         WaitIO(ReadBuffer -> SerialRequest);
  1660.  
  1661.         ReadBuffer -> IsBusy        = FALSE;
  1662.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1663.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1664.  
  1665.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1666.  
  1667.         DoIO(ReadBuffer -> SerialRequest);
  1668.  
  1669.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1670.         {
  1671.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1672.  
  1673.             if(Size > 0)
  1674.             {
  1675.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1676.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1677.  
  1678.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1679.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1680.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1681.  
  1682.                 DoIO(ReadBuffer -> SerialRequest);
  1683.  
  1684.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1685.             }
  1686.         }
  1687.     }
  1688.  
  1689.     ReadBuffer -> SerialRequest -> io_Baud = speed;
  1690.  
  1691.     if(parity)
  1692.     {
  1693.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 7;
  1694.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_PARTY_ON;
  1695.     }
  1696.     else
  1697.     {
  1698.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 8;
  1699.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_PARTY_ON;
  1700.     }
  1701.  
  1702.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1703.  
  1704.     DoIO(ReadBuffer -> SerialRequest);
  1705.  
  1706.     ThisBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1707.     ThisBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1708.     ThisBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1709.     ThisBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1710.  
  1711.     NextBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1712.     NextBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1713.     NextBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1714.     NextBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1715. }
  1716.  
  1717.     /* com_putblock(byte *s,word len):
  1718.      *
  1719.      *    Send a data block asynchronously.
  1720.      */
  1721.  
  1722. VOID
  1723. com_putblock(byte *s,word len)
  1724. {
  1725.     struct SerialBuffer *Swap = ThisBuffer;
  1726.  
  1727.     if(ThisBuffer -> IsBusy)
  1728.         WaitIO(ThisBuffer -> SerialRequest);
  1729.     else
  1730.     {
  1731.         if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1732.         {
  1733.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1734.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1735.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1736.  
  1737.             DoIO(ThisBuffer -> SerialRequest);
  1738.         }
  1739.     }
  1740.  
  1741.     ThisBuffer -> IsBusy        = FALSE;
  1742.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1743.  
  1744.     ThisBuffer = NextBuffer;
  1745.     NextBuffer = Swap;
  1746.  
  1747.     if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1748.     {
  1749.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1750.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1751.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1752.  
  1753.         DoIO(ThisBuffer -> SerialRequest);
  1754.     }
  1755.  
  1756.     ThisBuffer -> IsBusy        = FALSE;
  1757.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1758.  
  1759.     while(len > 2 * ThisBuffer -> SerialSize)
  1760.     {
  1761.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1762.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = s;
  1763.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialSize;
  1764.  
  1765.         s    += ThisBuffer -> SerialSize;
  1766.         len    -= ThisBuffer -> SerialSize;
  1767.  
  1768.         DoIO(ThisBuffer -> SerialRequest);
  1769.     }
  1770.  
  1771.     CopyMem(s,ThisBuffer -> SerialBuffer,MIN(len,ThisBuffer -> SerialSize));
  1772.  
  1773.     ThisBuffer -> IsBusy                    = TRUE;
  1774.     ThisBuffer -> SerialIndex                = ThisBuffer -> SerialBuffer + MIN(len,ThisBuffer -> SerialSize);
  1775.     ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1776.     ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1777.     ThisBuffer -> SerialRequest -> IOSer . io_Length    = MIN(len,ThisBuffer -> SerialSize);
  1778.  
  1779.     len    -= ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1780.     s    += ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1781.  
  1782.     ClrSignal(SIG_SERWRITE);
  1783.     SendIO(ThisBuffer -> SerialRequest);
  1784.  
  1785.     if(len > 0)
  1786.     {
  1787.         CopyMem(s,NextBuffer -> SerialBuffer,len);
  1788.  
  1789.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer + len;
  1790.     }
  1791. }
  1792.  
  1793.     /* breakfunc():
  1794.      *
  1795.      *    Cleanup routine for SAS/C.
  1796.      */
  1797.  
  1798. static int
  1799. breakfunc(void)
  1800. {
  1801.     CloseAll();
  1802.  
  1803.     return(1);
  1804. }
  1805.  
  1806.     /* sys_init(VOID):
  1807.      *
  1808.      *    Initialize this driver implementation.
  1809.      */
  1810.  
  1811. VOID
  1812. sys_init(VOID)
  1813. {
  1814.     if(!OpenAll(device,port))
  1815.     {
  1816.         CloseAll();
  1817.  
  1818.         endprog(2);
  1819.     }
  1820.  
  1821.     onbreak(breakfunc);
  1822. }
  1823.  
  1824.     /* sys_reset(VOID):
  1825.      *
  1826.      *    Perform cleanup for this driver implementation.
  1827.      */
  1828.  
  1829. VOID
  1830. sys_reset(VOID)
  1831. {
  1832.     CloseAll();
  1833. }
  1834.  
  1835.     /* sys_idle(VOID):
  1836.      *
  1837.      *    This routine gets called when the system is idle.
  1838.      *    That's a nice one. We are supposed to call the
  1839.      *    system scheduler, etc.
  1840.      */
  1841.  
  1842. VOID
  1843. sys_idle(VOID)
  1844. {
  1845.     ULONG Signals;
  1846.  
  1847.     if(ReadBuffer -> SerialFilled <= 0 && !ReadBuffer -> IsBusy)
  1848.     {
  1849.         ReadBuffer -> IsBusy                    = TRUE;
  1850.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1851.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1852.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1853.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1854.  
  1855.         ClrSignal(SIG_SERREAD);
  1856.         SendIO(ReadBuffer -> SerialRequest);
  1857.     }
  1858.  
  1859.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1860.     TimeRequest -> tr_time . tv_secs    = 1;
  1861.     TimeRequest -> tr_time . tv_micro    = 0;
  1862.  
  1863.     ClrSignal(SIG_TIMER);
  1864.     SendIO(TimeRequest);
  1865.  
  1866.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1867.  
  1868.     if(!(Signals & SIG_TIMER))
  1869.     {
  1870.         if(!CheckIO(TimeRequest))
  1871.             AbortIO(TimeRequest);
  1872.     }
  1873.  
  1874.     WaitIO(TimeRequest);
  1875.  
  1876.     if(Signals & SIG_SERREAD)
  1877.     {
  1878.         WaitIO(ReadBuffer -> SerialRequest);
  1879.  
  1880.         ReadBuffer -> IsBusy        = FALSE;
  1881.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1882.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1883.  
  1884.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1885.  
  1886.         DoIO(ReadBuffer -> SerialRequest);
  1887.  
  1888.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1889.         {
  1890.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1891.  
  1892.             if(Size > 0)
  1893.             {
  1894.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1895.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1896.  
  1897.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1898.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1899.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1900.  
  1901.                 DoIO(ReadBuffer -> SerialRequest);
  1902.  
  1903.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1904.             }
  1905.         }
  1906.     }
  1907.  
  1908.     if(Signals & SIG_SERWRITE)
  1909.     {
  1910.         struct SerialBuffer *Swap = ThisBuffer;
  1911.  
  1912.         WaitIO(ThisBuffer -> SerialRequest);
  1913.  
  1914.         ThisBuffer -> IsBusy        = FALSE;
  1915.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1916.  
  1917.         ThisBuffer = NextBuffer;
  1918.         NextBuffer = Swap;
  1919.     }
  1920.  
  1921.     if(Signals & SIG_CONREAD)
  1922.     {
  1923.         WaitIO(ConsoleReadRequest);
  1924.  
  1925.         ConsoleReady = TRUE;
  1926.     }
  1927.  
  1928.     if(Signals & SIG_WINDOW)
  1929.         WindowReady = TRUE;
  1930. }
  1931.  
  1932.     /* com_outfull(VOID):
  1933.      *
  1934.      *    Return number of bytes still to be transferred.
  1935.      */
  1936.  
  1937. int
  1938. com_outfull(VOID)
  1939. {
  1940.     return(ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer + NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer);
  1941. }
  1942.  
  1943.     /* carrier(VOID):
  1944.      *
  1945.      *    Return current carrier status.
  1946.      */
  1947.  
  1948. int
  1949. carrier(VOID)
  1950. {
  1951.     if(nocarrier)
  1952.         return(1);
  1953.     else
  1954.     {
  1955.         if(!ThisBuffer -> IsBusy)
  1956.         {
  1957.             ThisBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1958.  
  1959.             DoIO(ThisBuffer -> SerialRequest);
  1960.  
  1961.             if(ThisBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1962.                 return(0);
  1963.             else
  1964.                 return(1);
  1965.         }
  1966.         else
  1967.         {
  1968.             NextBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1969.  
  1970.             DoIO(NextBuffer -> SerialRequest);
  1971.  
  1972.             if(NextBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1973.                 return(0);
  1974.             else
  1975.                 return(1);
  1976.         }
  1977.     }
  1978. }
  1979.  
  1980.     /* com_flush(VOID):
  1981.      *
  1982.      *    Make sure all pending data gets written.
  1983.      */
  1984.  
  1985. VOID
  1986. com_flush(VOID)
  1987. {
  1988.     if(ThisBuffer -> IsBusy)
  1989.     {
  1990.         WaitIO(ThisBuffer -> SerialRequest);
  1991.  
  1992.         ThisBuffer -> IsBusy        = FALSE;
  1993.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1994.     }
  1995.  
  1996.     if(NextBuffer -> SerialIndex > NextBuffer -> SerialBuffer)
  1997.     {
  1998.         NextBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1999.         NextBuffer -> SerialRequest -> IOSer . io_Data        = NextBuffer -> SerialBuffer;
  2000.         NextBuffer -> SerialRequest -> IOSer . io_Length    = NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer;
  2001.  
  2002.         DoIO(NextBuffer -> SerialRequest);
  2003.  
  2004.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer;
  2005.     }
  2006. }
  2007.  
  2008.     /* com_putbyte(byte c):
  2009.      *
  2010.      *    Transmit a single byte, queueing it if necessary.
  2011.      */
  2012.  
  2013. VOID
  2014. com_putbyte(byte c)
  2015. {
  2016.     if(ThisBuffer -> IsBusy)
  2017.     {
  2018.         if(NextBuffer -> SerialIndex + 1 >= NextBuffer -> SerialTop)
  2019.         {
  2020.             struct SerialBuffer *Swap = ThisBuffer;
  2021.  
  2022.             WaitIO(ThisBuffer -> SerialRequest);
  2023.  
  2024.             ThisBuffer -> IsBusy        = FALSE;
  2025.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2026.  
  2027.             ThisBuffer = NextBuffer;
  2028.             NextBuffer = Swap;
  2029.  
  2030.             ThisBuffer -> IsBusy                    = TRUE;
  2031.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2032.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2033.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  2034.  
  2035.             ClrSignal(SIG_SERWRITE);
  2036.             SendIO(ThisBuffer -> SerialRequest);
  2037.         }
  2038.  
  2039.         *NextBuffer -> SerialIndex++ = c;
  2040.     }
  2041.     else
  2042.     {
  2043.         if(ThisBuffer -> SerialIndex + 1 < ThisBuffer -> SerialTop)
  2044.         {
  2045.             *ThisBuffer -> SerialIndex++ = c;
  2046.  
  2047.             ThisBuffer -> IsBusy                    = TRUE;
  2048.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2049.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2050.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2051.  
  2052.             ClrSignal(SIG_SERWRITE);
  2053.             SendIO(ThisBuffer -> SerialRequest);
  2054.         }
  2055.         else
  2056.         {
  2057.             ThisBuffer -> IsBusy                    = TRUE;
  2058.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2059.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2060.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  2061.  
  2062.             ClrSignal(SIG_SERWRITE);
  2063.             SendIO(ThisBuffer -> SerialRequest);
  2064.  
  2065.             *NextBuffer -> SerialIndex++ = c;
  2066.         }
  2067.     }
  2068. }
  2069.  
  2070.     /* com_purge(VOID):
  2071.      *
  2072.      *    Clear the read/write buffers.
  2073.      */
  2074.  
  2075. VOID
  2076. com_purge(VOID)
  2077. {
  2078.     if(ThisBuffer -> IsBusy)
  2079.     {
  2080.         if(!CheckIO(ThisBuffer -> SerialRequest))
  2081.             AbortIO(ThisBuffer -> SerialRequest);
  2082.  
  2083.         WaitIO(ThisBuffer -> SerialRequest);
  2084.     }
  2085.  
  2086.     ThisBuffer -> IsBusy        = FALSE;
  2087.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2088.  
  2089.     NextBuffer -> IsBusy        = FALSE;
  2090.     NextBuffer -> SerialIndex    = NextBuffer -> SerialBuffer;
  2091.  
  2092.     if(ReadBuffer -> IsBusy)
  2093.     {
  2094.         if(!CheckIO(ReadBuffer -> SerialRequest))
  2095.             AbortIO(ReadBuffer -> SerialRequest);
  2096.  
  2097.         WaitIO(ReadBuffer -> SerialRequest);
  2098.     }
  2099.  
  2100.     ReadBuffer -> IsBusy        = FALSE;
  2101.     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2102.     ReadBuffer -> SerialFilled    = 0;
  2103.  
  2104.     ThisBuffer -> SerialRequest -> IOSer . io_Command = CMD_CLEAR;
  2105.     DoIO(ThisBuffer -> SerialRequest);
  2106. }
  2107.  
  2108.     /* com_dump(VOID):
  2109.      *
  2110.      *    Wait for asynchronous write request to terminate.
  2111.      */
  2112.  
  2113. VOID
  2114. com_dump(VOID)
  2115. {
  2116.     com_flush();
  2117. }
  2118.  
  2119.     /* com_getbyte(VOID):
  2120.      *
  2121.      *    Read a single byte from the serial line. If not available,
  2122.      *    return EOF.
  2123.      */
  2124.  
  2125. int
  2126. com_getbyte(VOID)
  2127. {
  2128.     int Result;
  2129.  
  2130.     if(ReadBuffer -> SerialFilled <= 0)
  2131.     {
  2132.         if(ReadBuffer -> IsBusy)
  2133.         {
  2134.             if(!CheckIO(ReadBuffer -> SerialRequest))
  2135.                 return(EOF);
  2136.             else
  2137.                 WaitIO(ReadBuffer -> SerialRequest);
  2138.  
  2139.             ReadBuffer -> IsBusy        = FALSE;
  2140.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2141.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2142.  
  2143.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2144.  
  2145.             DoIO(ReadBuffer -> SerialRequest);
  2146.  
  2147.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2148.             {
  2149.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  2150.  
  2151.                 if(Size > 0)
  2152.                 {
  2153.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2154.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2155.  
  2156.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2157.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  2158.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  2159.  
  2160.                     DoIO(ReadBuffer -> SerialRequest);
  2161.  
  2162.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2163.                 }
  2164.             }
  2165.         }
  2166.         else
  2167.         {
  2168.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2169.  
  2170.             DoIO(ReadBuffer -> SerialRequest);
  2171.  
  2172.             if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2173.                 return(EOF);
  2174.             else
  2175.             {
  2176.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2177.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2178.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = MIN(ReadBuffer -> SerialRequest -> IOSer . io_Actual,ReadBuffer -> SerialSize);
  2179.  
  2180.                 DoIO(ReadBuffer -> SerialRequest);
  2181.  
  2182.                 if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2183.                     return(EOF);
  2184.                 else
  2185.                 {
  2186.                     ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2187.                     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2188.                 }
  2189.             }
  2190.         }
  2191.     }
  2192.  
  2193.     Result = *ReadBuffer -> SerialIndex++;
  2194.  
  2195.     ReadBuffer -> SerialFilled--;
  2196.  
  2197.     if(ReadBuffer -> SerialFilled <= 0)
  2198.     {
  2199.         ReadBuffer -> IsBusy                    = TRUE;
  2200.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  2201.  
  2202.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2203.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2204.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2205.  
  2206.         ClrSignal(SIG_SERREAD);
  2207.         SendIO(ReadBuffer -> SerialRequest);
  2208.     }
  2209.  
  2210.     return(Result);
  2211. }
  2212.  
  2213.     /* setstamp(STRPTR Name,LONG Time):
  2214.      *
  2215.      *    Set time/date of a file.
  2216.      */
  2217.  
  2218. VOID
  2219. setstamp(char *Name,long Time)
  2220. {
  2221.     struct DateStamp    Date;
  2222.     ULONG            Seconds;
  2223.  
  2224.     DB(kprintf("setstamp |%s| %ld\n",Name,Time));
  2225.  
  2226.         /* Translate it into an Amiga date. */
  2227.  
  2228.     if(Time > GMT_Offset)
  2229.         Seconds = Time - GMT_Offset;
  2230.     else
  2231.         Seconds = 0;
  2232.  
  2233.     Date . ds_Days        = Seconds / (24 * 60 * 60);
  2234.     Date . ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  2235.     Date . ds_Tick        = (Seconds % 60) * TICKS_PER_SECOND;
  2236.  
  2237.     SetFileDate(Name,&Date);
  2238. }
  2239.  
  2240.     /* freespace(STRPTR DrivePath):
  2241.      *
  2242.      *    Get free disk space for specified drive.
  2243.      */
  2244.  
  2245. long
  2246. freespace(char *DrivePath)
  2247. {
  2248.     struct DevProc    *DevProc = GetDeviceProc(DrivePath,NULL);
  2249.     struct DosList    *DosList;
  2250.     BOOL         GoodDevice = FALSE;
  2251.     LONG         Size = (LONG)((ULONG)~0 >> 2);
  2252.  
  2253.     if(!DrivePath)
  2254.         DrivePath = "";
  2255.  
  2256.     DB(kprintf("freespace |%s|\n",DrivePath));
  2257.  
  2258.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  2259.     {
  2260.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  2261.         {
  2262.             if(DosList -> dol_Task == DevProc -> dvp_Port)
  2263.             {
  2264.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList -> dol_misc . dol_handler . dol_Startup);
  2265.  
  2266.                 if(TypeOfMem(FSSM))
  2267.                 {
  2268.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM -> fssm_Environ);
  2269.                     STRPTR Name = (STRPTR)BADDR(FSSM -> fssm_Device);
  2270.  
  2271.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  2272.                     {
  2273.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  2274.                         {
  2275.                             struct IOStdReq __aligned IORequest;
  2276.  
  2277.                             if(!OpenDevice(Name + 1,FSSM -> fssm_Unit,&IORequest,FSSM -> fssm_Unit))
  2278.                             {
  2279.                                 CloseDevice(&IORequest);
  2280.  
  2281.                                 if(DosEnvec -> de_TableSize > 0 && DosEnvec -> de_LowCyl <= DosEnvec -> de_HighCyl)
  2282.                                     GoodDevice = TRUE;
  2283.                             }
  2284.                         }
  2285.                     }
  2286.                 }
  2287.             }
  2288.         }
  2289.  
  2290.         UnLockDosList(LDF_DEVICES | LDF_READ);
  2291.     }
  2292.  
  2293.     FreeDeviceProc(DevProc);
  2294.  
  2295.     if(GoodDevice)
  2296.     {
  2297.         struct InfoData *InfoData;
  2298.  
  2299.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  2300.         {
  2301.             UBYTE NewName[256],*Index;
  2302.             BPTR FileLock;
  2303.  
  2304.             memcpy(NewName,DrivePath,255);
  2305.  
  2306.             NewName[255] = 0;
  2307.  
  2308.             Index = PathPart(NewName);
  2309.  
  2310.             *Index = 0;
  2311.  
  2312.             FileLock = Lock(NewName,ACCESS_READ);
  2313.  
  2314.             if(FileLock)
  2315.             {
  2316.                 if(Info(FileLock,InfoData))
  2317.                     Size = InfoData -> id_BytesPerBlock * (InfoData -> id_NumBlocks - InfoData -> id_NumBlocksUsed);
  2318.  
  2319.                 UnLock(FileLock);
  2320.             }
  2321.  
  2322.             FreeVec(InfoData);
  2323.         }
  2324.     }
  2325.  
  2326.     return(Size);
  2327. }
  2328.  
  2329.     /* ffirst(char *FileSpec):
  2330.      *
  2331.      *    Return name of first file matching the given specs.
  2332.      */
  2333.  
  2334. char *
  2335. ffirst(char *filespec)
  2336. {
  2337.     AnchorUsed = TRUE;
  2338.  
  2339.     DB(kprintf("ffirst |%s|\n",filespec));
  2340.  
  2341.     if(MatchFirst(filespec,Anchor))
  2342.         return(NULL);
  2343.     else
  2344.         return((char *)Anchor -> ap_Buf);
  2345. }
  2346.  
  2347.     /* fnext(VOID):
  2348.      *
  2349.      *    Return name of next file matching the given specs.
  2350.      */
  2351.  
  2352. char *
  2353. fnext(VOID)
  2354. {
  2355.     AnchorUsed = TRUE;
  2356.  
  2357.     DB(kprintf("fnext\n"));
  2358.  
  2359.     if(MatchNext(Anchor))
  2360.         return(NULL);
  2361.     else
  2362.         return((char *)Anchor -> ap_Buf);
  2363. }
  2364.  
  2365.     /* time(time_t *timeptr):
  2366.      *
  2367.      *    Get the current time.
  2368.      */
  2369.  
  2370. time_t
  2371. time(time_t *timeptr)
  2372. {
  2373.     struct timeval    Now;
  2374.     time_t        CurrentTime;
  2375.  
  2376.     DB(kprintf("time 0x%08lx\n",timeptr));
  2377.  
  2378.         /* If the timer is already available,
  2379.          * just read the time. Otherwise, open what
  2380.          * we need to tell the time.
  2381.          */
  2382.  
  2383.     if(TimerBase)
  2384.         GetSysTime(&Now);
  2385.     else
  2386.         UpdateTime(&Now);
  2387.  
  2388.         /* Determine the current time, taking the time
  2389.          * zone into account.
  2390.          */
  2391.  
  2392.     CurrentTime = (time_t)(Now . tv_secs + GMT_Offset);
  2393.  
  2394.     if(timeptr)
  2395.         *timeptr = CurrentTime;
  2396.  
  2397.     return(CurrentTime);
  2398. }
  2399.  
  2400.     /* localtime(const time_t *t):
  2401.      *
  2402.      *    Convert UTC into local time.
  2403.      */
  2404.  
  2405. struct tm *
  2406. localtime(const time_t *t)
  2407. {
  2408.     STATIC struct tm Time;
  2409.  
  2410.     ULONG            Seconds,
  2411.                 Delta;
  2412.     struct ClockData    ClockData;
  2413.     BOOL            CloseIt = FALSE;
  2414.  
  2415.     DB(kprintf("localtime 0x%08lx\n",t));
  2416.  
  2417.         /* We need utility.library for the date conversion. */
  2418.  
  2419.     if(!UtilityBase)
  2420.     {
  2421.         if(UtilityBase = OpenLibrary("utility.library",37))
  2422.             CloseIt = TRUE;
  2423.     }
  2424.  
  2425.         /* Any luck? */
  2426.  
  2427.     if(!UtilityBase)
  2428.     {
  2429.         memset(&Time,0,sizeof(struct tm));
  2430.  
  2431.         return(&Time);
  2432.     }
  2433.  
  2434.         /* Update the time data. */
  2435.  
  2436.     if(!TimerBase)
  2437.         UpdateTime(NULL);
  2438.  
  2439.         /* Add the offset. */
  2440.  
  2441.     if(*t < GMT_Offset)
  2442.         Seconds = 0;
  2443.     else
  2444.         Seconds = (ULONG)*t - GMT_Offset;
  2445.  
  2446.         /* Convert the seconds into time data. */
  2447.  
  2448.     Amiga2Date(Seconds,&ClockData);
  2449.  
  2450.         /* Convert the time data. */
  2451.  
  2452.     Time . tm_sec    = ClockData . sec;
  2453.     Time . tm_min    = ClockData . min;
  2454.     Time . tm_hour    = ClockData . hour;
  2455.     Time . tm_mday    = ClockData . mday;
  2456.     Time . tm_mon    = ClockData . month - 1;
  2457.     Time . tm_year    = ClockData . year - 1900;
  2458.     Time . tm_wday    = ClockData . wday;
  2459.  
  2460.         /* No daylight savings time info is provided. */
  2461.  
  2462.     Time . tm_isdst = 0;
  2463.  
  2464.         /* We will need to fill in the yday entry. */
  2465.  
  2466.     ClockData . mday    = 1;
  2467.     ClockData . month    = 1;
  2468.  
  2469.     Delta = Date2Amiga(&ClockData);
  2470.  
  2471.     Time . tm_yday = (Seconds - Delta) / (24 * 60 * 60) + 1;
  2472.  
  2473.         /* Clean up if necessary. */
  2474.  
  2475.     if(CloseIt)
  2476.     {
  2477.         CloseLibrary(UtilityBase);
  2478.  
  2479.         UtilityBase = NULL;
  2480.     }
  2481.  
  2482.     return(&Time);
  2483. }
  2484.  
  2485.     /* stat(const char *file,struct stat *st):
  2486.      *
  2487.      *    Get information on a file.
  2488.      */
  2489.  
  2490. int
  2491. stat(const char *file,struct stat *st)
  2492. {
  2493.     BPTR FileLock;
  2494.  
  2495.     DB(kprintf("stat |%s| 0%08lx\n",file,st));
  2496.  
  2497.         /* Try to get a lock on the file. */
  2498.  
  2499.     if(FileLock = Lock((STRPTR)file,ACCESS_READ))
  2500.     {
  2501.         STATIC char    Volume[256],
  2502.                 Comment[80];
  2503.  
  2504.         struct FileInfoBlock __aligned    FileInfo;
  2505.         struct InfoData __aligned    InfoData;
  2506.  
  2507.             /* Get information on file and filing system. */
  2508.  
  2509.         if(Examine(FileLock,&FileInfo) && Info(FileLock,&InfoData))
  2510.         {
  2511.             unsigned short mode = 0;
  2512.  
  2513.                 /* Try to get the name of the volume. */
  2514.  
  2515.             if(!NameFromLock(FileLock,Volume,256))
  2516.                 Volume[0] = 0;
  2517.             else
  2518.             {
  2519.                 WORD i;
  2520.  
  2521.                     /* Chop off everything after the colon. */
  2522.  
  2523.                 for(i = 0 ; i < 256 ; i++)
  2524.                 {
  2525.                     if(Volume[i] == ':')
  2526.                     {
  2527.                         Volume[i + 1] = 0;
  2528.  
  2529.                         break;
  2530.                     }
  2531.                 }
  2532.             }
  2533.  
  2534.             UnLock(FileLock);
  2535.  
  2536.                 /* Build the protection bits. */
  2537.  
  2538.             if(!(FileInfo . fib_Protection & FIBF_EXECUTE))
  2539.                 mode |= S_IEXECUTE;
  2540.  
  2541.             if(!(FileInfo . fib_Protection & FIBF_DELETE))
  2542.                 mode |= S_IDELETE;
  2543.  
  2544.             if(!(FileInfo . fib_Protection & FIBF_READ))
  2545.                 mode |= S_IREAD;
  2546.  
  2547.             if(!(FileInfo . fib_Protection & FIBF_WRITE))
  2548.                 mode |= S_IWRITE;
  2549.  
  2550.             if(!(FileInfo . fib_Protection & FIBF_ARCHIVE))
  2551.                 mode |= S_IARCHIVE;
  2552.  
  2553.             if(FileInfo . fib_Protection & FIBF_PURE)
  2554.                 mode |= S_IPURE;
  2555.  
  2556.             if(FileInfo . fib_Protection & FIBF_SCRIPT)
  2557.                 mode |= S_ISCRIPT;
  2558.  
  2559.                 /* Keep the comment. */
  2560.  
  2561.             strcpy(Comment,FileInfo . fib_Comment);
  2562.  
  2563.                 /* Fix the time if necessary. */
  2564.  
  2565.             if(!TimerBase)
  2566.                 UpdateTime(NULL);
  2567.  
  2568.                 /* Fill in the data. */
  2569.  
  2570.             st -> st_mode    = mode;
  2571.             st -> st_ino    = FileInfo . fib_DiskKey;
  2572.             st -> st_dev    = InfoData . id_DiskType;
  2573.             st -> st_rdev    = Volume;
  2574.             st -> st_nlink    = FileInfo . fib_DirEntryType == ST_SOFTLINK || FileInfo . fib_DirEntryType == ST_LINKDIR || FileInfo . fib_DirEntryType == ST_LINKFILE;
  2575.             st -> st_uid    = FileInfo . fib_OwnerUID;
  2576.             st -> st_gid    = FileInfo . fib_OwnerGID;
  2577.             st -> st_size    = FileInfo . fib_Size;
  2578.             st -> st_atime    = GMT_Offset + (FileInfo . fib_Date . ds_Days * 24 * 60 + FileInfo . fib_Date . ds_Minute) * 60 + FileInfo . fib_Date . ds_Tick / TICKS_PER_SECOND;
  2579.             st -> st_mtime    = st -> st_atime;
  2580.             st -> st_ctime    = st -> st_atime;
  2581.             st -> st_type    = FileInfo . fib_DirEntryType;
  2582.             st -> st_comment= Comment;
  2583.  
  2584.                 /* Success. */
  2585.  
  2586.             return(0);
  2587.         }
  2588.  
  2589.         UnLock(FileLock);
  2590.     }
  2591.  
  2592.         /* What else should I choose? */
  2593.  
  2594.     errno = _OSERR = EIO;
  2595.  
  2596.     return(-1);
  2597. }
  2598.