amiga-roadshow/examples/SampleNetSpeed.c

1126 lines
24 KiB
C

/*
* $Id: SampleNetSpeed.c,v 1.13 2007-08-26 12:30:16 obarthel Exp $
*
* :ts=4
*
* Copyright © 2001-2007 by Olaf Barthel. All Rights Reserved.
*/
/****************************************************************************/
#include <dos/dosextens.h>
#include <dos/dosasl.h>
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <dos/stdio.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <devices/timer.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <clib/alib_protos.h>
/*****************************************************************************/
#undef __NOGLOBALIFACE__
#define __USE_INLINE__
#define __NOLIBBASE__
/*****************************************************************************/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/timer.h>
#include <proto/bsdsocket.h>
/*****************************************************************************/
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
/****************************************************************************/
/* A quick workaround for the timeval/timerequest->TimeVal/TimeRequest
change in the recent OS4 header files. */
#if defined(__NEW_TIMEVAL_DEFINITION_USED__)
#define timeval TimeVal
#define tv_secs Seconds
#define tv_micro Microseconds
#define timerequest TimeRequest
#define tr_node Request
#define tr_time Time
#endif /* __NEW_TIMEVAL_DEFINITION_USED__ */
/****************************************************************************/
#include "SampleNetSpeed_rev.h"
STRPTR Version = VERSTAG;
/****************************************************************************/
#include "macros.h"
/****************************************************************************/
/*#define DEBUG*/
#include "assert.h"
/****************************************************************************/
#define PORT_SIG_MASK(mp) (1UL << (mp)->mp_SigBit)
/****************************************************************************/
extern struct Library * SysBase;
extern struct Library * DOSBase;
/****************************************************************************/
struct Library * IntuitionBase;
struct Library * GfxBase;
struct Library * SocketBase;
struct Device * TimerBase;
/****************************************************************************/
#if defined(__amigaos4__)
struct IntuitionIFace * IIntuition;
struct GraphicsIFace * IGraphics;
struct SocketIFace * ISocket;
struct TimerIFace * ITimer;
#endif /* __amigaos4__ */
/****************************************************************************/
struct MsgPort * TimePort;
struct timerequest * TimeRequest;
/****************************************************************************/
UBYTE Title[100];
struct Window * Window;
struct DrawInfo * DrawInfo;
struct TextFont * Font;
/****************************************************************************/
UBYTE InterfaceName[20];
struct timeval LastSampleTime;
SBQUAD_T LastSampleIn;
SBQUAD_T LastSampleOut;
/****************************************************************************/
ULONG MaxSent;
ULONG MaxSentReceived;
ULONG MaxReceived;
ULONG LastSent;
ULONG LastReceived;
ULONG TotalReceived;
ULONG TotalSent;
ULONG TotalCounted;
/****************************************************************************/
ULONG * HistoryReceived;
ULONG * HistorySent;
LONG HistorySize;
/****************************************************************************/
VOID local_sprintf(STRPTR buffer, STRPTR formatString, ...);
VOID cleanup(void);
BOOL setup(void);
void print_stats(void);
void clear_display(void);
void redraw_display(void);
void update_display(BOOL can_draw);
/****************************************************************************/
#if defined(__GNUC__) && !defined(__amigaos4__)
#undef Printf
LONG
Printf(STRPTR format,...)
{
va_list arg;
LONG result;
va_start(arg,format);
result = VPrintf(format,arg);
va_end(arg);
return(result);
}
#endif /* __GNUC__ && !__amigaos4__ */
/****************************************************************************/
VOID VARARGS68K
local_sprintf(STRPTR buffer, STRPTR formatString, ...)
{
va_list varArgs;
#if defined(__amigaos4__)
{
va_startlinear(varArgs,formatString);
RawDoFmt(formatString,va_getlinearva(varArgs,APTR),(VOID (*)())NULL,buffer);
va_end(varArgs);
}
#else
{
va_start(varArgs,formatString);
RawDoFmt(formatString,varArgs,(VOID (*)())"\x16\xC0\x4E\x75",buffer);
va_end(varArgs);
}
#endif /* __amigaos4__ */
}
/****************************************************************************/
VOID
cleanup(void)
{
if(HistoryReceived != NULL)
{
FreeVec(HistoryReceived);
HistoryReceived = NULL;
}
if(DrawInfo != NULL)
{
FreeScreenDrawInfo(Window->WScreen,DrawInfo);
DrawInfo = NULL;
}
if(Window != NULL)
{
CloseWindow(Window);
Window = NULL;
}
#if defined(__amigaos4__)
{
DropInterface((struct Interface *)ITimer);
}
#endif /* __amigaos4__ */
if(TimeRequest != NULL)
{
if(TimeRequest->tr_node.io_Device != NULL)
CloseDevice((struct IORequest *)TimeRequest);
DeleteIORequest((struct IORequest *)TimeRequest);
TimeRequest = NULL;
}
if(TimePort != NULL)
{
DeleteMsgPort(TimePort);
TimePort = NULL;
}
if(Font != NULL)
{
CloseFont(Font);
Font = NULL;
}
#if defined(__amigaos4__)
{
DropInterface((struct Interface *)ISocket);
DropInterface((struct Interface *)IGraphics);
DropInterface((struct Interface *)IIntuition);
}
#endif /* __amigaos4__ */
if(SocketBase != NULL)
{
CloseLibrary(SocketBase);
SocketBase = NULL;
}
if(GfxBase != NULL)
{
CloseLibrary(GfxBase);
GfxBase = NULL;
}
if(IntuitionBase != NULL)
{
CloseLibrary(IntuitionBase);
IntuitionBase = NULL;
}
}
/****************************************************************************/
BOOL
setup(void)
{
STATIC struct TextAttr topaz =
{
"topaz.font",
8,
FS_NORMAL,
FPF_ROMFONT|FPF_DESIGNED
};
struct
{
STRPTR Interface;
LONG * Left;
LONG * Top;
LONG * Width;
LONG * Height;
STRPTR Screen;
} args;
struct RDArgs * rda = NULL;
BOOL success = FALSE;
LONG left,top,width,height;
if(SysBase->lib_Version < 36)
goto out;
/* The following may be necessary to flush out an inoperable
bsdsocket.library which reached the end of the shutdown
process. */
#if 1
{
struct ExecBase * ex = (struct ExecBase *)SysBase;
struct Library * lib;
Forbid();
lib = (struct Library *)FindName(&ex->LibList,"bsdsocket.library");
if(lib != NULL)
RemLibrary(lib);
Permit();
}
#endif
SocketBase = OpenLibrary("bsdsocket.library",4);
#if defined(__amigaos4__)
{
if(SocketBase != NULL)
{
ISocket = (struct SocketIFace *)GetInterface(SocketBase, "main", 1, 0);
if(ISocket == NULL)
{
CloseLibrary(SocketBase);
SocketBase = NULL;
}
}
}
#endif /* __amigaos4__ */
if(SocketBase == NULL)
{
Printf("Could not open 'bsdsocket.library' V4.\n");
goto out;
}
IntuitionBase = OpenLibrary("intuition.library",37);
#if defined(__amigaos4__)
{
if(IntuitionBase != NULL)
{
IIntuition = (struct IntuitionIFace *)GetInterface(IntuitionBase, "main", 1, 0);
if(IIntuition == NULL)
{
CloseLibrary(IntuitionBase);
IntuitionBase = NULL;
}
}
}
#endif /* __amigaos4__ */
if(IntuitionBase == NULL)
{
Printf("Could not open 'intuition.library' V37.\n");
goto out;
}
GfxBase = OpenLibrary("graphics.library",37);
#if defined(__amigaos4__)
{
if(GfxBase != NULL)
{
IGraphics = (struct GraphicsIFace *)GetInterface(GfxBase, "main", 1, 0);
if(IGraphics == NULL)
{
CloseLibrary(GfxBase);
GfxBase = NULL;
}
}
}
#endif /* __amigaos4__ */
if(GfxBase == NULL)
{
Printf("Could not open 'graphics.library' V37.\n");
goto out;
}
TimePort = CreateMsgPort();
if(TimePort == NULL)
{
Printf("Could not create timer message port.\n");
goto out;
}
TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(*TimeRequest));
if(TimeRequest == NULL)
{
Printf("Could not create timer I/O request.\n");
goto out;
}
if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimeRequest,0) != OK)
{
Printf("Could not open 'timer.device'.\n");
goto out;
}
TimerBase = TimeRequest->tr_node.io_Device;
#if defined(__amigaos4__)
{
ITimer = (struct TimerIFace *)GetInterface((struct Library *)TimerBase, "main", 1, 0);
if(ITimer == NULL)
{
Printf("Could not access 'timer.device' interface.\n");
goto out;
}
}
#endif /* __amigaos4__ */
memset(&args,0,sizeof(args));
rda = ReadArgs("INTERFACE,LEFT/N,TOP/N,WIDTH/N,HEIGHT/N,SCREEN/K",(LONG *)&args,NULL);
if(rda == NULL)
{
PrintFault(IoErr(),"Sample");
goto out;
}
if(args.Interface != NULL)
{
LONG len;
len = strlen(args.Interface);
if(len > sizeof(InterfaceName)-1)
len = sizeof(InterfaceName)-1;
memcpy(InterfaceName,args.Interface,len);
InterfaceName[len] = '\0';
}
if(args.Left != NULL)
left = (*args.Left);
else
left = -1;
if(args.Top != NULL)
top = (*args.Top);
else
top = -1;
if(args.Width != NULL)
width = (*args.Width);
else
width = 300;
if(args.Height != NULL)
height = (*args.Height);
else
height = 50;
if(width < 30)
width = 30;
if(height < 40)
height = 40;
GetSysTime(&LastSampleTime);
if(InterfaceName[0] != '\0')
{
local_sprintf(Title,"%s I/O performance",InterfaceName);
if(QueryInterfaceTags(InterfaceName,
IFQ_GetBytesIn, &LastSampleIn,
IFQ_GetBytesOut, &LastSampleOut,
TAG_END) != 0)
{
Printf("Could not query data throughput statistics for interface '%s'.\n",InterfaceName);
goto out;
}
}
else
{
strcpy(Title,"TCP/IP I/O performance");
if(SocketBaseTags(
SBTM_GETREF(SBTC_GET_BYTES_RECEIVED), &LastSampleIn,
SBTM_GETREF(SBTC_GET_BYTES_SENT), &LastSampleOut,
TAG_END) != 0)
{
Printf("Could not query data throughput statistics.\n");
goto out;
}
}
Font = OpenFont(&topaz);
if(Font == NULL)
{
Printf("Could not open default font topaz/8.\n");
goto out;
}
Window = OpenWindowTags(NULL,
WA_Title, Title,
WA_SizeGadget, TRUE,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_NoCareRefresh, TRUE,
WA_RMBTrap, TRUE,
WA_SmartRefresh, TRUE,
WA_SizeBRight, TRUE,
(left >= 0) ? WA_Left : TAG_IGNORE,left,
(top >= 0) ? WA_Top : TAG_IGNORE,top,
WA_InnerWidth, width,
WA_InnerHeight, height,
WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_VANILLAKEY,
(args.Screen != NULL) ? WA_PubScreenName : TAG_IGNORE, args.Screen,
TAG_END);
if(Window == NULL)
{
Printf("Could not open window.\n");
goto out;
}
HistorySize = Window->WScreen->Width;
HistoryReceived = AllocVec(HistorySize * 2 * sizeof(ULONG),MEMF_ANY|MEMF_CLEAR);
if(HistoryReceived)
HistorySent = HistoryReceived + HistorySize;
else
HistorySize = 0;
WindowLimits(Window,
Window->BorderLeft + 10 + Window->BorderRight,
Window->BorderTop + 20 + Font->tf_YSize+1 + Window->BorderBottom,
Window->WScreen->Width,
Window->WScreen->Height);
DrawInfo = GetScreenDrawInfo(Window->WScreen);
if(DrawInfo == NULL)
{
Printf("Could not get screen drawing information.\n");
goto out;
}
SetBPen(Window->RPort,DrawInfo->dri_Pens[BACKGROUNDPEN]);
SetDrMd(Window->RPort,JAM2);
SetFont(Window->RPort,Font);
clear_display();
success = TRUE;
out:
if(rda != NULL)
FreeArgs(rda);
if(NO success)
cleanup();
return(success);
}
/****************************************************************************/
void
print_stats(void)
{
struct RastPort * rp = Window->RPort;
UBYTE buffer[300];
ULONG avg_sent;
ULONG avg_received;
struct TextExtent te;
LONG width;
LONG len;
if(TotalCounted > 0)
{
avg_sent = TotalSent / TotalCounted;
avg_received = TotalReceived / TotalCounted;
}
else
{
avg_sent = 0;
avg_received = 0;
}
local_sprintf(buffer,"max %lD/%lD avg %lD/%lD last %lD/%lD",
MaxReceived,MaxSent,
avg_received,avg_sent,
LastReceived,LastSent);
width = Window->Width - (Window->BorderLeft + Window->BorderRight);
len = TextFit(rp,buffer,strlen(buffer),&te,NULL,1,width,32767);
if(len > 0)
{
SetAPen(rp,DrawInfo->dri_Pens[TEXTPEN]);
Move(rp,Window->BorderLeft,Window->Height - (Window->BorderBottom + Font->tf_YSize - Font->tf_Baseline));
Text(rp,buffer,len);
SetAPen(rp,DrawInfo->dri_Pens[BACKGROUNDPEN]);
RectFill(rp,
Window->BorderLeft,Window->Height - (Window->BorderBottom + Font->tf_YSize + 1),
Window->Width - (Window->BorderRight + 1),Window->Height - (Window->BorderBottom + Font->tf_YSize + 1));
}
if(te.te_Width < width)
{
SetAPen(rp,DrawInfo->dri_Pens[BACKGROUNDPEN]);
RectFill(rp,
Window->BorderLeft + te.te_Width,Window->Height - (Window->BorderBottom + Font->tf_YSize),
Window->Width - (Window->BorderRight + 1),Window->Height - (Window->BorderBottom + 1));
}
}
/****************************************************************************/
void
clear_display(void)
{
struct RastPort * rp = Window->RPort;
LONG height;
LONG top;
SetAPen(rp,DrawInfo->dri_Pens[BACKGROUNDPEN]);
RectFill(rp,
Window->BorderLeft,
Window->BorderTop,
Window->Width - (Window->BorderRight+1),
Window->Height - (Window->BorderBottom+1));
height = Window->Height - (Window->BorderTop + Window->BorderBottom + (Font->tf_YSize+1));
top = height - ((height / 2) + 1);
SetAPen(rp,DrawInfo->dri_Pens[SHADOWPEN]);
RectFill(rp,
Window->BorderLeft,Window->BorderTop + top,
Window->Width - (Window->BorderRight + 1),Window->BorderTop + top);
print_stats();
}
/****************************************************************************/
void
redraw_display(void)
{
struct RastPort * rp = Window->RPort;
LONG width,height;
LONG mid;
LONG top;
LONG bottom;
LONG i;
SetAPen(rp,DrawInfo->dri_Pens[BACKGROUNDPEN]);
RectFill(rp,
Window->BorderLeft,
Window->BorderTop,
Window->Width - (Window->BorderRight+1),
Window->Height - (Window->BorderBottom+1));
height = Window->Height - (Window->BorderTop + Window->BorderBottom + (Font->tf_YSize+1));
width = Window->Width - (Window->BorderLeft + Window->BorderRight);
mid = height / 2;
top = height - (mid + 1);
bottom = height - (top + 1);
for(i = 0 ; i < width ; i++)
{
if(MaxSentReceived > 0)
{
ULONG received = (HistoryReceived[HistorySize - width + i] * top) / MaxSentReceived;
ULONG sent = (HistorySent[HistorySize - width + i] * bottom) / MaxSentReceived;
if(received > 0)
{
SetAPen(rp,DrawInfo->dri_Pens[SHINEPEN]);
RectFill(rp,
Window->BorderLeft+i,Window->BorderTop + top - received,
Window->BorderLeft+i,Window->BorderTop + top - 1);
}
if(sent > 0)
{
SetAPen(rp,DrawInfo->dri_Pens[FILLPEN]);
RectFill(rp,
Window->BorderLeft+i,Window->BorderTop + top + 1,
Window->BorderLeft+i,Window->BorderTop + top + 1 + sent - 1);
}
}
}
SetAPen(rp,DrawInfo->dri_Pens[SHADOWPEN]);
RectFill(rp,
Window->BorderLeft,Window->BorderTop + top,
Window->Width - (Window->BorderRight + 1),Window->BorderTop + top);
print_stats();
}
/****************************************************************************/
ULONG
quad_delta(const SBQUAD_T * a,const SBQUAD_T * b)
{
ULONG result = 0;
SBQUAD_T delta;
delta = (*a);
if(delta.sbq_Low < b->sbq_Low)
{
if(delta.sbq_High == 0)
goto out;
delta.sbq_High--;
delta.sbq_Low = (~0UL) - b->sbq_Low + 1 + a->sbq_Low;
}
else
{
delta.sbq_Low -= b->sbq_Low;
}
if(delta.sbq_High < b->sbq_High)
goto out;
/*delta.sbq_High -= b->sbq_High;*/
result = delta.sbq_Low;
out:
return(result);
}
/****************************************************************************/
#define REDRAW_DISPLAY TRUE
#define PRETEND_TO_REDRAW_DISPLAY FALSE
/****************************************************************************/
void
update_display(BOOL can_draw)
{
STATIC BOOL catch_up;
struct RastPort * rp = Window->RPort;
struct timeval now;
SBQUAD_T sample_in;
SBQUAD_T sample_out;
struct timeval tv;
LONG height;
LONG mid;
LONG top;
LONG bottom;
ULONG sent;
ULONG received;
BOOL redraw;
GetSysTime(&now);
if(InterfaceName[0] != '\0')
{
if(QueryInterfaceTags(InterfaceName,
IFQ_GetBytesIn, &sample_in,
IFQ_GetBytesOut, &sample_out,
TAG_END) != 0)
{
memset(&sample_in,0,sizeof(sample_in));
memset(&sample_out,0,sizeof(sample_out));
}
}
else
{
if(SocketBaseTags(
SBTM_GETREF(SBTC_GET_BYTES_RECEIVED), &sample_in,
SBTM_GETREF(SBTC_GET_BYTES_SENT), &sample_out,
TAG_END) != 0)
{
memset(&sample_in,0,sizeof(sample_in));
memset(&sample_out,0,sizeof(sample_out));
}
}
if(NOT can_draw)
catch_up = TRUE;
height = Window->Height - (Window->BorderTop + Window->BorderBottom + (Font->tf_YSize+1));
mid = height / 2;
top = height - (mid + 1);
bottom = height - (top + 1);
tv = now;
SubTime(&tv,&LastSampleTime);
received = quad_delta(&sample_in,&LastSampleIn);
sent = quad_delta(&sample_out,&LastSampleOut);
LastSampleTime = now;
LastSampleIn = sample_in;
LastSampleOut = sample_out;
if(tv.tv_secs > 0 || tv.tv_micro > 0)
{
double f;
f = (double)tv.tv_secs + (double)tv.tv_micro / 1000000.0;
sent = (ULONG)((double)sent / f);
received = (ULONG)((double)received / f);
}
else
{
sent = received = 0;
}
if(HistorySize > 0)
{
memmove(HistoryReceived,HistoryReceived+1,sizeof(ULONG) * (HistorySize-1));
memmove(HistorySent,HistorySent+1,sizeof(ULONG) * (HistorySize-1));
HistoryReceived[HistorySize-1] = received;
HistorySent[HistorySize-1] = sent;
}
if(sent != 0)
LastSent = sent;
if(received != 0)
LastReceived = received;
TotalSent += sent;
TotalReceived += received;
TotalCounted += 1;
redraw = FALSE;
if(sent > MaxSent)
{
MaxSent = sent;
if(sent > MaxSentReceived)
MaxSentReceived = sent;
redraw = TRUE;
}
if(received > MaxReceived)
{
MaxReceived = received;
if(received > MaxSentReceived)
MaxSentReceived = received;
redraw = TRUE;
}
if(catch_up)
{
if(NOT redraw)
clear_display();
redraw = TRUE;
}
if(can_draw)
{
if(redraw && HistorySize > 0)
{
redraw_display();
}
else
{
SetBPen(rp,DrawInfo->dri_Pens[BACKGROUNDPEN]);
ScrollRaster(rp,1,0,
Window->BorderLeft,
Window->BorderTop,
Window->Width - (Window->BorderRight+1),
Window->Height - (Window->BorderBottom+1+Font->tf_YSize+1));
SetAPen(rp,DrawInfo->dri_Pens[SHADOWPEN]);
WritePixel(rp,Window->Width - (Window->BorderRight+1),Window->BorderTop + top);
if(MaxSentReceived > 0)
{
received = (received * top) / MaxSentReceived;
sent = (sent * bottom) / MaxSentReceived;
}
else
{
received = 0;
sent = 0;
}
if(received > 0)
{
SetAPen(rp,DrawInfo->dri_Pens[SHINEPEN]);
RectFill(rp,
Window->Width - (Window->BorderRight+1),Window->BorderTop + top - received,
Window->Width - (Window->BorderRight+1),Window->BorderTop + top - 1);
}
if(sent > 0)
{
SetAPen(rp,DrawInfo->dri_Pens[FILLPEN]);
RectFill(rp,
Window->Width - (Window->BorderRight+1),Window->BorderTop + top + 1,
Window->Width - (Window->BorderRight+1),Window->BorderTop + top + 1 + sent - 1);
}
}
print_stats();
catch_up = FALSE;
}
}
/****************************************************************************/
/****** ROADSHOW/SAMPLENETSPEED ************************************************
*
* NAME
* SampleNetSpeed - Display network I/O performance
*
* FORMAT
* SampleNetSpeed [[INTERFACE] <interface name>] [LEFT <window left edge>]
* [TOP <window top edge>] [WIDTH <window width>]
* [HEIGHT <window height>] [SCREEN <name>]
*
* TEMPLATE
* INTERFACE,LEFT/N,TOP/N,WIDTH/N,HEIGHT/N,SCREEN/K
*
* FUNCTION
* The command can be used to gather statistics on the performance of
* a specific network interface or all network interfaces used by the
* TCP/IP stack. Performance is measured as data throughput when sending
* or receiving data packets to/from the network.
*
* The performance data is sampled once every second and visualized in
* a window which is updated regularly. In the top half of the window
* the amount of data received is displayed, while the bottom half shows
* the amount of data sent. The sizes of the bars representing the
* performance are always using the same scale. At the bottom of the
* window three figures are printed (from left to right): maximum
* throughput, averaged throughput, last throughput. For each of these
* figures the values are displayed in the form "number of bytes
* received per second / number of bytes sent per second".
*
* OPTIONS
* INTERFACE
* The name of the interface whose performance should be sampled.
* If omitted, information on all networking interfaces will be
* gathered.
*
* LEFT
* TOP
* These parameters are optional; you can specify the position of
* the window to open. Default is to open it in the top left corner
* of the screen.
*
* WIDTH
* HEIGHT
* These parameters are optional; you can specify the size of the
* window to open. Default is to open a window that can display a
* 300 by 50 pixel area. Note that width and height actually refer
* to the size of the display area and not the total size of the
* window.
*
* SCREEN
* You can specify the name of a public screen to open the window
* on. If omitted, the window will open on the default public
* screen, which is usually the Workbench screen.
*
* NOTES
* To stop the command, either click on the window close gadget in the
* top left corner or send a break signal to it in the shell.
*
******************************************************************************
*/
int
main(int argc,char **argv)
{
if(setup())
{
ULONG time_mask;
ULONG window_mask;
ULONG signal_mask;
ULONG signals;
BOOL done;
time_mask = PORT_SIG_MASK(TimePort);
window_mask = PORT_SIG_MASK(Window->UserPort);
signal_mask = SIGBREAKF_CTRL_C | time_mask | window_mask;
signals = 0;
done = FALSE;
TimeRequest->tr_node.io_Command = TR_ADDREQUEST;
TimeRequest->tr_time.tv_secs = 1;
TimeRequest->tr_time.tv_micro = 0;
SendIO((struct IORequest *)TimeRequest);
do
{
if(signals == 0)
signals = Wait(signal_mask);
else
signals |= SetSignal(0,signal_mask) & signal_mask;
if(signals & time_mask)
{
if(GetMsg(TimePort) != NULL)
{
if(AttemptLockLayerRom(Window->WLayer))
{
update_display(REDRAW_DISPLAY);
UnlockLayerRom(Window->WLayer);
}
else
{
update_display(PRETEND_TO_REDRAW_DISPLAY);
}
TimeRequest->tr_node.io_Command = TR_ADDREQUEST;
TimeRequest->tr_time.tv_secs = 1;
TimeRequest->tr_time.tv_micro = 0;
SendIO((struct IORequest *)TimeRequest);
}
else
{
signals &= ~time_mask;
}
}
if(signals & window_mask)
{
struct IntuiMessage * imsg;
imsg = (struct IntuiMessage *)GetMsg(Window->UserPort);
if(imsg != NULL)
{
ULONG class = imsg->Class;
UWORD code = imsg->Code;
ReplyMsg((struct Message *)imsg);
if(class == IDCMP_CLOSEWINDOW)
{
done = TRUE;
}
else if (class == IDCMP_NEWSIZE)
{
LockLayerRom(Window->WLayer);
if(HistorySize > 0)
{
redraw_display();
}
else
{
clear_display();
update_display(REDRAW_DISPLAY);
}
UnlockLayerRom(Window->WLayer);
if(CheckIO((struct IORequest *)TimeRequest) == BUSY)
AbortIO((struct IORequest *)TimeRequest);
WaitIO((struct IORequest *)TimeRequest);
TimeRequest->tr_node.io_Command = TR_ADDREQUEST;
TimeRequest->tr_time.tv_secs = 1;
TimeRequest->tr_time.tv_micro = 0;
SendIO((struct IORequest *)TimeRequest);
}
else if (class == IDCMP_VANILLAKEY)
{
if(code == '\033' || code == '\034' || code == '\003')
done = TRUE;
}
}
else
{
signals &= ~window_mask;
}
}
if(signals & SIGBREAKF_CTRL_C)
{
done = TRUE;
signals &= ~SIGBREAKF_CTRL_C;
}
}
while(NOT done);
if(CheckIO((struct IORequest *)TimeRequest) == BUSY)
AbortIO((struct IORequest *)TimeRequest);
WaitIO((struct IORequest *)TimeRequest);
cleanup();
}
return(0);
}