;/* Execute me to Compile and link ShellTimer.c ;shelltimer start verbose ; For debugging, use the following command: ;lc -. -b1 -cfistq -j73 -v -Lit -d3 -isrc:memlib -dMWDEBUG=1 ShellTimer.c ; For production, use the following command: lc -. -O -ms -b1 -cfistq -j73 -Lit -tr ShellTimer.c ;echo "Time to compile and link: " NOLINE ;shelltimer stop quit */ /*** **** SHELLTIMER.C **** **** Creation: John Lindwall **** 19 Jan 1992 **** **** Description: Client program for ShellTimer system. The user **** invokes timer commands via this program. The commands are **** passed to the ShellTimerDaemon for processing. The client **** displays the results of the command, if any. **** **** As written, this program requires AmigaDOS 2.04. It could **** be modified to run under 1.3, but I don't have the inclination. **** 2.0 features used include local shell environment variables, **** ReadArgs(), and System(). **** **** This program must be run from the shell. ShellTimer exits **** gracefully if AmigaDOS 2.0 is not in charge, or if not run **** from the shell. **** **** See ShellTimer.doc for more information. **** **** The ShellTimer System (which includes the programs **** ShellTimerDaemon and ShellTimer) is released into the Public **** Domain by the author, John Lindwall. I ask that the archive **** be kept intact with the docs and the source code. Bug reports **** should be sent to me at johnl@crash.cts.com. **** **** Note: The code is not commented ... sorry. **** **** Overhauls: ***/ #include #include #include #include #include #include #include #include #include #include #include #include #include "ShellTimer.h" /* Command line parsing stuff */ #define ARGTEMPLATE "START/S,STOP/S,CANCEL/S,QUIT/S,HELP/S,V=VERBOSE/S,Q=QUERY/S" #define OPT_START 0 #define OPT_STOP 1 #define OPT_CANCEL 2 #define OPT_QUIT 3 #define OPT_HELP 4 #define OPT_VERBOSE 5 #define OPT_QUERY 6 #define OPT_COUNT 7 #define SECONDS_PER_MINUTE 60 #define SECONDS_PER_HOUR 3600 #define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24) #define APPNAME "ShellTimer" #define ADOS2_VERSION 37 int ParseCommandLine(void); BOOL SendCommand(int command); void PrintResults(int command); void PrintElapsedTime(struct timeval *diffTime); void Print(char *s); void ShowHelp(void); struct ST_Message message; static int verbose = FALSE; UBYTE versionTag[] = "\0$VER: " APPNAME " 1.0 (03.02.92)"; void main(int argc, char *argv[]) { int command; extern struct DOSLibrary *DOSBase; if( argc == 0 ) /* Bail out if started from WorkBench */ { exit(-10); } if( DOSBase->dl_lib.lib_Version < ADOS2_VERSION ) { Print(APPNAME " Requires AmigaDOS 2.0!\n"); exit(-20); } #ifdef MWDEBUG MWInit(NULL, 0, "CON:0/200/639/199/MemLib"); #endif command = ParseCommandLine(); if( command != ST_ERR ) { if( command != ST_HELP ) { if( SendCommand(command) ) { PrintResults(command); } } else { ShowHelp(); } } else { Print("Invalid parameters\n"); } #ifdef MWDEBUG MWTerm(); #endif exit(0); } int ParseCommandLine() { ULONG result[OPT_COUNT]; struct RDArgs *rda; memset(result, '\0', sizeof(result)); if( (rda = ReadArgs(ARGTEMPLATE, result, NULL)) != NULL ) { FreeArgs(rda); if( result[OPT_VERBOSE] ) { verbose = TRUE; } if( result[OPT_START] ) { return(ST_START); } if( result[OPT_STOP] ) { return(ST_STOP); } if( result[OPT_CANCEL] ) { return(ST_CANCEL); } if( result[OPT_QUIT] ) { return(ST_QUIT); } if( result[OPT_HELP] ) { return(ST_HELP); } if( result[OPT_QUERY] ) { return(ST_QUERY); } return(ST_TOGGLE); /* Default action if no args supplied */ } return(ST_ERR); } BOOL SendCommand(int command) { struct LocalVar *shellPID; struct MsgPort *publicPort, *myPort; BPTR file; int systemStat, i; static struct TagItem daemonTags[] = { SYS_Input, 0, SYS_Output, NULL, SYS_Asynch, TRUE, SYS_UserShell, TRUE, TAG_DONE }; shellPID = FindVar("process", GVF_LOCAL_ONLY); if( shellPID == NULL ) { Print("Can't get shell PID!\n"); #ifndef DEBUG exit(-1); #endif } #ifdef DEBUG message.requestID = 999; #else message.requestID = atoi(shellPID->lv_Value); #endif message.code = command; message.msg.mn_Length = sizeof(struct ST_Message);; Forbid(); if( (publicPort = FindPort(ST_PORT)) == NULL ) { Permit(); if( command == ST_QUIT ) { return(FALSE); } file = Open("NIL:", MODE_OLDFILE); daemonTags[0].ti_Data = file; systemStat = SystemTagList("ShellTimerDaemon", daemonTags); if( systemStat == 0 ) { if( verbose ) { Print("Timer daemon loaded.\n"); } } else { Print("Unable to load ShellTimerDaemon!\n"); return(FALSE); } /* Give the daemon a little while to start up */ for( i = 0; i < 4; i++ ) { Delay(25); if( FindPort(ST_PORT) != NULL ) { break; } } Forbid(); } if( (publicPort = FindPort(ST_PORT)) == NULL ) { Permit(); Print("Can't locate timer daemon.\n"); return(FALSE); } else { if( (myPort = CreateMsgPort()) != NULL ) { message.msg.mn_ReplyPort = myPort; PutMsg(publicPort,&message); Permit(); WaitPort(myPort); DeletePort(myPort); return(TRUE); } } } void PrintResults(int command) { if( message.code != ST_ERR ) { switch( message.code ) { case ST_START: if( verbose ) { Print("Timer started\n"); } break; case ST_STOP: if( verbose ) { Print("Timer stopped - Elapsed Time: "); } PrintElapsedTime(&(message.diffTime)); break; case ST_CANCEL: if( verbose ) { Print("Timer cancelled\n"); } break; case ST_QUERY: if( verbose ) { Print("Timer Query - Current elapsed time: "); } PrintElapsedTime(&(message.diffTime)); break; case ST_ERR_NO_PENDING: if( verbose ) { Print("No pending timer request\n"); } break; case ST_TIMEWARP: if( verbose ) { Print("Let's do the TimeWarp again!\n"); } Print("Error: System clock faulty or reset\n"); break; case ST_QUIT: Print("ShellTimerDaemon unloaded\n"); break; } } else { Print("ShellTimerDaemon returned an error\n"); } } void PrintElapsedTime(struct timeval *diffTime) { ULONG timedSeconds, days, hours, minutes, seconds; char string[80]; timedSeconds = diffTime->tv_secs; days = hours = minutes = seconds = 0; if( timedSeconds >= SECONDS_PER_DAY ) { days = timedSeconds / SECONDS_PER_DAY; timedSeconds %= SECONDS_PER_DAY; } if( timedSeconds >= SECONDS_PER_HOUR ) { hours = timedSeconds / SECONDS_PER_HOUR; timedSeconds %= SECONDS_PER_HOUR; } if( timedSeconds >= SECONDS_PER_MINUTE ) { minutes = timedSeconds / SECONDS_PER_MINUTE; timedSeconds %= SECONDS_PER_MINUTE; } seconds = timedSeconds; timedSeconds = diffTime->tv_secs; if( verbose ) { if( days > 0 ) { sprintf(string, "%ld Day%s, ", days, days == 1 ? NULL : "s"); Print(string); } if( timedSeconds >= SECONDS_PER_HOUR ) { sprintf(string, "%ld Hour%s, ", hours, hours == 1 ? NULL : "s"); Print(string); } if( timedSeconds >= SECONDS_PER_MINUTE ) { sprintf(string, "%ld Minute%s, ", minutes, minutes == 1 ? NULL : "s"); Print(string); } sprintf(string, "%ld Second%s\n", seconds, seconds == 1 ? NULL : "s"); Print(string); } else { if( days > 0 ) { sprintf(string, "%ld ", hours); Print(string); } sprintf(string, "%02ld:%02ld:%02ld\n", hours, minutes, seconds); Print(string); } } void Print(char *string) { Write(Output(), string, strlen(string)); } void ShowHelp(void) { Print("\n"); Print(&versionTag[7]); Print(" - A shell-based stopwatch by John Lindwall"); Print("\n\n" APPNAME " " ARGTEMPLATE); Print("\n\n START - Starts the timer STOP - Stops timer & prints time"); Print( "\n CANCEL - Abort the timer session QUIT - Kill daemon and quit"); Print( "\n HELP - Show help message VERBOSE - Use wordy messages"); Print( "\n QUERY - Show current timer value"); Print( "\n\nIf no arguments are supplied, ShellTimer toggles between performing START"); Print( "\nand STOP. So, typing 'ShellTimer' once starts the timer; typing 'ShellTimer'"); Print( "\nagain will stop the timer and display the result.\n\n"); }