home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff388.lzh
/
DClock
/
DClock-Handler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-23
|
61KB
|
3,128 lines
/* DClock-Handler.c *********************************************************
*
* DClock-Handler.c ------ Dumb clock main handler routines,
* display clock data, handle
* DisplayBeep, etc.
*
* Author ---------------- Olaf 'Olsen' Barthel, MXM
* Brabeckstrasse 35
* D-3000 Hannover 71
*
* Federal Republic of Germany
*
* This program truly is in the PUBLIC DOMAIN. Written on a cold
* and damp September evening, hoping the next morning would be
* better.
*
* Compiled using Aztec C 5.0a, CygnusEd Professional 2 & ARexx.
*
***************************************************************************/
/* Signal flag aliases. */
#define SIG_CLICK SIGBREAKF_CTRL_C
#define SIG_CLOSE SIGBREAKF_CTRL_D
#define SIG_TIMER SIGBREAKF_CTRL_E
#define SIG_TOGGL SIGBREAKF_CTRL_F
#define SIG_SHAKE SIGBREAKF_CTRL_D
#define SIG_BENCH (1 << BenchSig)
#define SIG_WINDO (1 << Window -> UserPort -> mp_SigBit)
#define SIG_DISPL (1 << DisplaySig)
#define SIG_SPEECH (1 << SpeechSig)
/* Prototypes. */
struct InputEvent * EventHandler(struct InputEvent *Event);
VOID Click(VOID);
VOID FlushSound(VOID);
UBYTE InitSound(VOID);
UBYTE InitHandler(VOID);
VOID FlushHandler(VOID);
VOID ModifiedCloseWBench(struct Screen *);
VOID AudioBeep(VOID);
VOID VideoBeep(struct Screen *Screen,BYTE Perform);
VOID ModifiedDisplayBeep(struct Screen *Screen);
VOID PrintIt(STRPTR TimeBuff);
VOID Ring(LONG Tea);
VOID ShowTime(UBYTE ReallyDoIt,UBYTE Force);
ULONG MaxMemSize(ULONG MemType);
struct Screen * FindTheBench(VOID);
VOID ShutDown(LONG HandShake);
LONG RangeRand(LONG);
struct Process * CreateFuncProc(char *Name,LONG Priority,APTR InitCode,ULONG StackSize);
UBYTE MaxFontWidth(VOID);
VOID DeleteDummyRPort(VOID);
BYTE CreateDummyRPort(VOID);
VOID Format(VOID *,char *,...);
LONG PlayChime(VOID);
VOID StopChime(VOID);
LONG FindChunk(ULONG ChunkName,BPTR FileHandle);
LONG LoadChimeSound(char *Name);
extern VOID NewDisplayBeep(VOID);
extern VOID NewCloseWBench(VOID);
/* The ARexx server routines. */
STRPTR CheckDClockStatus(STRPTR);
VOID RexxServer(VOID);
/* Interrupt register saving functions. */
VOID int_start(VOID);
VOID int_end(VOID);
/* System specific functions. */
VOID setenv(char *,char *);
LONG _main(VOID);
/* The speech server. */
VOID SpeechServer(VOID);
/* The magic pragmas. */
#pragma regcall(EventHandler(a0))
#pragma regcall(ModifiedDisplayBeep(a0))
/* Some global data. */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
extern struct ExecBase *SysBase;
struct Library *DiskfontBase;
struct RexxHostBase *RexxHostBase;
struct Window *Window;
struct Process *HandlerProcess;
struct Process *RexxProcess;
struct MsgPort *RexxTaskPort;
struct Process *SpeechProcess;
struct DSeg *DSeg;
BYTE NewKick = FALSE;
BYTE Printed = FALSE;
LONG BenchSig = -1;
LONG DisplaySig = -1;
LONG SpeechSig = -1;
/* Our current version tag. */
const char *VersionTag = "$VER: DClock-Handler 1.27 (26 Jul 1990)\n\r";
/* Online time. */
UBYTE OnlineHours = 0,OnlineMinutes = 0,OnlineSeconds = 0;
/* The chime data. */
struct IOAudio *ChimeAudioBlock;
struct MsgPort *ChimeReplyPort;
UBYTE *ChimeWaveMap;
/* Our dummy RastPort. */
struct BitMap *DummyMap;
struct RastPort *DummyRPort;
struct TextFont *DummyFont;
BYTE DummyDepth;
/* Static DClock window size and location. */
LONG LeftEdge = 409,TopEdge = 1,Width = 176,Height = 8;
/* Audio.device control structures. */
struct MsgPort *AudioPort;
struct IOAudio *Audio;
/* Input.device control structures. */
struct MsgPort *InputDevPort;
struct IOStdReq *InputRequestBlock;
/* The interrupt handler control. */
struct Interrupt *InputHandler;
/* Console.device control structures. */
struct Device *ConsoleDevice;
struct IOStdReq *ConStdReq;
struct InputEvent *CopyEvent;
/* The library offset pointers (old ones). */
VOID *OldDisplayBeep;
VOID *OldCloseWBench;
/* External data. */
extern ULONG SoundData[67];
extern ULONG RingData[1831];
extern USHORT ClockMap[456];
extern struct TextAttr DefaultFont;
extern struct IntuiText TimeString;
extern struct NewWindow NewWindow;
extern UBYTE AnyChannel[4];
extern UBYTE SquareWave[4];
extern struct Image ClockImage;
extern struct Gadget ClockGadget[2];
extern struct NewWindow NewClockWindow;
extern struct IntuiText ClockTxt[4];
/* EventHandler(Event) :
*
* This is the main interface to the handler
* routine.
*/
struct InputEvent *
EventHandler(struct InputEvent *Event)
{
int_start();
/* User wants to toggle text and memory mode. */
if(Event -> ie_Class == IECLASS_RAWKEY && Event -> ie_Code == 0x5F && Event -> ie_Qualifier == RIGHT_AMIGA)
{
Event -> ie_Class = IECLASS_NULL;
if(DSeg -> Child)
Signal(DSeg -> Child,SIG_TOGGL);
}
/* User wants to know the time? */
if(Event -> ie_Class == IECLASS_RAWKEY && Event -> ie_Code == 0x5F && Event -> ie_Qualifier == RIGHT_ALT)
{
Event -> ie_Class = IECLASS_NULL;
if(DSeg -> Child)
Signal(DSeg -> Child,SIG_SPEECH);
}
/* Modify the time display size? */
if(Event -> ie_Class == IECLASS_RAWKEY && Event -> ie_Code == 0x46 && Event -> ie_Qualifier == RIGHT_AMIGA)
{
Event -> ie_Class = IECLASS_NULL;
if(DSeg -> Child)
Signal(DSeg -> Child,SIG_DISPL);
}
/* If we can use it, initialize the copyevent and signal
* the main process to produce a click.
*/
if(Event -> ie_Class == IECLASS_RAWKEY && !(Event -> ie_Code & IECODE_UP_PREFIX) && DSeg -> Click)
{
CopyEvent -> ie_Class = Event -> ie_Class;
CopyEvent -> ie_Code = Event -> ie_Code;
CopyEvent -> ie_Qualifier = Event -> ie_Qualifier;
/* This is safe from interrupt code, or
* at least should be.
*/
if(DSeg -> Child)
Signal(DSeg -> Child,SIG_CLICK);
}
/* I had a lot of trouble getting DClock-Handler to
* work with timer.device. Well, the only thing
* happening in time were system crashes, so I
* decided to use the timer entries of the
* InputEvent structures.
*/
if(Event -> ie_TimeStamp . tv_secs != DSeg -> LastSecs)
{
DSeg -> LastSecs = Event -> ie_TimeStamp . tv_secs;
if(DSeg -> Child)
Signal(DSeg -> Child,SIG_TIMER);
/* Each second we take a look at CIA B, port A
* to find out if a carrier signal is currently
* present at the serial port. Note that the port
* bits are low-active.
*/
if(!(ciab . ciapra & CIAF_COMCD))
{
/* Are we online? */
if(!DSeg -> Online)
{
/* Reset counters. */
OnlineHours = OnlineMinutes = OnlineSeconds = 0;
DSeg -> Online = TRUE;
}
/* Increment time counter. */
if(++OnlineSeconds == 60)
{
OnlineSeconds = 0;
if(++OnlineMinutes == 60)
{
OnlineMinutes = 0;
++OnlineHours;
}
}
}
else
DSeg -> Online = FALSE;
}
int_end();
return(Event);
}
/* Click() :
*
* Produces the click (or what did you expect?).
*/
VOID
Click()
{
char PrimaryBuffer[11]; /* Rawkey conversion buffer. */
SHORT i;
/* Erase the buffer. */
for(i = 0 ; i < 11 ; i++)
PrimaryBuffer[i] = 0;
/* Convert the input event according to the
* current keymap settings.
*/
RawKeyConvert(CopyEvent,PrimaryBuffer,10,NULL);
/* If it didn't produce a sensible result,
* don't click.
*/
if(!PrimaryBuffer[0])
return;
Audio -> ioa_Volume = DSeg -> ClickVolume;
/* Let it click. */
Tick: if(CheckIO(Audio))
BeginIO(Audio);
}
/* FlushSound() :
*
* Send the sound control data to NIL:
*/
VOID
FlushSound()
{
if(Audio)
{
/* Audio device still open? */
if(Audio -> ioa_Request . io_Device)
{
if(!CheckIO(Audio))
WaitIO(Audio);
/* Free the channel(s). */
CloseDevice(Audio);
}
/* Free the audio control block. */
FreeMem(Audio,sizeof(struct IOAudio));
}
/* Delete the replyport. */
if(AudioPort)
DeletePort(AudioPort);
}
/* InitSound() :
*
* Sets up the audio control structures.
*/
UBYTE
InitSound()
{
if(!(Audio = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC | MEMF_CLEAR)))
return(FALSE);
if(!(AudioPort = (struct MsgPort *)CreatePort(NULL,0)))
return(FALSE);
/* Open the channel. */
if(OpenDevice(AUDIONAME,0,Audio,0))
return(FALSE);
/* Try to allocate a vacant channel. */
Audio -> ioa_Request . io_Command = ADCMD_ALLOCATE;
Audio -> ioa_Request . io_Flags = ADIOF_NOWAIT;
Audio -> ioa_Request . io_Message . mn_Node . ln_Pri = 100;
Audio -> ioa_Request . io_Message . mn_ReplyPort = AudioPort;
Audio -> ioa_Data = AnyChannel;
Audio -> ioa_Length = 4;
/* Try the allocation. */
BeginIO(Audio);
/* Did it return an error? */
if(WaitIO(Audio))
return(FALSE);
/* Prepare it for the click. */
Audio -> ioa_Request . io_Command = CMD_WRITE;
Audio -> ioa_Request . io_Flags = ADIOF_PERVOL | ADIOF_NOWAIT;
Audio -> ioa_Period = 180;
Audio -> ioa_Volume = 0;
Audio -> ioa_Length = 270;
Audio -> ioa_Data = (UBYTE *)SoundData;
Audio -> ioa_Cycles = 1;
/* Click once. */
BeginIO(Audio);
WaitIO(Audio);
return(TRUE);
}
/* InitHandler() :
*
* Open the console.device for keymap translation
* and add the input.device handler.
*/
UBYTE
InitHandler()
{
if(!(ConStdReq = (struct IOStdReq *)AllocMem(sizeof(struct IOStdReq),MEMF_PUBLIC | MEMF_CLEAR)))
return(FALSE);
if(OpenDevice("console.device",-1,ConStdReq,0))
return(FALSE);
if(!(InputDevPort = (struct MsgPort *)CreatePort(NULL,0)))
return(FALSE);
if(!(InputRequestBlock = (struct IOStdReq *)CreateStdIO(InputDevPort)))
return(FALSE);
if(OpenDevice("input.device",0,InputRequestBlock,0))
return(FALSE);
if(!(InputHandler = (struct Interrupt *)AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC | MEMF_CLEAR)))
return(FALSE);
if(!(CopyEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_PUBLIC | MEMF_CLEAR)))
return(FALSE);
InputHandler -> is_Node . ln_Name = "DClock-Handler";
InputHandler -> is_Node . ln_Pri = 51;
InputHandler -> is_Code = (VOID *)EventHandler;
InputRequestBlock -> io_Command = IND_ADDHANDLER;
InputRequestBlock -> io_Data = (APTR)InputHandler;
DoIO(InputRequestBlock);
ConsoleDevice = ConStdReq -> io_Device;
return(TRUE);
}
/* FlushHandler() :
*
* Closes the console.device and removes the
* input.device handler from the chain.
*/
VOID
FlushHandler()
{
if(ConsoleDevice)
CloseDevice(ConStdReq);
if(InputRequestBlock)
{
if(InputRequestBlock -> io_Device)
{
InputRequestBlock -> io_Command = IND_REMHANDLER;
InputRequestBlock -> io_Data = (APTR)InputHandler;
DoIO(InputRequestBlock);
CloseDevice(InputRequestBlock);
}
DeleteStdIO(InputRequestBlock);
}
if(ConStdReq)
FreeMem(ConStdReq,sizeof(struct IOStdReq));
if(CopyEvent)
FreeMem(CopyEvent,sizeof(struct InputEvent));
if(InputHandler)
FreeMem(InputHandler,sizeof(struct Interrupt));
if(InputDevPort)
DeletePort(InputDevPort);
}
/* ModifiedCloseWBench():
*
* Tells DClock to close its window before the
* Workbench screen gets closed.
*/
VOID
ModifiedCloseWBench()
{
if(Window)
{
struct Task *ThisTask = SysBase -> ThisTask;
BYTE CurrentPri;
/* Shut down... */
Signal(DSeg -> Child,SIG_BENCH);
/* Careful - rather rude window close check,
* don't waste too much time in the loop.
*/
CurrentPri = SetTaskPri(ThisTask,0);
while(Window);
SetTaskPri(ThisTask,CurrentPri);
}
}
VOID
AudioBeep()
{
struct IOAudio *AudioBlock;
struct MsgPort *ReplyPort;
/* Allocate some driver memory. */
if(AudioBlock = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC | MEMF_CLEAR))
{
/* Time for a replyport? */
if(ReplyPort = (struct MsgPort *)CreatePort(NULL,0))
{
AudioBlock -> ioa_Request . io_Message . mn_ReplyPort = ReplyPort;
if(!OpenDevice(AUDIONAME,0,AudioBlock,0))
{
/* Set up initial driver data. */
AudioBlock -> ioa_Request . io_Command = ADCMD_ALLOCATE;
AudioBlock -> ioa_Request . io_Message . mn_Node . ln_Pri = 90;
AudioBlock -> ioa_Data = &AnyChannel[0];
AudioBlock -> ioa_Length = 4;
if(!DoIO(AudioBlock))
{
AudioBlock -> ioa_Request . io_Command = CMD_WRITE;
AudioBlock -> ioa_Request . io_Flags = ADIOF_PERVOL;
AudioBlock -> ioa_Period = 447;
AudioBlock -> ioa_Volume = 64 / 2;
AudioBlock -> ioa_Cycles = 150;
AudioBlock -> ioa_Data = &SquareWave[0];
AudioBlock -> ioa_Length = 4;
/* Beeep! */
BeginIO(AudioBlock);
WaitIO(AudioBlock);
}
CloseDevice(AudioBlock);
}
DeletePort(ReplyPort);
}
FreeMem(AudioBlock,sizeof(struct IOAudio));
}
}
/* VideoBeep(Screen,Perform):
*
* Handles the visual part of the DisplayBeep,
* flashes a particular screen or restores its
* original colour (well, hope so).
*/
VOID
VideoBeep(struct Screen *Screen,BYTE Perform)
{
UBYTE R,G,B;
/* Beep this screen? */
if(Perform)
{
/* Is it already beeping? */
if(!(Screen -> Flags & BEEPING))
{
/* This one's beeping. */
Screen -> Flags |= BEEPING;
/* Don't forget this one. */
Screen -> SaveColor0 = GetRGB4(Screen -> ViewPort . ColorMap,0);
/* Reverse the colour. */
R = ((Screen -> SaveColor0 >> 8) & 0xF) ^ 0xF;
G = ((Screen -> SaveColor0 >> 4) & 0xF) ^ 0xF;
B = ((Screen -> SaveColor0 ) & 0xF) ^ 0xF;
/* Set it. */
SetRGB4(&Screen -> ViewPort,0,R,G,B);
}
}
else
{
/* Is this one beeping? */
if(Screen -> Flags & BEEPING)
{
/* This one isn't beeping any longer. */
Screen -> Flags &= ~BEEPING;
/* Restore the saved colour. */
R = ((Screen -> SaveColor0 >> 8) & 0xF);
G = ((Screen -> SaveColor0 >> 4) & 0xF);
B = ((Screen -> SaveColor0 ) & 0xF);
SetRGB4(&Screen -> ViewPort,0,R,G,B);
}
}
}
/* ModifiedDisplayBeep(Screen):
*
* Magic replacement for usual DisplayBeep()
* function.
*/
VOID
ModifiedDisplayBeep(struct Screen *Screen)
{
/* Flash a particular screen. */
if(Screen)
{
VideoBeep(Screen,TRUE);
if(DSeg -> Beep)
AudioBeep();
VideoBeep(Screen,FALSE);
}
else
{
/* Flash all screens. */
ULONG IntuiLock;
/* Where's the first one? Has anybody
* used the LockIBase() function so
* far (save me)?
*/
IntuiLock = LockIBase(NULL);
Screen = IntuitionBase -> FirstScreen;
/* Walk through the screens flashing them all. */
do
VideoBeep(Screen,TRUE);
while(Screen = Screen -> NextScreen);
UnlockIBase(IntuiLock);
/* Let it resound. */
if(DSeg -> Beep)
AudioBeep();
/* Again: where's the first screen? */
IntuiLock = LockIBase(NULL);
Screen = IntuitionBase -> FirstScreen;
do
VideoBeep(Screen,FALSE);
while(Screen = Screen -> NextScreen);
UnlockIBase(IntuiLock);
}
}
/* PrintIt(TimeBuff,CharOffset):
*
* Prints the formatted string into the Workbench title bar.
*/
VOID
PrintIt(STRPTR TimeBuff)
{
BYTE Length = strlen((char *)TimeBuff);
BYTE Offset = Width - TextLength(DummyRPort,TimeBuff,Length);
SetAPen(DummyRPort,DSeg -> TextColour);
SetBPen(DummyRPort,DSeg -> BackColour);
SetRast(DummyRPort,1);
Move(DummyRPort,(Offset >= 0 ? Offset : 0),DummyRPort -> Font -> tf_Baseline);
Text(DummyRPort,TimeBuff,Length);
}
/* Ring():
*
* This one rings the bell of the alarm clock.
*/
VOID
Ring(LONG Tea)
{
struct IOAudio *AudioBlock;
struct MsgPort *ReplyPort;
struct Screen PublicScreen;
struct Screen *FirstOne;
struct Window *ClockWindow;
struct IntuiMessage *Massage;
ULONG Class;
USHORT Code;
struct Gadget *ID;
ULONG IntuiLock;
struct View *ViewLord;
SHORT DyOffset,PlusY;
LONG TimeOut;
/* Remember initial first screen. */
IntuiLock = LockIBase(NULL);
FirstOne = IntuitionBase -> FirstScreen;
UnlockIBase(IntuiLock);
/* Knockin' on heaven's door... */
OpenWorkBench();
/* Center the clock window. */
GetScreenData(&PublicScreen,sizeof(struct Screen),WBENCHSCREEN,NULL);
NewClockWindow . LeftEdge = (PublicScreen . Width - NewClockWindow . Width) / 2;
NewClockWindow . TopEdge = (PublicScreen . Height - NewClockWindow . Height) / 2;
/* Open it and paint the background. */
if(!(ClockWindow = (struct Window *)OpenWindow(&NewClockWindow)))
{
DisplayBeep(NULL);
goto Quit;
}
if(NewKick)
SetAPen(ClockWindow -> RPort,2);
else
SetAPen(ClockWindow -> RPort,1);
RectFill(ClockWindow -> RPort,2,1,ClockWindow -> Width - 3,ClockWindow -> Height - 2);
RefreshGadgets(&ClockGadget[0],ClockWindow,NULL);
/* Adjust the contents of the alarm time string. */
if(Tea)
Format(ClockTxt[3] . IText,"Alarm time » %2ld:%02ld:%02ld «",DSeg -> AlarmHour,DSeg -> AlarmMinute,DSeg -> AlarmSecond);
else
strcpy((char *)ClockTxt[3] . IText,"Countdown elapsed!");
PrintIText(ClockWindow -> RPort,&ClockTxt[0],0,0);
/* Allocate some driver memory. */
if(AudioBlock = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC | MEMF_CLEAR))
{
/* Time for a replyport? */
if(ReplyPort = (struct MsgPort *)CreatePort(NULL,0))
{
/* Set up initial driver data. */
AudioBlock -> ioa_Data = &AnyChannel[0];
AudioBlock -> ioa_Length = 4;
AudioBlock -> ioa_Request . io_Message . mn_ReplyPort = ReplyPort;
AudioBlock -> ioa_Request . io_Message . mn_Node.ln_Pri = 80;
/* Allocate the channels on the fly. */
if(!OpenDevice(AUDIONAME,0,AudioBlock,0))
{
AudioBlock -> ioa_Request . io_Command = CMD_WRITE;
AudioBlock -> ioa_Request . io_Flags = ADIOF_PERVOL;
AudioBlock -> ioa_Period = 308;
AudioBlock -> ioa_Volume = 64;
AudioBlock -> ioa_Cycles = 1;
AudioBlock -> ioa_Data = (UBYTE *)&RingData[0];
AudioBlock -> ioa_Length = 7326;
IntuiLock = LockIBase(NULL);
ViewLord = &IntuitionBase -> ViewLord;
UnlockIBase(IntuiLock);
DyOffset = ViewLord -> DyOffset;
/* Ring! */
BeginIO(AudioBlock);
WBenchToFront();
TimeOut = 0;
/* Ring until somebody clicked our window
* or a timeout occurs.
*/
FOREVER
{
/* Cycles already finished. */
if(CheckIO(AudioBlock))
BeginIO(AudioBlock);
Class = Code = NULL;
if(Massage = GetMsg(ClockWindow -> UserPort))
{
Class = Massage -> Class;
Code = Massage -> Code;
ID = (struct Gadget *)Massage -> IAddress;
ReplyMsg(Massage);
if((Class == GADGETUP && !ID -> GadgetID) || Class == VANILLAKEY)
break;
}
PlusY = 1 - RangeRand(3);
/* Make the view vibrate. */
if(DyOffset + PlusY >= 0)
ViewLord -> DyOffset = DyOffset + PlusY;
RethinkDisplay();
/* Wait a tick. */
Delay(1);
/* Now for the timeout... */
if((TimeOut++) >= (TICKS_PER_SECOND * 30))
break;
}
ViewLord -> DyOffset = DyOffset;
RethinkDisplay();
/* Still ringing? */
if(!CheckIO(AudioBlock))
WaitIO(AudioBlock);
/* Tick! */
CloseDevice(AudioBlock);
}
DeletePort(ReplyPort);
}
FreeMem(AudioBlock,sizeof(struct IOAudio));
}
/* Bring original first screen to the front again. */
Quit: if(FirstOne != ClockWindow -> WScreen)
ScreenToBack(ClockWindow -> WScreen);
if(ClockWindow)
CloseWindow(ClockWindow);
}
/* ShowTime(ReallyDoIt,Force):
*
* Yes, it's Showtime! This one compiles the date/timestring
* and prints it.
*/
VOID
ShowTime(UBYTE ReallyDoIt,UBYTE Force)
{
UBYTE TempBuff[30];
static char *Months[12] =
{
"Jan","Feb","Mar",
"Apr","May","Jun",
"Jul","Aug","Sep",
"Oct","Nov","Dec"
};
static char *Days[7] =
{
"Sun", /* Note: these have to appear right in this order. */
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
};
static char *LongDays[7] =
{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
static char DateBuff[15],TimeBuff[10];
static UBYTE LastState = 2;
static SHORT MonthVectors[14] =
{
-1, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
};
LONG JulianDate, Day0, Day1, Day2, Day3;
LONG Year, Month, Day;
struct DateStamp Date;
DateStamp(&Date);
JulianDate = Date . ds_Days + DDELTA;
Year = (JulianDate / 146097) * 400;
Day0 = Day1 = JulianDate %= 146097;
Year += (JulianDate / 36524) * 100;
Day2 = Day1 %= 36524;
Year += (Day2 / 1461) * 4;
Day3 = Day1 %= 1461;
Year += Day3 / 365;
Month = 1 + (Day1 %= 365);
Day = Month % 30;
Month /= 30;
if((Day3 >= 59 && Day0 < 59) || (Day3 < 59 && (Day2 >= 59 || Day0 < 59)))
Day1++;
if(Day1 > MonthVectors[1 + Month])
Month++;
Day = Day1 - MonthVectors[Month];
DSeg -> CurrentTime . Year = Year;
DSeg -> CurrentTime . Month = Month;
DSeg -> CurrentTime . Day = Day;
DSeg -> CurrentTime . Weekday = Date . ds_Days % DAYS_PER_WEEK;
DSeg -> CurrentTime . Hour = Date . ds_Minute / MINS_PER_HOUR;
DSeg -> CurrentTime . Minute = Date . ds_Minute % MINS_PER_HOUR;
DSeg -> CurrentTime . Second = Date . ds_Tick / TICS_PER_SEC;
/* Did we need a change? */
if(LastState != DSeg -> Seconds)
{
LastState = DSeg -> Seconds;
Force = TRUE;
}
if(ReallyDoIt)
{
if(DSeg -> Seconds)
{
Format(TempBuff,"%s %02ld-%s-%02ld %02ld:%02ld:%02ld",
Days[DSeg -> CurrentTime . Weekday],
DSeg -> CurrentTime . Day,
Months[DSeg -> CurrentTime . Month - 1],
DSeg -> CurrentTime . Year % 100,
DSeg -> CurrentTime . Hour,
DSeg -> CurrentTime . Minute,
DSeg -> CurrentTime . Second);
PrintIt(TempBuff);
}
else
{
if(!(Date . ds_Tick / TICKS_PER_SECOND) || Force)
{
Format(TempBuff,"%s %02ld-%s-%02ld %02ld:%02ld",
Days[DSeg -> CurrentTime . Weekday],
DSeg -> CurrentTime . Day,
Months[DSeg -> CurrentTime . Month - 1],
DSeg -> CurrentTime . Year % 100,
DSeg -> CurrentTime . Hour,
DSeg -> CurrentTime . Minute);
SetRast(DummyRPort,1);
PrintIt(TempBuff);
}
}
}
if((!DSeg -> CurrentTime . Second || !Printed) && DSeg -> SetEnv)
{
Printed = TRUE;
Format(DateBuff,"%02ld-%s-%02ld",Day,Months[DSeg -> CurrentTime . Month - 1],DSeg -> CurrentTime . Year % 100);
Format(TimeBuff,"%02ld:%02ld",DSeg -> CurrentTime . Hour,DSeg -> CurrentTime . Minute);
setenv("DAY",LongDays[DSeg -> CurrentTime . Weekday]);
setenv("DATE",DateBuff);
setenv("TIME",TimeBuff);
}
}
/* MaxMemSize(MemType):
*
* Returns the length of memory block of a special
* kind. Borrowed from Louis A. Mamakos' GfxMem 0.4.
*/
ULONG
MaxMemSize(ULONG MemType)
{
ULONG BlockSize = 0;
struct MemHeader *MemHeader;
Forbid();
/* Walk through the memory lists adding the
* amount of memory bound to them.
*/
for(MemHeader = (struct MemHeader *)SysBase -> MemList . lh_Head ; MemHeader -> mh_Node . ln_Succ ; MemHeader = (struct MemHeader *)MemHeader -> mh_Node . ln_Succ)
{
if(MemHeader -> mh_Attributes & MemType)
BlockSize += ((ULONG)MemHeader -> mh_Upper - (ULONG)MemHeader -> mh_Lower);
}
Permit();
return(BlockSize);
}
/* FindTheBench():
*
* Tries to locate the Workbench screen in the linked list
* of system screens. This is rather a rude method and should
* be exercised only while Intuition is locked.
*
* This could be lot easier if using LockPubScreen().
*/
struct Screen *
FindTheBench()
{
struct Screen *WBench;
ULONG IntuiLock = LockIBase(NULL);
/* Start with the first one. */
WBench = IntuitionBase -> FirstScreen;
/* Scan the list... */
do
{
/* The type we want? */
if((WBench -> Flags & SCREENTYPE) == WBENCHSCREEN)
{
UnlockIBase(IntuiLock);
return(WBench);
}
}
while(WBench = WBench -> NextScreen);
/* Failed! */
UnlockIBase(IntuiLock);
return(NULL);
}
/* PlayChime():
*
* Plays the hour chime.
*/
LONG
PlayChime()
{
LONG Rate = 1788,Length = 4,Cycles = 150,Volume = 64 / 2;
if(ChimeReplyPort)
return(FALSE);
ObtainSemaphore(DSeg -> SoundSemaphore);
if(DSeg -> SoundData && DSeg -> SoundLength)
{
ChimeWaveMap = (UBYTE *)DSeg -> SoundData;
Length = DSeg -> SoundLength;
Volume = DSeg -> SoundVolume;
Rate = DSeg -> SoundRate;
Cycles = 1;
}
else
ChimeWaveMap = &SquareWave[0];
/* Allocate some driver memory. */
if(!(ChimeAudioBlock = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC | MEMF_CLEAR)))
{
ReleaseSemaphore(DSeg -> SoundSemaphore);
return(FALSE);
}
/* Time for a replyport? */
if(!(ChimeReplyPort = (struct MsgPort *)CreatePort(NULL,0)))
{
FreeMem(ChimeAudioBlock,sizeof(struct IOAudio));
ChimeAudioBlock = NULL;
ReleaseSemaphore(DSeg -> SoundSemaphore);
return(FALSE);
}
/* Set up initial driver data. */
ChimeAudioBlock -> ioa_Data = &AnyChannel[0];
ChimeAudioBlock -> ioa_Length = 4;
ChimeAudioBlock -> ioa_Request . io_Message . mn_ReplyPort = ChimeReplyPort;
ChimeAudioBlock -> ioa_Request . io_Message . mn_Node . ln_Pri = 90;
/* Allocate the channels on the fly. */
if(OpenDevice(AUDIONAME,0,ChimeAudioBlock,0))
{
FreeMem(ChimeAudioBlock,sizeof(struct IOAudio));
DeletePort(ChimeReplyPort);
ChimeAudioBlock = NULL;
ChimeReplyPort = NULL;
ReleaseSemaphore(DSeg -> SoundSemaphore);
return(FALSE);
}
ChimeAudioBlock -> ioa_Request . io_Command = CMD_WRITE;
ChimeAudioBlock -> ioa_Request . io_Flags = ADIOF_PERVOL;
ChimeAudioBlock -> ioa_Cycles = Cycles;
ChimeAudioBlock -> ioa_Data = ChimeWaveMap;
ChimeAudioBlock -> ioa_Length = Length;
ChimeAudioBlock -> ioa_Period = Rate;
ChimeAudioBlock -> ioa_Volume = Volume;
BeginIO(ChimeAudioBlock);
}
/* StopChime():
*
* Stops the hour chime.
*/
VOID
StopChime()
{
if(ChimeAudioBlock)
{
if(ChimeAudioBlock -> ioa_Request . io_Device)
{
if(!CheckIO(ChimeAudioBlock))
WaitIO(ChimeAudioBlock);
CloseDevice(ChimeAudioBlock);
}
if(!DSeg -> SoundData || !DSeg -> SoundLength)
{
if(ChimeWaveMap != &SquareWave[0])
FreeMem(ChimeWaveMap,4);
}
FreeMem(ChimeAudioBlock,sizeof(struct IOAudio));
DeletePort(ChimeReplyPort);
ChimeAudioBlock = NULL;
ChimeReplyPort = NULL;
ReleaseSemaphore(DSeg -> SoundSemaphore);
}
}
/* FindChunk(ChunkName,FileHandle):
*
* Tries to locate an iff-chunk inside a file.
*/
LONG
FindChunk(ULONG ChunkName,BPTR FileHandle)
{
LONG OldPosition;
ULONG FormType = 0;
/* The format of a typical IFF-chunk. */
struct
{
ULONG IFF_Type;
ULONG IFF_Length;
} Chunk;
/* Remember initial file position. */
OldPosition = Seek(FileHandle,0,OFFSET_CURRENT);
/* Try to find it. */
FOREVER
{
/* Read the first bytes. */
if(Read(FileHandle,&Chunk,sizeof(Chunk)) != sizeof(Chunk))
{
Seek(FileHandle,OldPosition,OFFSET_BEGINNING);
return(FALSE);
}
/* Is it a FORM-chunk? */
if(OldPosition == 0 && FormType == 0 && Chunk . IFF_Type == 'FORM')
{
Read(FileHandle,&FormType,sizeof(LONG));
/* Check the form type. */
if(FormType == ChunkName)
return(TRUE);
continue;
}
/* Is it the chunk type we want? */
if(Chunk . IFF_Type == ChunkName)
return(TRUE);
/* Skip chunk. */
Seek(FileHandle,Chunk . IFF_Length,OFFSET_CURRENT);
}
}
/* LoadChimeSound(Name):
*
* Loads an IFF-8SVX-soundfile to be used as the hour
* chime sound.
*/
LONG
LoadChimeSound(char *Name)
{
BPTR SoundHandle;
APTR SoundData;
LONG SoundRate,SoundLength,SoundVolume;
/* The format of the VoiceHeader-chunk. */
struct
{
ULONG oneShotHiSamples,
repeatHiSamples,
samplesPerHiCycle;
UWORD samplesPerSec;
UBYTE ctOctave,
sCompression;
LONG volume;
} VoiceHeader;
/* No name? Reset to defaults. */
if(!RexxStrCmp(Name,"OFF"))
{
ObtainSemaphore(DSeg -> SoundSemaphore);
/* Free the memory. */
if(DSeg -> SoundLength && DSeg -> SoundData)
FreeMem(DSeg -> SoundData,DSeg -> SoundLength);
/* Mark sound slot as vacant. */
DSeg -> SoundLength = 0;
DSeg -> SoundData = NULL;
ReleaseSemaphore(DSeg -> SoundSemaphore);
return(TRUE);
}
/* Open the file for reading. */
if(!(SoundHandle = Open(Name,MODE_OLDFILE)))
return(FALSE);
/* Is it a sound file? */
if(!FindChunk('8SVX',SoundHandle))
{
Close(SoundHandle);
return(FALSE);
}
/* Look for the VoiceHeader. */
if(!FindChunk('VHDR',SoundHandle))
{
Close(SoundHandle);
return(FALSE);
}
/* Read the header. */
if(Read(SoundHandle,&VoiceHeader,sizeof(VoiceHeader)) != sizeof(VoiceHeader))
{
Close(SoundHandle);
return(FALSE);
}
/* Fill in the more important information. */
SoundLength = VoiceHeader . oneShotHiSamples + VoiceHeader . repeatHiSamples;
SoundRate = ((GfxBase -> DisplayFlags & PAL) ? 3546895 : 3579545) / VoiceHeader . samplesPerSec;
SoundVolume = (VoiceHeader . volume > 64 ? 64 : VoiceHeader . volume);
/* Proceed with the body chunk. */
if(!FindChunk('BODY',SoundHandle))
{
Close(SoundHandle);
return(FALSE);
}
/* Allocate space for the sound data. */
if(!(SoundData = (APTR)AllocMem(SoundLength,MEMF_PUBLIC | MEMF_CHIP)))
{
Close(SoundHandle);
return(FALSE);
}
/* Read the sound data. */
if(Read(SoundHandle,SoundData,SoundLength) != SoundLength)
{
FreeMem(SoundData,SoundLength);
Close(SoundHandle);
return(FALSE);
}
/* Close the file. */
Close(SoundHandle);
/* Lock access to sound data. */
ObtainSemaphore(DSeg -> SoundSemaphore);
/* Free last sound. */
if(DSeg -> SoundLength && DSeg -> SoundData)
FreeMem(DSeg -> SoundData,DSeg -> SoundLength);
/* Fill in the data. */
DSeg -> SoundData = SoundData;
DSeg -> SoundLength = SoundLength;
DSeg -> SoundRate = SoundRate;
DSeg -> SoundVolume = SoundVolume;
/* Unlock it again. */
ReleaseSemaphore(DSeg -> SoundSemaphore);
return(TRUE);
}
/* CheckDClockStatus(Arg):
*
* Checks DClock option flags and returns them.
*/
STRPTR
CheckDClockStatus(STRPTR Arg)
{
/* Static result string. */
STATIC UBYTE Response[200];
/* Every option to be checked. */
STATIC STRPTR Options[17] =
{
"BEEP",
"CLICK",
"CLICKVOLUME",
"PRIORITY",
"TEXTCOLOUR",
"BACKCOLOUR",
"ALARM",
"ALARMTIME",
"SETENV",
"VERSION",
"COUNTDOWN",
"HOUR",
"SECONDS",
"SOUND",
"PAGE",
"SPEECH",
"LINE"
};
/* A temporary string. */
UBYTE TempString[20];
LONG i,TheOption = -1;
/* Clear the string. */
Response[0] = 0;
/* Check which option matches the argument.
* If none matches we'll produce a string
* filled with all options.
*/
for(i = 0 ; i < 16 ; i++)
{
if(!RexxStrCmp(Arg,Options[i]))
{
TheOption = i;
break;
}
}
/* Is it BEEP? */
if(TheOption == 0 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response,Options[0]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Beep ? "ON" : "OFF"));
}
/* Is it CLICK? */
if(TheOption == 1 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[1]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Click ? "ON" : "OFF"));
}
/* Is it CLICKVOLUME? */
if(TheOption == 2 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[2]);
strcat(Response," ");
}
BuildValueString(DSeg -> ClickVolume,TempString);
strcat(Response,TempString);
}
/* Is it PRIORITY? */
if(TheOption == 3 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[3]);
strcat(Response," ");
}
BuildValueString(DSeg -> Priority,TempString);
strcat(Response,TempString);
}
/* Is it TEXTCOLOUR? */
if(TheOption == 4 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[4]);
strcat(Response," ");
}
BuildValueString(DSeg -> TextColour,TempString);
strcat(Response,TempString);
}
/* Is it BACKCOLOUR? */
if(TheOption == 5 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[5]);
strcat(Response," ");
}
BuildValueString(DSeg -> Priority,TempString);
strcat(Response,TempString);
}
/* Is it ALARM? */
if(TheOption == 6 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[6]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Alarm ? "ON" : "OFF"));
}
/* Is it ALARMTIME? */
if(TheOption == 7 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[7]);
strcat(Response," ");
}
Format(TempString,"%02ld:%02ld:%02ld",DSeg -> AlarmHour,DSeg -> AlarmMinute,DSeg -> AlarmSecond);
strcat(Response,TempString);
}
/* Is it SETENV? */
if(TheOption == 8 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[8]);
strcat(Response," ");
}
strcat(Response,(DSeg -> SetEnv ? "ON" : "OFF"));
}
/* Is it VERSION? */
if(TheOption == 9 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[9]);
strcat(Response," ");
}
BuildValueString(DSeg -> Revision,TempString);
strcat(Response,TempString);
}
/* Is it COUNTDOWN? */
if(TheOption == 10 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[10]);
strcat(Response," ");
}
BuildValueString(DSeg -> Countdown,TempString);
strcat(Response,TempString);
}
/* Is it HOUR? */
if(TheOption == 11 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[11]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Hour ? "ON" : "OFF"));
}
/* Is it SECONDS? */
if(TheOption == 12 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[12]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Seconds ? "ON" : "OFF"));
}
/* Is it SOUND? */
if(TheOption == 13 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[13]);
strcat(Response," ");
}
strcat(Response,((DSeg -> SoundData && DSeg -> SoundLength) ? "ON" : "OFF"));
}
/* Is it PAGE? */
if(TheOption == 14 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[14]);
strcat(Response," ");
}
BuildValueString(DSeg -> Page,TempString);
strcat(Response,TempString);
}
/* Is it SPEECH? */
if(TheOption == 15 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[15]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Speech ? "ON" : "OFF"));
}
/* Is it LINE? */
if(TheOption == 16 || TheOption == -1)
{
if(TheOption == -1)
{
strcat(Response," ");
strcat(Response,Options[16]);
strcat(Response," ");
}
strcat(Response,(DSeg -> Online ? "ON" : "OFF"));
}
/* Return the result of our 'questionnaire'. */
return(Response);
}
/* RexxServer():
*
* Rexx server subtask (process), handles the rexx commands
* asynchronously.
*/
VOID
RexxServer()
{
struct RexxMessage *RexxMsg; /* Rexx signal message. */
ULONG SignalSet; /* Incoming signals. */
STRPTR StringResult; /* Result string (error message). */
LONG NumResult; /* Return code. */
LONG ArgCount; /* String counter. */
UBYTE Arg1[20],Arg2[20]; /* Both arguments. */
/* Get the base register (hey Manx, where's
* the __saveds equivalent?).
*/
geta4();
/* Create the communication port. */
if(!(RexxTaskPort = (struct MsgPort *)CreatePort(NULL,0)))
goto Quit;
/* Synchronization. */
Signal(HandlerProcess,SIG_SHAKE);
/* Ad infinitum. */
FOREVER
{
/* Wait for a signal. */
SignalSet = Wait(SIG_CLOSE | (1 << RexxTaskPort -> mp_SigBit));
/* A rexx message? */
if(SignalSet & (1 << RexxTaskPort -> mp_SigBit))
{
/* Intercept all messages. */
while(RexxMsg = GetMsg(RexxTaskPort))
{
ArgCount = 0;
/* Get the command string. */
StringResult = GetRexxCommand(RexxMsg);
/* Get command and argument. */
GetToken(StringResult,&ArgCount,Arg1,20);
GetToken(StringResult,&ArgCount,Arg2,20);
/* Zero default values. */
StringResult = NULL;
NumResult = 0;
/* Adjust Click volume? */
if(!RexxStrCmp(Arg1,"CLICKVOLUME"))
{
if(GetStringValue(Arg2) > 64 || GetStringValue(Arg2) < 0)
NumResult = 10;
else
DSeg -> ClickVolume = GetStringValue(Arg2);
}
/* Adjust task priority? */
if(!RexxStrCmp(Arg1,"PRIORITY"))
{
if(GetStringValue(Arg2) > 127 || GetStringValue(Arg2) < -128)
NumResult = 10;
else
{
DSeg -> Priority = GetStringValue(Arg2);
SetTaskPri(DSeg -> Child,DSeg -> Priority);
}
}
/* Turn DisplayBeep() off? */
if(!RexxStrCmp(Arg1,"BEEP"))
{
if(!RexxStrCmp(Arg2,"OFF"))
DSeg -> Beep = FALSE;
else
{
if(!RexxStrCmp(Arg2,"ON"))
DSeg -> Beep = TRUE;
else
NumResult = 10;
}
}
/* Turn keyboard click off? */
if(!RexxStrCmp(Arg1,"CLICK"))
{
if(!RexxStrCmp(Arg2,"OFF"))
DSeg -> Click = FALSE;
else
{
if(!RexxStrCmp(Arg2,"ON"))
DSeg -> Click = TRUE;
else
NumResult = 10;
}
}
/* Set text colour? */
if(!RexxStrCmp(Arg1,"TEXTCOLOUR"))
DSeg -> TextColour = GetStringValue(Arg2);
/* Set background colour? */
if(!RexxStrCmp(Arg1,"BACKCOLOUR"))
DSeg -> BackColour = GetStringValue(Arg2);
/* Turn alarm on? */
if(!RexxStrCmp(Arg1,"ALARM"))
{
if(!RexxStrCmp(Arg2,"OFF"))
DSeg -> Alarm = FALSE;
else
{
if(!RexxStrCmp(Arg2,"ON"))
DSeg -> Alarm = TRUE;
else
NumResult = 10;
}
}
/* Set alarm time? */
if(!RexxStrCmp(Arg1,"ALARMTIME"))
{
char TimeBuff[3];
LONG TheTime;
TimeBuff[2] = 0;
TimeBuff[0] = Arg2[0];
TimeBuff[1] = Arg2[1];
TheTime = GetStringValue(TimeBuff);
if(TheTime >= 0 && TheTime <= 23)
DSeg -> AlarmHour = TheTime;
else
NumResult = 10;
TimeBuff[0] = Arg2[3];
TimeBuff[1] = Arg2[4];
TheTime = GetStringValue(TimeBuff);
if(TheTime >= 0 && TheTime <= 59)
DSeg -> AlarmMinute = TheTime;
else
NumResult = 10;
TimeBuff[0] = Arg2[6];
TimeBuff[1] = Arg2[7];
TheTime = GetStringValue(TimeBuff);
if(TheTime >= 0 && TheTime <= 59)
DSeg -> AlarmSecond = TheTime;
else
NumResult = 10;
}
/* Set environment variables? */
if(!RexxStrCmp(Arg1,"SETENV"))
{
if(!RexxStrCmp(Arg2,"OFF"))
DSeg -> SetEnv = FALSE;
else
{
if(!RexxStrCmp(Arg2,"ON"))
DSeg -> SetEnv = TRUE;
else
NumResult = 10;
}
}
/* Set the countdown tea timer? */
if(!RexxStrCmp(Arg1,"COUNTDOWN"))
{
if(GetStringValue(Arg2) > 0)
DSeg -> Countdown = GetStringValue(Arg2);
else
NumResult = 10;
}
/* Refresh the display? */
if(!RexxStrCmp(Arg1,"REFRESH"))
{
if(CloseWorkBench())
OpenWorkBench();
}
/* Turn hour alarm on? */
if(!RexxStrCmp(Arg1,"HOUR"))
{
if(!RexxStrCmp(Arg2,"OFF"))
DSeg -> Hour = FALSE;
else
{
if(!RexxStrCmp(Arg2,"ON"))
DSeg -> Hour = TRUE;
else
NumResult = 10;
}
}
/* Turn keyboard click off? */
if(!RexxStrCmp(Arg1,"SECONDS"))
{
if(!RexxStrCmp(Arg2,"OFF"))
DSeg -> Seconds = FALSE;
else
{
if(!RexxStrCmp(Arg2,"ON"))
DSeg -> Seconds = TRUE;
else
NumResult = 10;
}
}
/* Load a sound file? */
if(!RexxStrCmp(Arg1,"SOUND"))
{
if(!LoadChimeSound(Arg2))
NumResult = 10;
}
/* Get a DClock status. */
if(!RexxStrCmp(Arg1,"STATUS"))
StringResult = CheckDClockStatus(Arg2);
/* Show a special page? */
if(!RexxStrCmp(Arg1,"PAGE"))
{
if(GetStringValue(Arg2) > 4 || GetStringValue(Arg2) < 0 || (GetStringValue(Arg2) == 4 && DSeg -> Countdown < 1))
NumResult = 10;
else
DSeg -> Page = GetStringValue(Arg2);
}
/* Tell the current time? */
if(!RexxStrCmp(Arg1,"TELLTIME"))
{
if(!SpeechProcess)
{
Forbid();
if(SpeechProcess = CreateFuncProc("DClock-Speech",5,SpeechServer,4000))
Wait(SIG_SHAKE);
Permit();
}
if(SpeechProcess)
Signal(SpeechProcess,SIG_CLICK);
}
/* Read the clock chip? */
if(!RexxStrCmp(Arg1,"READTIME"))
{
if(!ReadClock())
NumResult = 10;
}
/* Reply the rexx command. */
ReplyRexxCommand(RexxMsg,NumResult,0,StringResult);
}
}
/* Remove the server task. */
if(SignalSet & SIG_CLOSE)
break;
}
/* Delete the port. */
Quit: if(RexxTaskPort)
DeletePort(RexxTaskPort);
/* Hey, I'm done! */
Signal(HandlerProcess,SIG_SHAKE);
}
/* SpeechServer():
*
* Asks the narrator device to tell the time.
*/
VOID
SpeechServer()
{
ULONG SignalSet; /* Signal mask. */
struct MsgPort *NarratorPort; /* Narrator reply port. */
struct narrator_rb *NarratorRequest; /* Narrator device link. */
char WorkString[40]; /* Phoneme string. */
/* Numbers above twenty. */
static char *AboveTwenty[4] =
{
"TWEH4NTIY4",
"THER4TIY4",
"FOH4RTIY4",
"FIH4FTIY4"
};
/* Numbers from zero to nineteen. */
static char *SingleNumbers[20] =
{
"ZIY4ROW",
"WAH4N",
"TUW4",
"THRIY4",
"FOH4R",
"FAY4V",
"SIH4KKSZ",
"SEH4VVEHN",
"EY4T",
"NAY4N",
"TEH4N",
"IY4LAEEHFAEEHN",
"TWEH4LF",
"THER4TIY4N",
"FOH4RTIY4N",
"FIH4FTIY4N",
"SIH4KKSZTIY4N",
"SEH4VVEHNTIY4N",
"EY3TIY4N",
"NAY4NTIY4N"
};
/* The two halves of the day. */
static char *TimeOfDay[2] =
{
" EY5EH3M.",
" BPIY5EH3M."
};
/* Get the data base register. */
geta4();
/* Allocate speech driver data. */
if(NarratorPort = CreatePort(NULL,0))
{
if(NarratorRequest = (struct narrator_rb *)CreateExtIO(NarratorPort,sizeof(struct narrator_rb)))
{
/* Say which channels we need. */
NarratorRequest -> ch_masks = &AnyChannel[0];
NarratorRequest -> nm_masks = 4;
/* This is a write request. */
NarratorRequest -> message . io_Command = CMD_WRITE;
NarratorRequest -> message . io_Data = (APTR)WorkString;
/* Try to open the speech driver. */
if(!OpenDevice("narrator.device",0,NarratorRequest,0))
{
/* Handshake with handler process. */
Signal(HandlerProcess,SIG_SHAKE);
FOREVER
{
/* Wait for signal. */
SignalSet = Wait(SIG_CLOSE | SIG_CLICK);
/* Are we to shut down? */
if(SignalSet & SIG_CLOSE)
break;
/* Prevent time data from being changed. */
Forbid();
strcpy(WorkString,"IH4THZ ");
/* Is the hour below twelve? */
if(DSeg -> CurrentTime . Hour <= 12)
strcat(WorkString,SingleNumbers[DSeg -> CurrentTime . Hour]);
/* Is it above twelve? */
if(DSeg -> CurrentTime . Hour > 12)
strcat(WorkString,SingleNumbers[DSeg -> CurrentTime . Hour - 12]);
strcat(WorkString," EH4KLAA4K ");
/* Are the minutes above zero and below twenty? */
if(DSeg -> CurrentTime . Minute < 20 && DSeg -> CurrentTime . Minute > 0)
strcat(WorkString,SingleNumbers[DSeg -> CurrentTime . Minute]);
/* Are the minutes above twenty? */
if(DSeg -> CurrentTime . Minute >= 20)
{
/* Append the tenths first. */
strcat(WorkString,AboveTwenty[DSeg -> CurrentTime . Minute / 10 - 2]);
/* Add the minutes if any. */
if(DSeg -> CurrentTime . Minute % 10)
strcat(WorkString,SingleNumbers[DSeg -> CurrentTime . Minute % 10]);
}
/* Add a.m./p.m. */
if(DSeg -> CurrentTime . Hour > 12)
strcat(WorkString,TimeOfDay[1]);
else
{
if(DSeg -> CurrentTime . Hour > 0 && DSeg -> CurrentTime . Hour < 12)
strcat(WorkString,TimeOfDay[0]);
}
Permit();
/* Remember the length (-1 doesn't work here for some reason). */
NarratorRequest -> message . io_Length = strlen(WorkString);
/* Say it and wait for it to terminate. */
SendIO(NarratorRequest);
WaitIO(NarratorRequest);
GetMsg(NarratorPort);
}
/* Deallocate our resources and exit. */
while(!CheckIO(NarratorRequest))
{
AbortIO(NarratorRequest);
WaitIO(NarratorRequest);
GetMsg(NarratorPort);
}
CloseDevice(NarratorRequest);
}
DeleteExtIO(NarratorRequest);
}
DeletePort(NarratorPort);
}
/* Lock & quit. */
Forbid();
SpeechProcess = NULL;
Signal(HandlerProcess,SIG_SHAKE);
}
/* CreateFuncProc():
*
* Similar to CreateTask this routine will start a
* 'C' function as a process. The technique used
* by this nifty little piece of code was originally
* conceived by Leo Schwab.
*/
struct Process *
CreateFuncProc(char *Name,LONG Priority,APTR InitCode,ULONG StackSize)
{
struct Process *ChildProc = NULL;
struct
{
ULONG SegLength; /* Length of segment. */
BPTR NextSeg; /* Pointer to next segment. */
WORD FirstCode; /* First instruction (JMP). */
APTR RealCode; /* Address of function. */
} *FakeSeg;
/* Allocate the segment. */
if(FakeSeg = (struct FakeSeg *)AllocMem(sizeof(*FakeSeg),MEMF_PUBLIC | MEMF_CLEAR))
{
struct MsgPort *ChildPort;
/* Fill in the data. */
FakeSeg -> SegLength = sizeof(*FakeSeg);
FakeSeg -> FirstCode = 0x4EF9; /* JMP EA */
FakeSeg -> RealCode = InitCode; /* EA */
/* Create the process. */
if(ChildPort = (struct MsgPort *)CreateProc(Name,Priority,MKBADDR(&FakeSeg -> NextSeg),StackSize))
ChildProc = (struct Process *)ChildPort -> mp_SigTask;
Delay(TICKS_PER_SECOND / 2);
/* Free the segment. */
FreeMem(FakeSeg,sizeof(*FakeSeg));
}
/* Return the pointer to the process. */
return(ChildProc);
}
/* CreateDummyRPort():
*
* Creates a hidden RastPort for time/graphics
* rendering.
*/
BYTE
CreateDummyRPort()
{
struct TextAttr FontRequest;
SHORT i;
/* Allocate the BitMap. */
if(!(DummyMap = (struct DummyMap *)AllocMem(sizeof(struct BitMap),MEMF_PUBLIC | MEMF_CLEAR)))
return(FALSE);
/* How many bitplanes are there in the display? */
DummyDepth = Window -> RPort -> BitMap -> Depth;
/* Initialize the bitmap pointers. */
InitBitMap(DummyMap,DummyDepth,Width,Height);
/* Allocate the memory. */
for(i = 0 ; i < DummyDepth ; i++)
{
if(!(DummyMap -> Planes[i] = AllocMem(Byte(Width) * Height,MEMF_CHIP)))
return(FALSE);
}
/* Mangle the RastPort. */
if(!(DummyRPort = (struct RastPort *)AllocMem(sizeof(struct RastPort),MEMF_PUBLIC | MEMF_CLEAR)))
return(FALSE);
/* Initialize the RastPort. */
InitRastPort(DummyRPort);
/* Link it to the BitMap. */
DummyRPort -> BitMap = DummyMap;
/* Clear the drawing area. */
SetRast(DummyRPort,1);
/* Copy the font attributes. */
FontRequest . ta_Name = (STRPTR)Window -> IFont -> tf_Message . mn_Node . ln_Name;
FontRequest . ta_YSize = Window -> IFont -> tf_YSize;
FontRequest . ta_Style = Window -> IFont -> tf_Style;
FontRequest . ta_Flags = Window -> IFont -> tf_Flags;
/* Can we open the font (is it already in the system
* list)?
*/
if(!(DummyFont = (struct TextFont *)OpenFont(&FontRequest)))
{
/* It is probably a diskfont. */
if(DiskfontBase = (struct Library *)OpenLibrary("diskfont.library",0))
{
if(!(DummyFont = (struct TextFont *)OpenDiskFont(&FontRequest)))
return(FALSE);
else
CloseLibrary(DiskfontBase);
}
}
/* Attach the font to the RastPort. */
SetFont(DummyRPort,DummyFont);
/* And set the drawing mode. */
SetDrMd(DummyRPort,JAM2);
return(TRUE);
}
/* DeleteDummyRPort():
*
* Removes the hidden RastPort from memory and get rid
* of the font attached to it.
*/
VOID
DeleteDummyRPort()
{
SHORT i;
if(DummyMap)
{
for(i = 0 ; i < DummyDepth ; i++)
if(DummyMap -> Planes[i])
FreeMem(DummyMap -> Planes[i],Byte(Width) * Height);
FreeMem(DummyMap,sizeof(struct BitMap));
DummyMap = NULL;
}
if(DummyRPort)
{
FreeMem(DummyRPort,sizeof(struct RastPort));
DummyRPort = NULL;
}
if(DummyFont)
{
CloseFont(DummyFont);
DummyFont = NULL;
}
}
/* MaxFontWidth():
*
* Calculate the maximum width of the display by looking for
* the widest letter.
*/
UBYTE
MaxFontWidth()
{
BYTE FontWidth = 0,TempWidth;
char Shuttle[2];
SHORT i;
/* We cannot use a single character to check the width
* of a letter, so we'll fake a string.
*/
Shuttle[1] = 0;
/* Check all letters. */
for(i = 0 ; i < 256 ; i++)
{
Shuttle[0] = i;
/* Is it wider than the last letter. */
if((TempWidth = TextLength(Window -> RPort,Shuttle,1)) > FontWidth)
FontWidth = TempWidth;
}
return(FontWidth);
}
/* ShutDown(HandShake):
*
* Closes DClock and waits for removal.
*/
VOID
ShutDown(LONG HandShake)
{
/* Restore system functions. */
if(OldDisplayBeep)
SetFunction((struct Library *)IntuitionBase,-0x60,OldDisplayBeep);
if(OldCloseWBench)
SetFunction((struct Library *)IntuitionBase,-0x4E,OldCloseWBench);
FlushHandler();
FlushSound();
if(Window)
{
SetRast(DummyRPort,1);
ClipBlit(DummyRPort,0,0,Window -> WScreen -> BarLayer -> rp,LeftEdge,1,Width,Height,0xC0);
CloseWindow(Window);
}
DeleteDummyRPort();
/* Return the special signals. */
if(BenchSig != -1)
FreeSignal(BenchSig);
if(DisplaySig != 1)
FreeSignal(DisplaySig);
if(SpeechSig != 1)
FreeSignal(SpeechSig);
/* Free the Rexx host port. */
if(DSeg -> RexxHost)
DeleteRexxHost(DSeg -> RexxHost);
if(RexxProcess)
{
Signal(RexxProcess,SIG_CLOSE);
Wait(SIG_SHAKE);
}
if(SpeechProcess)
{
Signal(SpeechProcess,SIG_CLOSE);
Wait(SIG_SHAKE);
}
if(RexxHostBase)
CloseLibrary(RexxHostBase);
if(IntuitionBase)
CloseLibrary(IntuitionBase);
if(GfxBase)
CloseLibrary(GfxBase);
/* Sneak out before someone can
* UnLoadSeg() us.
*/
Forbid();
/* Goodbye father. */
if(DSeg -> Father)
Signal(DSeg -> Father,HandShake);
}
/* _main():
*
* Modified Aztec C startup-routine, no CLI parsing,
* no Workbench parsing, absolutely nothing.
*/
LONG
_main()
{
volatile ULONG MemSize,MaxSize;
ULONG SignalSet;
UBYTE Force,Blink = FALSE,i,EmptyWidth,FullWidth;
LONG RexxMask = 0;
struct Screen *Workbench;
HandlerProcess = (struct Process *)SysBase -> ThisTask;
/* If somebody called us from CLI... */
if(HandlerProcess -> pr_CLI)
return(-1);
/* Is the DSeg structure anywhere? */
if(!(DSeg = (struct DSeg *)FindPort(PORTNAME)))
{
Forbid();
Signal(DSeg -> Father,DSeg -> RingBack);
return;
}
/* Check if it's below our current revision
* number (probably doesn't support some
* structure tags).
*/
if(DSeg -> Revision < REVISION)
{
Forbid();
Signal(DSeg -> Father,DSeg -> RingBack);
return;
}
/* Open those libraries. */
if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
{
Forbid();
Signal(DSeg -> Father,DSeg -> RingBack);
return;
}
if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
{
ShutDown(DSeg -> RingBack);
return;
}
/* Open RexxHostLibrary if possible. If the open
* fails, it doesn't matter.
*/
RexxHostBase = OpenLibrary("rexxhost.library",34);
/* Try to find the Workbench screen. */
if(!(Workbench = (struct Screen *)FindTheBench()))
{
ShutDown(DSeg -> RingBack);
return;
}
/* Open the backdrop window. */
if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
{
ShutDown(DSeg -> RingBack);
return;
}
/* Initialize the click sound data. */
if(!InitSound())
{
ShutDown(DSeg -> RingBack);
return;
}
/* Install the handler code. */
if(!InitHandler())
{
ShutDown(DSeg -> RingBack);
return;
}
if((BenchSig = AllocSignal(-1)) == -1)
{
ShutDown(DSeg -> RingBack);
return;
}
if((DisplaySig = AllocSignal(-1)) == -1)
{
ShutDown(DSeg -> RingBack);
return;
}
if((SpeechSig = AllocSignal(-1)) == -1)
{
ShutDown(DSeg -> RingBack);
return;
}
/* Adjust the window left offset. */
Width = MaxFontWidth() * 22;
Height = Window -> IFont -> tf_YSize;
LeftEdge = Workbench -> Width - 55 - Width;
EmptyWidth = TextLength(Window -> RPort,"E",1);
FullWidth = TextLength(Window -> RPort,"F",1);
/* Create the dummy RastPort. */
if(!CreateDummyRPort())
{
ShutDown(DSeg -> RingBack);
return;
}
/* Check if we are running unter Kickstart 2.x. */
if(SysBase -> LibNode . lib_Version >= 36)
{
USHORT TempCol;
NewKick = TRUE;
for(i = 0 ; i < 228 ; i++)
{
TempCol = ClockMap[i];
ClockMap[i] = ClockMap[i + 228];
ClockMap[i + 228] = TempCol;
}
for(i = 0 ; i < 3 ; i++)
ClockTxt[i] . FrontPen = 1;
LeftEdge = Workbench -> Width - 25 - Width;
}
/* Create the rexx server task. */
if(RexxHostBase)
{
if(!(RexxProcess = (struct Process *)CreateFuncProc("DClock-Rexx",5,RexxServer,4000)))
{
Shut: ShutDown(DSeg -> RingBack);
return;
}
/* Wait for handshake. */
Wait(SIG_SHAKE);
/* No port? Fail fast! */
if(!RexxTaskPort)
goto Shut;
}
/* Fill in the window and bring it to the front. */
ShowTime(FALSE,TRUE);
/* Patch system function. */
OldDisplayBeep = SetFunction((struct Library *)IntuitionBase,-0x60,NewDisplayBeep);
OldCloseWBench = SetFunction((struct Library *)IntuitionBase,-0x4E,NewCloseWBench);
/* If RexxHostBase is around, add the rexx port. */
if(RexxHostBase)
{
if(DSeg -> RexxHost = CreateRexxHost("DCLOCK"))
RexxMask = (1 << DSeg -> RexxHost -> rh_Port . mp_SigBit);
}
/* Initialize the signal-semaphore. */
InitSemaphore(DSeg -> SoundSemaphore);
/* Now we are truly running. */
DSeg -> Child = SysBase -> ThisTask;
/* How much memory is there around in this
* Amiga?
*/
MaxSize = MaxMemSize(MEMF_CHIP) + MaxMemSize(MEMF_FAST);
/* Tell father to finish. */
Signal(DSeg -> Father,DSeg -> RingBack);
DSeg -> Father = NULL;
/* Go into infinite loop waiting for signals. */
FOREVER
{
SignalSet = Wait(SIG_TIMER | SIG_CLOSE | SIG_CLICK | SIG_TOGGL | SIG_BENCH | SIG_WINDO | SIG_DISPL | SIG_SPEECH | RexxMask);
/* Was it a Rexx call? */
if((SignalSet & RexxMask) && RexxMask)
{
struct RexxMessage *RexxMsg;
/* Capture the messages... */
while(RexxMsg = GetMsg((struct MsgPort *)DSeg -> RexxHost))
{
/* Send them to the rexx server task. */
if(GetRexxCommand(RexxMsg))
PutMsg(RexxTaskPort,RexxMsg);
else
FreeRexxCommand(RexxMsg);
}
}
/* Change the display mode? */
if(SignalSet & SIG_TOGGL)
{
DSeg -> Page++;
SetRast(DummyRPort,1);
if(DSeg -> Page == 5)
DSeg -> Page = 0;
if(DSeg -> Countdown < 1 && DSeg -> Page == 4)
DSeg -> Page = 0;
Force = TRUE;
}
/* Are we to click? */
if((SignalSet & SIG_CLICK) && DSeg -> Click)
Click();
/* Are we to shut down? */
if(SignalSet & SIG_CLOSE)
{
if(ChimeAudioBlock)
StopChime();
ShutDown(SIG_CLOSE);
return;
}
if(SignalSet & SIG_BENCH)
{
/* Close the window... */
if(Window)
{
CloseWindow(Window);
Window = NULL;
DeleteDummyRPort();
Delay(25);
FOREVER
{
/* Wait for wakeup call... */
if((SetSignal(NULL,NULL) & SIG_CLOSE) == SIG_CLOSE)
{
SetSignal(NULL,SIG_CLOSE);
SignalSet = SIG_CLOSE;
break;
}
if(Workbench = (struct Screen *)FindTheBench())
{
SignalSet = NULL;
break;
}
Delay(25);
}
}
/* Finish? */
if(SignalSet & SIG_CLOSE)
{
if(ChimeAudioBlock)
StopChime();
ShutDown(SIG_CLOSE);
return;
}
/* Open the window. */
if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
{
BeatIt: if(ChimeAudioBlock)
StopChime();
ShutDown(SIG_CLOSE);
return;
}
Width = MaxFontWidth() * 22;
Height = Window -> IFont -> tf_YSize;
/* Re-adjust the Window offset. */
if(NewKick)
LeftEdge = Workbench -> Width - 25 - Width;
else
LeftEdge = Workbench -> Width - 55 - Width;
EmptyWidth = TextLength(Window -> RPort,"E",1);
FullWidth = TextLength(Window -> RPort,"F",1);
/* Redraw the time if necessary. */
Printed = FALSE;
if(!CreateDummyRPort())
goto BeatIt;
}
/* A window refresh call came in. */
if(SignalSet & SIG_WINDO)
{
struct IntuiMessage *IMsg;
/* Reply the Message (don't need it). */
if(IMsg = GetMsg(Window -> UserPort))
ReplyMsg(IMsg);
}
/* Give it a brief beep to indicate the hour? */
if(DSeg -> Hour && !DSeg -> CurrentTime . Minute && !DSeg -> CurrentTime . Second)
PlayChime();
/* Check if chime has ended. */
if(ChimeAudioBlock)
{
if(CheckIO(ChimeAudioBlock))
StopChime();
}
/* Ready to ring the bell? */
if(DSeg -> CurrentTime . Hour == DSeg -> AlarmHour &&
DSeg -> CurrentTime . Minute == DSeg -> AlarmMinute &&
DSeg -> CurrentTime . Second == DSeg -> AlarmSecond &&
DSeg -> Alarm)
Ring(TRUE);
/* If needed, decrement the tea timer. */
if(DSeg -> Countdown > 0)
{
if(!(--DSeg -> Countdown))
Ring(FALSE);
}
/* Check the display signal before we
* redraw it.
*/
if(SignalSet & SIG_DISPL)
{
DSeg -> Seconds ^= TRUE;
Force = TRUE;
}
/* We are to tell the time. */
if(SignalSet & SIG_SPEECH)
{
/* Remove speech process if speech
* has been turned off after it has
* been run once.
*/
if(!DSeg -> Speech)
{
if(SpeechProcess)
{
Signal(SpeechProcess,SIG_CLOSE);
Wait(SIG_SHAKE);
}
}
else
{
/* Try to create the speech process. */
if(!SpeechProcess)
{
Forbid();
if(SpeechProcess = CreateFuncProc("DClock-Speech",5,SpeechServer,4000))
Wait(SIG_SHAKE);
Permit();
}
/* Tell the time. */
if(SpeechProcess)
Signal(SpeechProcess,SIG_CLICK);
}
}
/* Show time and date. */
if(DSeg -> Page == 0)
ShowTime(TRUE,Force);
else
ShowTime(FALSE,Force);
Force = FALSE;
/* Show memory display. */
if(DSeg -> Page == 1)
{
LONG BarLength;
/* For single bitplane Workbench
* screen -> use fill pattern.
*/
static USHORT Checkers[8]=
{
0xAAAA,0x5555,
0xAAAA,0x5555,
0xAAAA,0x5555,
0xAAAA,0x5555
};
/* How much memory is still available? */
MemSize = AvailMem(MEMF_CHIP) + AvailMem(MEMF_FAST);
/* How LONG will the bar be? */
BarLength = ((Width - (EmptyWidth + FullWidth)) * MemSize) / MaxSize;
if(NewKick)
{
SetAPen(DummyRPort,2);
SetBPen(DummyRPort,3);
}
else
{
SetAPen(DummyRPort,1);
SetBPen(DummyRPort,2);
}
Move(DummyRPort,0,Window -> IFont -> tf_Baseline);
Text(DummyRPort,"E",1);
Move(DummyRPort,Width - FullWidth,Window -> IFont -> tf_Baseline);
Text(DummyRPort,"F",1);
/* Draw the full part. */
if(Window -> RPort -> BitMap -> Depth < 2)
SetAfPt(DummyRPort,&Checkers[0],1);
if(NewKick)
SetAPen(DummyRPort,2);
else
SetAPen(DummyRPort,3);
RectFill(DummyRPort,EmptyWidth,0,Width - FullWidth - BarLength,Height - 1);
if(Window -> RPort -> BitMap -> Depth < 2)
SetAfPt(DummyRPort,NULL,0);
/* Add the empty part. */
if(NewKick)
SetAPen(DummyRPort,3);
else
SetAPen(DummyRPort,2);
RectFill(DummyRPort,Width - FullWidth - BarLength,0,Width - (FullWidth + 1),Height - 1);
}
/* Numeric memory display. */
if(DSeg -> Page == 2)
{
UBYTE TempBuff[30];
Format(TempBuff,"C: %07ld F: %07ld",AvailMem(MEMF_CHIP),AvailMem(MEMF_FAST));
PrintIt(TempBuff);
}
/* Show online timer? */
if(DSeg -> Page == 3)
{
UBYTE TempBuff[50];
Format(TempBuff,"OFFLINE %02ld:%02ld:%02ld",OnlineHours,OnlineMinutes,OnlineSeconds);
if(DSeg -> Online)
{
if(Blink ^= TRUE)
{
TempBuff[0] = ' ';
TempBuff[1] = 'O';
TempBuff[2] = 'N';
}
else
{
TempBuff[0] = ' ';
TempBuff[1] = ' ';
TempBuff[2] = ' ';
}
}
PrintIt(TempBuff);
}
/* Show the countdown. */
if(DSeg -> Page == 4)
{
UBYTE TempBuff[50];
if(DSeg -> Countdown > 0)
{
Format(TempBuff,"Countdown %ld ",-DSeg -> Countdown);
TempBuff[22] = 0;
PrintIt(TempBuff);
}
else
DSeg -> Page = 0;
}
/* Transfer the image portion. */
ClipBlit(DummyRPort,0,0,Window -> WScreen -> BarLayer -> rp,LeftEdge,1,Width,Height,0xC0);
}
}