home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
550b.lha
/
Term_v1.8a
/
Source.LZH
/
termAux.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-20
|
49KB
|
2,493 lines
/* $Revision Header * Header built automatically - do not edit! *************
*
* (C) Copyright 1990 by Olaf 'Olsen' Barthel & MXM
*
* Name .....: TermAux.c
* Created ..: Monday 21-Jan-91 20:12
* Revision .: 0
*
* Date Author Comment
* ========= ======== ====================
* 21-Jan-91 Olsen Created this file!
*
* $Revision Header ********************************************************/
#include "TermGlobal.h"
/* The following static strings are displayed in the status
* window.
*/
STATIC UBYTE *ConfigFont[2] =
{
"Topaz",
"IBM "
};
STATIC UBYTE *ConfigEmulation[3] =
{
"ANSI/VT",
"Atomic ",
"TTY "
};
STATIC UBYTE *ConfigParity[5] =
{
"None",
"Even",
"Odd ",
"Mark",
"Spac"
};
STATIC UBYTE *ConfigStatus[7] =
{
"Ready ",
"Holding ",
"Dialing ",
"Upload ",
"Download",
"Breaking",
"Hang Up "
};
/* Block window nest count. */
STATIC SHORT BlockNestCount;
/* GetConUnit():
*
* Extract the ConUnit pointer from the current output stream
* console.
*/
struct ConUnit *
GetConUnit(struct MsgPort *ConsoleTask)
{
struct InfoData *InfoData;
struct ConUnit *ConUnit = NULL;
if(!ConsoleTask)
ConsoleTask = (struct MsgPort *)((struct Process *)SysBase -> ThisTask) -> pr_ConsoleTask;
if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR))
{
/* Send the inquiry packet to the console task. */
if(DoPkt1(ConsoleTask,ACTION_DISK_INFO,MKBADDR(InfoData)))
ConUnit = (struct ConUnit *)((struct IOStdReq *)InfoData -> id_InUse) -> io_Unit;
FreeVec(InfoData);
}
return(ConUnit);
}
/* AddDownloadObject(UBYTE *Line):
*
* Add another downloaded object to the list.
*/
VOID
AddDownloadObject(UBYTE *Line)
{
struct Node *SomeNode;
/* Allocate space for the node itself and the
* string to be put into the node name.
*/
if(SomeNode = (struct Node *)AllocVec(sizeof(struct Node) + strlen(Line) + 1,MEMF_PUBLIC|MEMF_CLEAR))
{
/* Block list modification. */
ObtainSemaphore(DownloadSemaphore);
/* Enter the name. */
SomeNode -> ln_Name = (UBYTE *)(SomeNode + 1);
/* Copy the line over. */
strcpy(SomeNode -> ln_Name,Line);
/* Add it to the list. */
AddTail(&DownloadList,SomeNode);
/* Increment number of downloads. */
DownloadLineCount++;
ReleaseSemaphore(DownloadSemaphore);
}
}
/* ClearDownloadObjects():
*
* Clear the list of downloaded objects.
*/
VOID
ClearDownloadObjects()
{
struct Node *SomeNode,*NextNode;
ObtainSemaphore(DownloadSemaphore);
SomeNode = DownloadList . lh_Head;
while(SomeNode -> ln_Succ)
{
NextNode = SomeNode -> ln_Succ;
Remove(SomeNode);
FreeVec(SomeNode);
SomeNode = NextNode;
}
DownloadNode = NULL;
DownloadLineCount = 0;
ReleaseSemaphore(DownloadSemaphore);
}
/* SequenceFilter(UBYTE Char):
*
* Yet another byte sequence filter, this time it's the
* ARexx interface to make the call.
*/
struct ScanNode *
SequenceFilter(UBYTE Char)
{
struct ScanNode *SomeNode,*Matching = NULL;
BYTE Matches = 0;
/* Convert input character to upper case. */
Char = ToUpper(Char);
/* Get the first node in the list. */
SomeNode = (struct ScanNode *)SequenceList . lh_Head;
/* Scan until the last node is found. */
while(SomeNode -> Node . mln_Succ)
{
/* This sequence had a couple of matches. */
if(SomeNode -> Count == SequenceCount)
{
/* The next character in the sequence
* still matches.
*/
if(Char == SomeNode -> Sequence[SequenceCount])
{
/* Increase number of matching
* characters.
*/
SomeNode -> Count++;
/* If there's another character
* in the sequence, increase
* the match counter.
*/
if(SomeNode -> Sequence[SequenceCount + 1])
Matches++;
else
{
/* We were able to make
* a perfect match.
*/
Matches = 0;
Matching = SomeNode;
}
}
}
/* Skip to the next node. */
SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
}
if(!Matches)
{
/* Clear the list entry counters. */
if(SequenceCount)
{
SomeNode = (struct ScanNode *)SequenceList . lh_Head;
while(SomeNode -> Node . mln_Succ)
{
SomeNode -> Count = 0;
SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
}
SequenceCount = 0;
}
}
else
SequenceCount++;
return(Matching);
}
/* AddSequenceObject(UBYTE *Sequence):
*
* Add another sequence to the list of byte sequences
* the routine above will look at whilst parsing.
*/
VOID
AddSequenceObject(UBYTE *Sequence)
{
struct ScanNode *SomeNode;
if(SomeNode = AllocVec(sizeof(struct ScanNode) + strlen(Sequence) + 1,MEMF_PUBLIC|MEMF_CLEAR))
{
SHORT i;
SomeNode -> Sequence = (UBYTE *)(SomeNode + 1);
for(i = 0 ; i <= strlen(Sequence) ; i++)
SomeNode -> Sequence[i] = ToUpper(Sequence[i]);
AddTail(&SequenceList,(struct Node *)SomeNode);
}
}
/* ClearSequenceObjects():
*
* Clear the list of scan sequences.
*/
VOID
ClearSequenceObjects()
{
struct Node *SomeNode,*NextNode;
SomeNode = SequenceList . lh_Head;
while(SomeNode -> ln_Succ)
{
NextNode = SomeNode -> ln_Succ;
Remove(SomeNode);
FreeVec(SomeNode);
SomeNode = NextNode;
}
}
/* LogAction(UBYTE *String,...):
*
* Write an action to the default log file.
*/
VOID __stdargs
LogAction(UBYTE *String,...)
{
if(Config . LogActions && Config . LogFile[0])
{
UBYTE DummyBuffer[256];
BPTR File;
va_list VarArgs;
/* Build a valid string. */
va_start(VarArgs,String);
VSPrintf(DummyBuffer,String,VarArgs);
va_end(VarArgs);
/* Does the log file already exist? */
if(GetFileSize(Config . LogFile))
{
/* It does, let's append the data. */
if(File = Open(Config . LogFile,MODE_READWRITE))
{
if(Seek(File,0,OFFSET_END) == -1)
{
Close(File);
File = NULL;
}
}
}
else
{
/* Create a new file. */
if(File = Open(Config . LogFile,MODE_NEWFILE))
FPrintf(File,"Date Time Action\n--------- -------- ----------------------------------------\n");
}
/* The file is open, build the date/time string and
* write the log action.
*/
if(File)
{
UBYTE TimeBuffer[20],DateBuffer[20];
struct DateTime DateTime;
/* Obtain current time. */
DateStamp(&DateTime . dat_Stamp);
/* Convert it to human readable form. */
DateTime . dat_Format = FORMAT_DOS;
DateTime . dat_Flags = 0;
DateTime . dat_StrDay = NULL;
DateTime . dat_StrDate = DateBuffer;
DateTime . dat_StrTime = TimeBuffer;
/* Conversion succeeded? */
if(DateToStr(&DateTime))
FPrintf(File,"%s %s %s\n",DateBuffer,TimeBuffer,DummyBuffer);
/* Done! */
Close(File);
}
}
}
/* FlushMsg(struct Window *Window):
*
* Cancel all pending messages of a window.
*/
VOID
FlushMsg(struct Window *Window)
{
struct IntuiMessage *Massage;
while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
ReplyMsg(&Massage -> ExecMessage);
}
/* Local2Upper(UBYTE c):
*
* Very much the same as the macro expression ToUpper, but
* more suitable for expressions such as `ToUpper(*a++)'.
*/
UBYTE
Local2Upper(UBYTE c)
{
return((UBYTE)((((c) >= 224 && (c) <= 254) || ((c) >= 'a' && (c) <= 'z')) ? (c) - 32 : (c)));
}
/* GetString(UBYTE *Prompt,UBYTE *Buffer):
*
* Get a string from the user, very much the same as xpr_gets,
* but also including the `Load File' gadget.
*/
BYTE
GetString(UBYTE *Prompt,UBYTE *Buffer)
{
struct Gadget *GadgetList;
struct Gadget *GadgetArray[4];
struct Window *PanelWindow;
struct Menu *PanelMenu;
UBYTE DummyBuffer[256];
struct FileRequester *FileRequest;
LONG Width;
BYTE Success = FALSE;
STATIC struct NewMenu GetStringMenu[] =
{
{ NM_TITLE, "Project", 0 , 0, 0, (APTR)0},
{ NM_ITEM, "Okay", "O", 0, 0, (APTR)1},
{ NM_ITEM, "Cancel", "C", 0, 0, (APTR)3},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, "Load File...", "L", 0, 0, (APTR)2},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, "Quit", "Q", 0, 0, (APTR)3},
{ NM_END, 0, 0 , 0, 0, (APTR)0}
};
if(CreateAllGetsGadgets(TRUE,Buffer,Prompt,&Width,&GadgetArray[0],&GadgetList,VisualInfo,Screen -> WBorTop + Screen -> Font -> ta_YSize + 1))
{
if(PanelMenu = CreateMenus(GetStringMenu,
GTMN_FrontPen, 0,
TAG_DONE))
{
if(LayoutMenus(PanelMenu,VisualInfo,
GTMN_TextAttr,&DefaultFont,
TAG_DONE))
{
if(PanelWindow = OpenWindowTags(NULL,
WA_Width, Width,
WA_Height, 56,
WA_Left, (Screen -> Width - Width) >> 1,
WA_Top, (Screen -> Height - 56) >> 1,
WA_Activate, TRUE,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_RMBTrap, TRUE,
WA_CustomScreen,Screen,
WA_IDCMP, IDCMP_GADGETDOWN | IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_MENUPICK | IDCMP_RAWKEY,
WA_Title, "Enter A String",
TAG_DONE))
{
struct IntuiMessage *Massage;
ULONG Class,Code;
struct Gadget *Gadget;
BYTE Terminated = FALSE;
PushWindow(PanelWindow);
SetMenuStrip(PanelWindow,PanelMenu);
PanelWindow -> Flags &= ~WFLG_RMBTRAP;
AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
GT_RefreshWindow(PanelWindow,NULL);
ActiveGadget = GadgetArray[0];
ActivateGadget(GadgetArray[0],PanelWindow,NULL);
while(!Terminated)
{
WaitPort(PanelWindow -> UserPort);
while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
{
Class = Massage -> Class;
Code = Massage -> Code;
Gadget = (struct Gadget *)Massage -> IAddress;
GT_ReplyIMsg(Massage);
if(Class == IDCMP_GADGETDOWN)
{
if((Gadget -> GadgetType & GTYP_GTYPEMASK) == STRGADGET)
ActiveGadget = Gadget;
}
if(Class == IDCMP_RAWKEY)
{
if(Code == IECODE_UP_PREFIX|103 && CommandWindow == PanelWindow)
ActivateGadget(CommandGadget,PanelWindow,NULL);
}
if(Class == IDCMP_ACTIVEWINDOW)
ActivateGadget(GadgetArray[0],PanelWindow,NULL);
if(Class == IDCMP_MENUPICK)
{
struct MenuItem *MenuItem;
while(Code != MENUNULL)
{
MenuItem = ItemAddress(PanelMenu,Code);
switch((ULONG)MENU_USERDATA(MenuItem))
{
case 3: Class = IDCMP_CLOSEWINDOW;
break;
case 1: strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);
Success = TRUE;
Terminated = TRUE;
break;
case 2: GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
GA_Disabled,TRUE,
TAG_DONE);
SetWait(PanelWindow);
PanelWindow -> Flags |= WFLG_RMBTRAP;
if(FileRequest = GetFile("Load File...","","",DummyBuffer,NULL,FALSE,FALSE))
{
GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
GTST_String,DummyBuffer,
TAG_DONE);
RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
FreeAslRequest(FileRequest);
}
GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
GA_Disabled,FALSE,
TAG_DONE);
ClearPointer(PanelWindow);
PanelWindow -> Flags &= ~WFLG_RMBTRAP;
break;
}
Code = MenuItem -> NextSelect;
}
if(ActiveGadget)
ActivateGadget(ActiveGadget,PanelWindow,NULL);
}
if(Class == IDCMP_CLOSEWINDOW)
Terminated = TRUE;
if(Class == IDCMP_GADGETUP)
{
if(!DontActivate)
{
switch(Gadget -> GadgetID)
{
case 0:
case 1: strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);
Success = TRUE;
Terminated = TRUE;
break;
case 2: GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
GA_Disabled,TRUE,
TAG_DONE);
SetWait(PanelWindow);
PanelWindow -> Flags |= WFLG_RMBTRAP;
if(FileRequest = GetFile("Load File...","","",DummyBuffer,NULL,FALSE,FALSE))
{
strcpy(((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer,DummyBuffer);
RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
FreeAslRequest(FileRequest);
}
OnGadget(GadgetArray[0],PanelWindow,NULL);
ClearPointer(PanelWindow);
PanelWindow -> Flags &= ~WFLG_RMBTRAP;
break;
case 3: Terminated = TRUE;
break;
}
}
else
DontActivate = FALSE;
}
}
}
PanelWindow -> Flags |= WFLG_RMBTRAP;
ClearMenuStrip(PanelWindow);
RemoveGList(PanelWindow,GadgetList,(UWORD)-1);
PopWindow();
CloseWindow(PanelWindow);
}
FreeGadgets(GadgetList);
}
FreeMenus(PanelMenu);
}
}
return(Success);
}
/* WakeUp(struct Window *Window):
*
* Pop a window to the front and alert the user.
*/
VOID
WakeUp(struct Window *Window)
{
if(Window)
BumpWindow(Window);
Beep();
WaitTime(2,0);
/*
Beep();
WaitTime(0,MILLION / 4);
Beep();
WaitTime(0,MILLION / 4);*/
}
/* SendAmigaDOSCommand(UBYTE *Name):
*
* Let the current default Shell execute an AmigaDOS
* command. Block until the command has returned.
*/
VOID
SendAmigaDOSCommand(UBYTE *Name)
{
BYTE DummyBuffer[2];
BPTR File;
/* Let the asynchronous Rexx server pick up and process
* all incoming messages rather than sending them to the
* main process (hopefully avoids deadlock situations).
*/
BatchMode = TRUE;
/* Open the console window or whatever the user
* wants us to open here.
*/
if(File = Open(WindowName,MODE_NEWFILE))
{
ULONG Tags[3];
struct ConUnit *ConUnit = GetConUnit(((struct FileHandle *)BADDR(File)) -> fh_Type);
Tags[0] = SYS_Output;
Tags[1] = (ULONG)File;
Tags[2] = TAG_DONE;
if(ConUnit)
{
if(ConUnit -> cu_Window)
BumpWindow(ConUnit -> cu_Window);
}
/* Make the Shell execute the command. */
/* SystemTags(Name,SYS_Output,File,TAG_DONE);*/
System(Name,(APTR)&Tags[0]);
/* Wait for some impressive user action. */
Write(File,"Press \33[1mRETURN\33[0m or close window to continue. ",51);
Read(File,DummyBuffer,1);
Close(File);
}
/* Bring the `term' main screen to the front and
* fall back into asynchronous Rexx message processing.
*/
BumpWindow(Window);
BatchMode = FALSE;
}
/* RexxBackgroundServer():
*
* The background process to handle the rexx
* massaging.
*/
VOID __saveds
RexxBackgroundServer()
{
BPTR OldCOS,OldCIS,NewCOS,NewCIS;
struct MsgPort *OldConsoleTask,*ReplyPort;
BYTE DummyBuffer[2];
struct RexxMsg *RexxMsg;
struct Process *BackgroundProcess;
struct Message *SetupMsg;
/* Look who we are. */
BackgroundProcess = (struct Process *)SysBase -> ThisTask;
/* Wait for startup message. */
WaitPort(&BackgroundProcess -> pr_MsgPort);
/* Pick the message up. */
SetupMsg = GetMsg(&BackgroundProcess -> pr_MsgPort);
/* Create a reply port the Rexx message is to
* return to after processing.
*/
if(ReplyPort = (struct MsgPort *)CreateMsgPort())
{
/* Remember previous I/O streams and
* console handler.
*/
OldCOS = BackgroundProcess -> pr_COS;
OldCIS = BackgroundProcess -> pr_CIS;
OldConsoleTask = BackgroundProcess -> pr_ConsoleTask;
/* The following lines perform an `almost illegal'
* action: new console I/O streams are opened for
* the `term' main process. This is due to a rather
* helpful Rexx server feature. Errors, messages
* and other data are sent to the current output
* stream.
*/
if(NewCIS = Open(WindowName,MODE_NEWFILE))
{
struct FileHandle *FileHandle = (struct FileHandle *)BADDR(NewCIS);
struct ConUnit *ConUnit = GetConUnit(((struct FileHandle *)BADDR(NewCIS)) -> fh_Type);
/* Lock until we're done with the forgery. */
Forbid();
BackgroundProcess -> pr_ConsoleTask = (APTR)FileHandle -> fh_Type;
BackgroundProcess -> pr_CIS = NewCIS;
BackgroundProcess -> pr_COS = NewCOS = Open("*",MODE_NEWFILE);
Permit();
RexxWindow = NULL;
if(ConUnit)
{
if(RexxWindow = ConUnit -> cu_Window)
BumpWindow(RexxWindow);
}
/* Send the command and wait for a reply. */
if(SendRexxCommand(ReplyPort,SetupMsg -> mn_Node . ln_Name,NULL,NULL))
{
ULONG SignalSet;
SignalSet = Wait((1 << ReplyPort -> mp_SigBit) | SIGBREAKF_CTRL_C);
if(SignalSet & SIGBREAKF_CTRL_C)
Signal(ThisProcess,SIGBREAKF_CTRL_D);
if(!(SignalSet & (1 << ReplyPort -> mp_SigBit)))
Wait(1 << ReplyPort -> mp_SigBit);
/* Pick up the RexxMsg (SendRexxCommand
* had allocated it for us) and
* examine the return codes.
*/
if(RexxMsg = (struct RexxMsg *)GetMsg(ReplyPort))
{
if(!ExitQuietly)
{
/* This doesn't look too
* good, does it?
*/
if(RexxMsg -> rm_Result1)
FPrintf(NewCIS,"\nCommand \"%s\" has terminated with code %ld, %ld.\n",SetupMsg -> mn_Node . ln_Name,RexxMsg -> rm_Result1,RexxMsg -> rm_Result2);
/* Show our hand and return
* to the usual business.
*/
Write(BackgroundProcess -> pr_COS,"Press \33[1mRETURN\33[0m or close window to continue. ",51);
Rexx2Front();
Read(NewCIS,DummyBuffer,1);
Term2Front();
}
else
ExitQuietly = FALSE;
/* Release the message. */
FreeRexxCommand(RexxMsg);
}
}
Forbid();
RexxWindow = NULL;
Permit();
BumpWindow(Window);
/* Close our fake I/O streams. */
Forbid();
Close(NewCIS);
Close(NewCOS);
/* And install the previous pointers. */
BackgroundProcess -> pr_ConsoleTask = (APTR)OldConsoleTask;
BackgroundProcess -> pr_CIS = OldCIS;
BackgroundProcess -> pr_COS = OldCOS;
Permit();
}
/* Remove the reply port. */
DeleteMsgPort(ReplyPort);
}
/* We are done, lock and reply the message causing the
* main process to return to the input loop.
*/
Forbid();
ReplyMsg(SetupMsg);
}
/* SendARexxCommand(UBYTE *Name):
*
* Let the ARexx server execute a command (or a script
* file if necessary) and block until the command
* has returned.
*/
VOID
SendARexxCommand(UBYTE *Name)
{
struct Process *BackgroundProcess;
struct Message *SetupMsg;
struct MsgPort *ReplyPort;
ULONG SignalSet;
/* Create a reply port for the info message. */
if(ReplyPort = CreateMsgPort())
{
/* Allocate the message body. */
if(SetupMsg = (struct Message *)AllocVec(sizeof(struct Message),MEMF_PUBLIC|MEMF_CLEAR))
{
/* Set up the message itself. */
SetupMsg -> mn_Node . ln_Name = Name;
SetupMsg -> mn_ReplyPort = ReplyPort;
SetupMsg -> mn_Length = sizeof(struct Message);
/* Create the background process which will
* handle all the messy rexx message sending
* for us.
*/
if(BackgroundProcess = (struct Process *)CreateNewProcTags(
NP_Entry, RexxBackgroundServer,
NP_Name, "term Rexx Background Process",
NP_StackSize, 16384,
TAG_END))
{
SetSignal(0,SIGBREAKF_CTRL_D);
/* Send the startup message. */
PutMsg(&BackgroundProcess -> pr_MsgPort,SetupMsg);
/* Go into loop and wait for the
* background process to return.
*/
FOREVER
{
SignalSet = Wait(SIG_REXX | (1 << ReplyPort -> mp_SigBit));
/* Yet another rexx message. */
if(SignalSet & SIG_REXX)
HandleRexx();
/* The background server has
* finished.
*/
if(SignalSet & (1 << ReplyPort -> mp_SigBit))
break;
}
SetSignal(0,SIGBREAKF_CTRL_D);
}
/* Free the message. */
FreeVec(SetupMsg);
}
/* Delete the reply port. */
DeleteMsgPort(ReplyPort);
}
}
/* ahtoi(UBYTE *String):
*
* Turn a hexadecimal string into an integer (borrowed from
* Matt Dillon's dmouse.c).
*/
LONG
ahtoi(UBYTE *String)
{
LONG Value = 0;
UBYTE c;
while(c = *String)
{
Value <<= 4;
if(c >= '0' && c <= '9')
Value |= (c & 15);
else
Value |= (c & 15) + 9;
++String;
}
return(Value);
}
/* BlockWindows():
*
* Block the main window and the status window (i.e. disable
* the menu and attach a wait pointer).
*/
VOID
BlockWindows()
{
if(!(BlockNestCount++))
{
SetWait(Window);
SetWait(StatusWindow);
if(PacketWindow)
{
SetWait(PacketWindow);
PacketWindow -> Flags |= WFLG_RMBTRAP;
GT_SetGadgetAttrs(PacketGadgetArray[0],PacketWindow,NULL,
GA_Disabled,TRUE,
TAG_DONE);
}
Window -> Flags |= WFLG_RMBTRAP;
StatusWindow -> Flags |= WFLG_RMBTRAP;
WeAreBlocking = TRUE;
}
}
/* ReleaseWindows():
*
* Reenable the menus and clear the wait pointer.
*/
VOID
ReleaseWindows()
{
if(!(--BlockNestCount))
{
Window -> Flags &= ~WFLG_RMBTRAP;
StatusWindow -> Flags &= ~WFLG_RMBTRAP;
ClearPointer(Window);
ClearPointer(StatusWindow);
if(PacketWindow)
{
PacketWindow -> Flags &= ~WFLG_RMBTRAP;
ClearPointer(PacketWindow);
OnGadget(PacketGadgetArray[0],PacketWindow,NULL);
}
FlushMsg(Window);
WeAreBlocking = FALSE;
}
}
/* LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars):
*
* Read a few bytes from a file (à la gets).
*/
BYTE
LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars)
{
STATIC UBYTE Data[1024];
STATIC LONG RIdx = 0,RLen = 0;
LONG i;
if(File)
{
for(i = 0 ; i < MaxChars ; i++)
{
if(RIdx >= RLen)
{
RLen = Read(File,Data,1024);
RIdx = 0;
if(RLen <= 0)
{
Buffer[i] = 0;
return(FALSE);
}
}
if((Buffer[i] = Data[RIdx]) != '\r')
{
if(Data[RIdx++] == '\n')
{
Buffer[i + 1] = 0;
break;
}
}
}
}
else
RIdx = RLen = 0;
return(TRUE);
}
/* FlowInit():
*
* Set up the data flow parser. The parser scans the serial
* output data for more or less interesting modem output
* (carrier lost, connect, etc.).
*/
VOID
FlowInit()
{
FlowInfo . Changed = FALSE;
FlowInfo . NoCarrier = FlowInfo . ZModemUpload = FlowInfo . Connect = FlowInfo . Voice = FlowInfo . Ring = FlowInfo . Busy = FALSE;
AttentionBuffers[0] = Config . NoCarrier;
AttentionBuffers[1] = Config . Ring;
AttentionBuffers[2] = Config . Voice;
AttentionBuffers[3] = "*B01";
AttentionBuffers[4] = "**B01";
AttentionBuffers[5] = Config . Connect;
AttentionBuffers[6] = Config . Busy;
FlowCount = 0;
memset(&AttentionCount[0],0,7);
BaudPending = FALSE;
FullCheck = FALSE;
}
/* FlowFilter(UBYTE Char):
*
* Send a character through the data flow parser and look
* if it's part of a modem message.
*/
VOID
FlowFilter(UBYTE Char)
{
STATIC BYTE IgnoreChar;
BYTE i,Matches = 0,Start,End,WasOnline = Online;
/* Full data check is a lot slower than looking for
* just a single sequence (such as the `CONNECT'
* below). This mode is reserved for the dial panel.
*/
if(FullCheck)
{
Start = 1;
End = 7;
}
else
{
Start = 0;
if(UsesZModem)
End = 5;
else
End = 3;
}
/* We already got a `CONNECT' and the
* `connect auto-baud' feature is enabled.
* Continue scanning the serial output
* data for the actual baud rate.
*/
if(BaudPending)
{
if(Char >= '0' && Char <= '9')
{
BaudBuffer[BaudCount++] = Char;
if(IgnoreChar)
IgnoreChar = 0;
}
else
{
/* The scanner has found a
* non-numerical character.
* This is either a blank
* space or something else.
* The latter tells us
* that the baud rate has
* been identified and is
* ready to be used.
*/
if(Char != IgnoreChar)
{
BaudBuffer[BaudCount] = 0;
BaudPending = FALSE;
}
}
}
if(!BaudPending)
{
/* Scan all ID strings for matches. */
for(i = Start ; i < End ; i++)
{
/* This sequence is a probable
* match.
*/
if(AttentionCount[i] == FlowCount)
{
/* Does the character
* fit into the sequence?
*/
if(Char == AttentionBuffers[i][FlowCount])
{
/* Increment the
* number of matching
* characters in this
* sequence.
*/
AttentionCount[i]++;
/* Did we hit the
* last character
* in the sequence?
*/
if(AttentionBuffers[i][FlowCount + 1])
Matches++;
else
{
Matches = 0;
/* We've got a valid
* sequence, now look
* which flags to change.
*/
switch(i)
{
/* We got a `no carrier' message. */
case 0: if(!FlowInfo . NoCarrier)
{
FlowInfo . NoCarrier = TRUE;
FlowInfo . Changed = TRUE;
}
Online = FALSE;
/* Clear the password. */
Password[0] = 0;
if(WasOnline)
{
if(CurrentPay)
LogAction("Carrier lost (cost %ld.%02ld).",CurrentPay / 100,CurrentPay % 100);
else
LogAction("Carrier lost.");
Say("Carrier lost.");
}
break;
/* Got a voice call. */
case 1: if(!FlowInfo . Voice)
{
FlowInfo . Voice = TRUE;
FlowInfo . Changed = TRUE;
}
break;
/* Got another call. */
case 2: if(!FlowInfo . Ring)
{
FlowInfo . Ring = TRUE;
FlowInfo . Changed = TRUE;
}
break;
case 3:
case 4: if(!FlowInfo . ZModemUpload)
{
FlowInfo . ZModemUpload = TRUE;
FlowInfo . Changed = TRUE;
}
break;
/* Got a connect message. */
case 5: if(!FlowInfo . Connect)
{
FlowInfo . Connect = TRUE;
FlowInfo . Changed = TRUE;
}
if(Config . ConnectAutoBaud)
{
BaudBuffer[0] = 0;
BaudPending = TRUE;
BaudCount = 0;
IgnoreChar = ' ';
}
break;
/* Line is busy. */
case 6: if(!FlowInfo . Busy)
{
FlowInfo . Busy = TRUE;
FlowInfo . Changed = TRUE;
}
break;
}
}
}
}
}
/* We've got a good match (recognized
* a sequence, so reset the data flow
* scanner.
*/
if(!Matches)
{
if(FlowCount)
{
FlowCount = 0;
memset(&AttentionCount[0],0,7);
}
}
else
FlowCount++;
}
else
{
/* This checks for just a single sequence:
* the notorious `NO CARRIER'.
*/
if(AttentionCount[0] == FlowCount)
{
if(Char == AttentionBuffers[0][FlowCount])
{
AttentionCount[0]++;
if(AttentionBuffers[0][FlowCount + 1])
Matches++;
else
{
Matches = 0;
if(!FlowInfo . NoCarrier)
{
FlowInfo . NoCarrier = TRUE;
FlowInfo . Changed = TRUE;
}
Online = FALSE;
/* Clear the password. */
Password[0] = 0;
if(WasOnline)
{
if(CurrentPay)
LogAction("Carrier lost (cost %ld.%02ld).",CurrentPay / 100,CurrentPay % 100);
else
LogAction("Carrier lost.");
Say("Carrier lost.");
}
}
}
}
if(!Matches)
{
if(FlowCount)
{
FlowCount = 0;
memset(&AttentionCount[0],0,7);
}
}
else
FlowCount++;
}
}
/* LoadMacros(UBYTE *Name,struct MacroKeys *Keys):
*
* Load the keyboard macros from a file.
*/
BYTE
LoadMacros(UBYTE *Name,struct MacroKeys *Keys)
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
struct StoredProperty *Prop;
struct TermInfo *TermInfo;
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
{
InitIFFasDOS(Handle);
if(!OpenIFF(Handle,IFFF_READ))
{
/* Collect version number ID if
* available.
*/
if(!PropChunks(Handle,&VersionProps[0],1))
{
/* The following line tells iffparse to stop at the
* very beginning of a `Type' chunk contained in a
* `TERM' FORM chunk.
*/
if(!StopChunk(Handle,'TERM','KEYS'))
{
/* Parse the file... */
if(!ParseIFF(Handle,IFFPARSE_SCAN))
{
/* Did we get a version ID? */
if(Prop = FindProp(Handle,'TERM','VERS'))
{
TermInfo = (struct TermInfo *)Prop -> sp_Data;
/* Is it the file format we are able
* to read?
*/
if(TermInfo -> Version == TermVersion && TermInfo -> Revision <= TermRevision && TermInfo -> Revision >= 6)
{
/* The file read pointer is positioned
* just in front of the first data
* to be read, so let's don't disappoint
* iffparse and read it.
*/
if(ReadChunkBytes(Handle,Keys,sizeof(struct MacroKeys)) == sizeof(struct MacroKeys))
Success = TRUE;
}
else
{
/* Probably an older revision. */
if(TermInfo -> Version == 1 && TermInfo -> Revision < 6)
{
memset(Keys,0,sizeof(struct MacroKeys));
if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
Success = TRUE;
}
}
}
else
{
/* File was created by WriteIFFData previous
* to revision 1.4.
*/
memset(Keys,0,sizeof(struct MacroKeys));
if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
Success = TRUE;
}
}
}
}
CloseIFF(Handle);
}
Close(Handle -> iff_Stream);
}
FreeIFF(Handle);
}
return(Success);
}
/* FindThisItem(ULONG MenuID):
*
* Scan the main menu for a menuitem associated with a
* menu ID.
*/
struct MenuItem *
FindThisItem(ULONG MenuID)
{
struct Menu *FirstMenu;
struct MenuItem *FirstItem;
for(FirstMenu = Menu ; FirstMenu -> NextMenu ; FirstMenu = FirstMenu -> NextMenu)
{
for(FirstItem = FirstMenu -> FirstItem ; FirstItem -> NextItem ; FirstItem = FirstItem -> NextItem)
{
if((ULONG)GTMENUITEM_USERDATA(FirstItem) == MenuID)
return(FirstItem);
}
}
return(NULL);
}
/* GetFileSize(UBYTE *Name):
*
* Simple routine to return the size of a file in
* bytes.
*/
LONG
GetFileSize(UBYTE *Name)
{
struct FileInfoBlock *FileInfo;
BPTR FileLock;
LONG FileSize = 0;
if(FileInfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
{
if(FileLock = Lock(Name,ACCESS_READ))
{
if(Examine(FileLock,FileInfo))
FileSize = FileInfo -> fib_Size;
UnLock(FileLock);
}
FreeMem(FileInfo,sizeof(struct FileInfoBlock));
}
return(FileSize);
}
/* StrCmp(UBYTE *a,UBYTE *b):
*
* Perform case insensitive string comparison. I know
* that Stricmp in utility.library handles the same
* job, but by the time I had spread calls to this
* routine across a number of modules I lost interest
* in changing the call.
*/
LONG
StrCmp(UBYTE *a,UBYTE *b)
{
for( ; Local2Upper(*a) == Local2Upper(*b) ; a++, b++)
{
if(!(*a))
return(0);
}
return((LONG)(Local2Upper(*a) - Local2Upper(*b)));
}
/* GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect):
*
* Call the asl.library file requester to select a single or
* a couple of files.
*/
struct FileRequester *
GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect)
{
struct FileRequester *AslFileRequest;
BYTE Result = FALSE;
LONG Flags;
STATIC UBYTE DirBuffer[256];
/* We use this tag array to remember the size and
* position of the asl requester window.
*/
STATIC struct {
ULONG Tag1, LeftEdge;
ULONG Tag2, TopEdge;
ULONG Tag3, Width;
ULONG Tag4, Height;
ULONG Tag5;
} Dims = {
ASL_LeftEdge, 0,
ASL_TopEdge, 0,
ASL_Width, 0,
ASL_Height, 0,
TAG_DONE
};
/* Empty directory string? Revert to the last directory
* name.
*/
if(!Directory[0])
Directory = DirBuffer;
/* If a wildcard pattern is required, add a gadget
* to display it.
*/
if(Pattern)
{
Flags = FILF_PATGAD;
if(!Pattern[0])
Pattern = "#?";
}
else
{
Flags = 0;
Pattern = "#?";
}
/* Set the save flag if we are about to save something. */
if(SaveFlag)
Flags |= FILF_SAVE;
/* Set the multiselect bit if multiple files are
* to be selected (e.g. for batch file upload).
*/
if(MultiSelect)
Flags |= FILF_MULTISELECT;
/* Allocate the asl.library directory requester
* and display it.
*/
if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
ASL_Window, Window,
ASL_File, Name,
ASL_Dir, Directory,
ASL_Hail, Title,
ASL_FuncFlags, Flags,
ASL_Pattern, Pattern,
ASL_OKText, SaveFlag ? "Save" : "Open",
Dims . Width ? TAG_MORE : TAG_END,&Dims))
{
if(AslRequestTags(AslFileRequest,TAG_DONE))
{
Dims . LeftEdge = AslFileRequest -> rf_LeftEdge;
Dims . TopEdge = AslFileRequest -> rf_TopEdge;
Dims . Width = AslFileRequest -> rf_Width;
Dims . Height = AslFileRequest -> rf_Height;
/* Do we have a valid file name? */
if(AslFileRequest -> rf_File[0])
{
/* Build a legal path/file string. */
strcpy(Buffer,AslFileRequest -> rf_Dir);
AddPart((UBYTE *)Buffer,(UBYTE *)AslFileRequest -> rf_File,256);
Result = TRUE;
strcpy(DirBuffer,AslFileRequest -> rf_Dir);
}
}
}
/* We didn't get a file, no need to keep the
* file requester.
*/
if(!Result && AslFileRequest)
{
FreeAslRequest(AslFileRequest);
return(NULL);
}
else
return(AslFileRequest);
}
/* MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...):
*
* Really quite simple varargs version of Intuition's
* EasyRequest requester.
*/
SHORT __stdargs
MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...)
{
struct EasyStruct Easy;
SHORT Result;
ULONG IDCMP = NULL;
va_list VarArgs;
/* Standard data. */
Easy . es_StructSize = sizeof(struct EasyStruct);
Easy . es_Flags = NULL;
Easy . es_Title = (UBYTE *)"term Request";
Easy . es_TextFormat = (UBYTE *)Text;
Easy . es_GadgetFormat = (UBYTE *)Gadgets;
/* Use the argument array to build the
* requester and display it.
*/
va_start(VarArgs,Gadgets);
Result = EasyRequestArgs(Window,&Easy,&IDCMP,VarArgs);
va_end(VarArgs);
return(Result);
}
/* A handy positioning macro. */
#define MoveItem(X,Y) Move(RPort,((11 + X * 20) * 8) + ((Screen -> Width - 640) >> 1),2 + 6 + Y * 8)
/* StatusServer():
*
* Asynchronous task to continuosly display the current
* terminal settings.
*/
VOID __saveds
StatusServer()
{
struct RastPort *RPort = StatusWindow -> RPort;
UBYTE Buffer[20];
struct timerequest *TimeRequest;
struct MsgPort *TimePort;
struct timeval OnlineTime;
BYTE GotOnline = FALSE;
BYTE KeepGoing = TRUE;
BYTE LastFont = -1;
BYTE LastEmulation = -1;
BYTE LastProtocol[40],ProtocolBuffer[10],i;
LONG LastBaud = -1;
BYTE LastBitsPerChar = -1;
BYTE LastParity = -1;
BYTE LastStopBits = -1;
BYTE LastStatus = -1;
LONG SecCount;
BYTE FlagBit;
LONG ThisHour,ThisMinute,TestTime;
BYTE FlashIt = FALSE;
LastProtocol[0] = 0;
/* Create a timer device request. */
if(TimePort = (struct MsgPort *)CreateMsgPort())
{
if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
{
if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0))
{
/* Signal our father process
* that we're running.
*/
Signal(ThisProcess,SIGBREAKF_CTRL_C);
MoveItem(3,1);
Print("00:00:00");
/* Keep on displaying. */
while(KeepGoing)
{
/* Are we to quit? */
if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
{
KeepGoing = FALSE;
SetSignal(0,SIGBREAKF_CTRL_C);
}
/* Get the current time. */
TimeRequest -> tr_node . io_Command = TR_GETSYSTIME;
DoIO(TimeRequest);
/* A connection has just
* been established.
*/
if(Online && !GotOnline)
{
OnlineTime = TimeRequest -> tr_time;
GotOnline = TRUE;
SecCount = 0;
FlagBit = FALSE;
}
/* Print the current time. */
ThisHour = (TimeRequest -> tr_time . tv_secs % 86400) / 3600;
ThisMinute = (TimeRequest -> tr_time . tv_secs % 3600) / 60;
SPrintf(Buffer,"%02ld:%02ld:%02ld",ThisHour,ThisMinute,TimeRequest -> tr_time . tv_secs % 60);
MoveItem(3,0);
Print(Buffer);
if(Online)
{
struct timeval TempTime;
if(PayPerUnit[0] || PayPerUnit[1])
{
TestTime = ThisHour * 6 + ThisMinute / 10;
if(TestTime >= TimeOfDay[0] && TestTime <= TimeOfDay[1])
PreferredTime = 0;
else
{
if(TestTime >= TimeOfDay[1] && TestTime <= TimeOfDay[0])
PreferredTime = 1;
else
{
if(TestTime >= TimeOfDay[0] && TestTime >= TimeOfDay[1])
{
if(TimeOfDay[0] > TimeOfDay[1])
PreferredTime = 0;
else
PreferredTime = 1;
}
else
{
if(TestTime <= TimeOfDay[0] && TestTime <= TimeOfDay[1])
{
if(TimeOfDay[0] > TimeOfDay[1])
PreferredTime = 0;
else
PreferredTime = 1;
}
}
}
}
if(!CurrentPay)
CurrentPay = PayPerUnit[PreferredTime];
FlagBit ^= TRUE;
if(!FlagBit)
{
if((SecCount++) == SecPerUnit[PreferredTime])
{
SecCount = 0;
CurrentPay += PayPerUnit[PreferredTime];
}
}
}
/* Show the time
* we have been online
* yet.
*/
TempTime = TimeRequest -> tr_time;
SubTime(&TempTime,&OnlineTime);
SPrintf(Buffer,"%02ld:%02ld:%02ld",(TempTime . tv_secs % 86400) / 3600,(TempTime . tv_secs % 3600) / 60,TempTime . tv_secs % 60);
MoveItem(3,1);
Print(Buffer);
}
else
{
if(GotOnline)
GotOnline = FALSE;
}
/* Display the current terminal
* status.
*/
if(LastStatus != Status)
{
LastStatus = Status;
MoveItem(0,0);
Print(ConfigStatus[LastStatus]);
}
/* Show the current transfer
* protocol.
*/
if(strcmp(LastProtocol,FilePart(Config . Protocol)))
{
strcpy(LastProtocol,FilePart(Config . Protocol));
strcpy(ProtocolBuffer," ");
for(i = 0 ; i < 8 ; i++)
{
if(!LastProtocol[i + 3] || LastProtocol[i + 3] == '.')
break;
else
ProtocolBuffer[i] = LastProtocol[i + 3];
}
MoveItem(1,0);
Print(ProtocolBuffer);
}
/* Show the current baud
* rate.
*/
if(LastBaud != Config . BaudRate)
{
LastBaud = Config . BaudRate;
SPrintf(Buffer,"%ld ",LastBaud);
Buffer[8] = 0;
MoveItem(2,0);
Print(Buffer);
}
/* Show the current
* terminal font.
*/
if(LastFont != Config . Font)
{
LastFont = Config . Font;
MoveItem(0,1);
Print(ConfigFont[LastFont]);
}
/* Show the current terminal
* emulation.
*/
if(LastEmulation != Config . Emulation)
{
LastEmulation = Config . Emulation;
MoveItem(1,1);
Print(ConfigEmulation[LastEmulation]);
}
/* Show the current serial
* parameters (parity, etc).
*/
if(LastBitsPerChar != Config . BitsPerChar || LastParity != Config . Parity || LastStopBits != Config . StopBits)
{
LastBitsPerChar = Config . BitsPerChar;
LastParity = Config . Parity;
LastStopBits = Config . StopBits;
SPrintf(Buffer,"%ld-%s-%ld",LastBitsPerChar,ConfigParity[LastParity],LastStopBits);
MoveItem(2,1);
Print(Buffer);
}
/* Wait another half a second. */
if(KeepGoing)
{
TimeRequest -> tr_node . io_Command = TR_ADDREQUEST;
TimeRequest -> tr_time . tv_secs = 0;
TimeRequest -> tr_time . tv_micro = MILLION / 2;
DoIO(TimeRequest);
}
/* Make the colours blink. */
if((Window -> Flags & WFLG_MENUSTATE) || (Window -> Pointer))
{
if(!FlashIt)
{
if(Screen == IntuitionBase -> FirstScreen)
LoadRGB4(VPort,Config . Colours,16);
FlashIt = TRUE;
}
}
else
{
/* Are we to flash the display? */
if(!Config . DisableBlinking)
{
if(Screen == IntuitionBase -> FirstScreen)
{
if(FlashIt)
LoadRGB4(VPort,BlinkColours,16);
else
LoadRGB4(VPort,Config . Colours,16);
}
FlashIt ^= TRUE;
}
}
}
CloseDevice(TimeRequest);
}
DeleteIORequest(TimeRequest);
}
DeleteMsgPort(TimePort);
}
/* Signal the father process that we're done
* and quietly remove ourselves.
*/
Forbid();
Signal(ThisProcess,SIGBREAKF_CTRL_C);
StatusTask = NULL;
RemTask(SysBase -> ThisTask);
}
/* CloseWindowSafely(struct Window *Window):
*
* Close a window freeing all messages pending at
* its user port (taken from example source code
* published once upon a time in Amiga Mail).
*/
VOID
CloseWindowSafely(struct Window *Window)
{
struct IntuiMessage *IntuiMessage;
struct Node *Successor;
Forbid();
IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
{
if(IntuiMessage -> IDCMPWindow == Window)
{
Remove(IntuiMessage);
ReplyMsg((struct Message *)IntuiMessage);
}
IntuiMessage = (struct IntuiMessage *)Successor;
}
Window -> UserPort = NULL;
ModifyIDCMP(Window,NULL);
Permit();
CloseWindow(Window);
}
/* WaitTime(LONG Secs,LONG Micros):
*
* Wait a given period of time.
*/
VOID
WaitTime(LONG Secs,LONG Micros)
{
TimeRequest -> tr_node . io_Command = TR_ADDREQUEST;
TimeRequest -> tr_time . tv_secs = Secs;
TimeRequest -> tr_time . tv_micro = Micros;
DoIO(TimeRequest);
}
/* GetEnvDOS(UBYTE *Name,UBYTE *Buffer):
*
* Get the contents of a vanilla AmigaDOS environment
* variable.
*/
UBYTE *
GetEnvDOS(UBYTE *Name,UBYTE *Buffer)
{
LONG Size;
BPTR File,SomeLock;
Buffer[0] = 0;
/* Is ENV: present? */
if(SomeLock = Lock("ENV:",ACCESS_READ))
{
UBYTE SomeBuffer[80];
UnLock(SomeLock);
strcpy(SomeBuffer,"ENV:");
strcat(SomeBuffer,Name);
/* Open the file. */
if(File = Open(SomeBuffer,MODE_OLDFILE))
{
/* Read the contents. */
Size = Read(File,Buffer,256);
Close(File);
if(Size > 0)
{
Buffer[Size] = 0;
return(Buffer);
}
}
}
return(NULL);
}
/* SetEnvDOS(UBYTE *Name,UBYTE *Value):
*
* Set the contents of a vanilla AmigaDOS environment
* variable.
*/
BYTE
SetEnvDOS(UBYTE *Name,UBYTE *Value)
{
UBYTE Buffer[80],*Destination;
LONG Length = 0;
BPTR File,FileLock;
BYTE Success = FALSE;
SHORT i;
for(i = 0 ; i < 2 ; i++)
{
if(i)
Destination = "ENVARC:";
else
Destination = "ENV:";
/* Is ENV:/ENVARC: present? */
if(FileLock = Lock(Destination,ACCESS_READ))
{
UnLock(FileLock);
strcpy(Buffer,Destination);
strcat(Buffer,Name);
/* There already is a variable of that
* name in the environment storage
* directory.
*/
if(FileLock = Lock(Buffer,ACCESS_WRITE))
{
UnLock(FileLock);
/* Delete the variable. */
if(!DeleteFile(Buffer))
{
Success = FALSE;
continue;
}
}
/* Set the new variable. */
if(Length = strlen(Value))
{
if(File = Open(Buffer,MODE_NEWFILE))
{
if(Write(File,Value,Length) != Length)
{
Close(File);
DeleteFile(Buffer);
Success = FALSE;
}
else
{
Close(File);
SetProtection(Buffer,FIBF_EXECUTE);
Success = TRUE;
}
}
else
Success = FALSE;
}
else
Success = TRUE;
}
else
Success = FALSE;
}
return(Success);
}
/* BumpWindow(struct Window *SomeWindow):
*
* Bring a window to the front (and shift the screen
* back to its initial position).
*/
VOID
BumpWindow(struct Window *SomeWindow)
{
MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,-SomeWindow -> WScreen -> TopEdge);
ScreenToFront(SomeWindow -> WScreen);
ActivateWindow(SomeWindow);
}
/* BumpDefault():
*
* Bring the current default screen to the front.
*/
VOID
BumpDefault()
{
struct Screen *DefaultScreen;
if(DefaultScreen = (struct Screen *)LockPubScreen(NULL))
{
MoveScreen(DefaultScreen,-DefaultScreen -> LeftEdge,-DefaultScreen -> TopEdge);
ScreenToFront(DefaultScreen);
UnlockPubScreen(NULL,DefaultScreen);
}
}
/* WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
*
* Write data to an IFF file (via iffparse.library).
*/
BYTE
WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
/* Allocate a handle. */
if(Handle = AllocIFF())
{
/* Open an output stream. */
if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
{
/* Tell iffparse that this is
* a DOS handle.
*/
InitIFFasDOS(Handle);
/* Open the handle for writing. */
if(!OpenIFF(Handle,IFFF_WRITE))
{
/* Push outmost chunk onto stack. */
if(!PushChunk(Handle,'TERM','FORM',IFFSIZE_UNKNOWN))
{
/* Add a version identifier. */
if(!PushChunk(Handle,0,'VERS',IFFSIZE_UNKNOWN))
{
struct TermInfo TermInfo;
TermInfo . Version = TermVersion;
TermInfo . Revision = TermRevision;
/* Write the version data. */
if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
{
/* Pop the version chunk, i.e. write it to the file. */
if(PopChunk(Handle))
Success = FALSE;
else
{
/* Push the real data chunk on the stack. */
if(!PushChunk(Handle,0,Type,IFFSIZE_UNKNOWN))
{
/* Write the data. */
if(WriteChunkBytes(Handle,Data,Size) == Size)
Success = TRUE;
/* Pop the data chunk. */
if(PopChunk(Handle))
Success = FALSE;
}
else
Success = FALSE;
}
}
else
Success = FALSE;
}
/* Seems that we're done, now try to pop the FORM chunk
* and return.
*/
if(PopChunk(Handle))
Success = FALSE;
}
/* Close the handle (flush any pending data). */
CloseIFF(Handle);
}
/* Close the DOS handle itself. */
Close(Handle -> iff_Stream);
}
/* And free the IFF handle. */
FreeIFF(Handle);
}
if(Success)
SetProtection(Name,FIBF_EXECUTE);
return(Success);
}
/* ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
*
* Read data from a `TERM' FORM chunk contained in an IFF file.
*/
BYTE
ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
struct StoredProperty *Prop;
struct TermInfo *TermInfo;
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
{
InitIFFasDOS(Handle);
if(!OpenIFF(Handle,IFFF_READ))
{
/* Collect version number ID if
* available.
*/
if(!PropChunks(Handle,&VersionProps[0],1))
{
/* The following line tells iffparse to stop at the
* very beginning of a `Type' chunk contained in a
* `TERM' FORM chunk.
*/
if(!StopChunk(Handle,'TERM',Type))
{
/* Parse the file... */
if(!ParseIFF(Handle,IFFPARSE_SCAN))
{
/* Did we get a version ID? */
if(Prop = FindProp(Handle,'TERM','VERS'))
{
TermInfo = (struct TermInfo *)Prop -> sp_Data;
/* Is it the file format we are able
* to read?
*/
if(TermInfo -> Version == TermVersion && TermInfo -> Revision <= TermRevision && TermInfo -> Revision >= 6)
{
/* The file read pointer is positioned
* just in front of the first data
* to be read, so let's don't disappoint
* iffparse and read it.
*/
if(ReadChunkBytes(Handle,Data,Size) == Size)
Success = TRUE;
}
}
}
}
}
CloseIFF(Handle);
}
Close(Handle -> iff_Stream);
}
FreeIFF(Handle);
}
return(Success);
}
/* PushWindow(struct Window *Window):
*
* Push/PopWindow implement a single lifo window stack
* which always updates the window to activate when
* LSHIFT+RSHIFT+RETURN is pressed. This routine will
* push a window on the stack.
*/
VOID
PushWindow(struct Window *Window)
{
if(WindowStackPtr < 5)
{
WindowStack[WindowStackPtr++] = Window;
TopWindow = Window;
}
}
/* PopWindow():
*
* Remove topmost window from window stack.
*/
VOID
PopWindow()
{
if(WindowStackPtr > 0)
{
WindowStackPtr--;
if(WindowStackPtr)
TopWindow = WindowStack[WindowStackPtr - 1];
else
TopWindow = Window;
}
}