[comp.sources.amiga] amicron

ain@j.cc.purdue.edu (Patrick White) (04/28/88)

Submitted by:	kim@amdahl.uts.amdhal.com (Kim DeVaughn)
Summary:	unix cron for the Amiga -- run a command at a particular time.
Poster Boy:	Patrick White	(ain@j.cc.purdue.edu)
Archive Name:	sources/volume4/amicron24a.d.sh.Z binaries/volume5/amicron24a.d.sh.Z
Tested.
 
NOTES:
   I re-did the arc to sepatate the binaries, sources & docs.
   There are some set-up files in the docs shar.
 
 
-- Pat White   (co-moderator comp.sources/binaries.amiga)
ARPA/UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM  PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906
 
========================================
 
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	AmiCron.doc
#	.startcron
#	crontab
#	alias4shell
# This archive created: Wed Apr 27 10:10:51 1988
# By:	Patrick White (PUCC Land, USA)
echo shar: extracting README '(1997 characters)'
cat << \SHAR_EOF > README
This is an improved version of the AmiCron program on Fish Disk #113.  It was
originally written by Steve Sampson, and is NOT copyrighted, but is explicitly
placed Public Domain (p).  The Amiga port was done by Rick Schaeffer, with the
latest (v2.4a) improvements courtesy of Christian Balzer, and others (see the
AmiCron.doc file).  The timer code is extracted from Rob Peck's "simple timer
example" program.

I've included sample "crontab" and ".startcron" files, as well as my "startcron"
alias for the Dillon/Drew "shell".

To run amicron, simply copy "AmiCron24a" to your c: directory (renaming it to
"amicron"), and the ".startcron" and "crontab" files to your s: directory.
Add the initiating alias (in "alias4shell") to your shell ".login" file, and
re-source it.  Then just enter "startcron", and (poof) AmiCron will be up and
running whatever commands you've added to the "crontab" file.  [ If you're
NOT using "shell", just enter the newcli command as shown in "alias4shell" (or
some variation thereof). ]

Note that the "months" field now runs from 1-12 (instead of 0-11), and that
command initiation "accuracy" has been improved.  See the doc file for a
more complete list of improvements over v2.3.


Some future enhancements I'd like to see are:

    1 - A cleaner way of shutting amicron down

    2 - Fix amicron to run without a window to avoid it "blocking" when
        one accidentally types into it's window (you *will* do this, per
        Murphy)

    3 - Have amicron write it's output to a log file (due to 2), and
        provide a method for listing this file without shutting amicron
        down.

    4 - Continue to improve the "accuracy" of amicron's timing (in a load
        independent way).

I'll probably get working on these "RSN" ...


/kim


UUCP:  kim@amdahl.amdahl.com
  or:  {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim
DDD:   408-746-8462
USPS:  Amdahl Corp.  M/S 249,  1250 E. Arques Av,  Sunnyvale, CA 94086
CIS:   76535,25

SHAR_EOF
if test 1997 -ne "`wc -c README`"
then
echo shar: error transmitting README '(should have been 1997 characters)'
fi
echo shar: extracting AmiCron.doc '(8033 characters)'
cat << \SHAR_EOF > AmiCron.doc
                    AmiCron - Cron task for the Amiga

Following below is the original AmiCron documentation by Rick
Schaeffer (Version 2.3). I changed it were necessary and listed
additional features below.
<CB>

This is a (no longer) crude but effective version of the Unix (tm) 
program known as "cron" modified to run on an Amiga.  For those 
who aren't Unix knowledgeable, cron is a background task which 
uses a disk-resident table to automatically run certain tasks on a 
regular basis.  The cron table's format is very simple...it 
contains entries in the form of lines where each line has 6 fields 
and each field is separated by "white space" (either tabs or 
spaces) from it's neighbor. The fields are as follows:

   1.  Minute       (0-59)
   2.  Hour         (0-23)
   3.  Day          (1-31)	(now works, <CB>)
   4.  Month        (1-12) 
   5.  Day of week  (0-6 where 0=Sunday and 6=Saturday)
   6.  Command      This is the command to be run at the appointed 
                    time.  It will be run just as if typed into 
                    the CLI.

Each of the first 5 fields are numbers.  However, it is 
permissable to use an asterisk (*) in a field to mean ALL possible 
numbers for that field,  and you can specify a series of numbers 
separated by commas (,) and ranges separated by dashes (-).  For 
instance, in the Day field you could specify "1,5,10" to mean the 
first, fifth, and tenth days of the month; or you could specify 
"1-15" to mean the first through the fifteenth of the month.  Here 
are some examples of Amicron table entries:

  	Print the date in the crontask window every minute:
  		* * * * * date
  
  	Print the date in the crontask window on the hour, every hour:
  		0 * * * * date
  
  	Run uupc at 4:30 am every day except Sat and Sun:
  		30 4 * * 1-5 uupc -siscuva
  
  	Incrementally backup the files every other day at 7:30 pm:
  		30 19 * * 1,3,5 sdbackup -l -s LAST dh0: incbkup_1:

    	Backup the files on the 1st and 15th of each month at 1:00 am:
        	00 01 1,15 * * sdbackup -l dh0: SemiBkup_1:

The Amicron table file is by default located using the following path:

    S:	(or S:CronTab to be exact and include the filename)

but you now may specify a complete path (including filename!) for
the CronTab file (which needn't but should have this name) as a
command line parameter like this:

    Amicron RAM:MyCronTab

which would cause Amicron to use the CronTab file "MyCronTab"
located in the RAM: disk and not to access a disk drive every minute
to read in the CronTab file.

Crontab entries *MUST* be left justified starting in column 1 and 
each entry must contain 6 fields, each separated by spaces or 
tabs.

To run Amicron, you must use your favorite editor to create the
"CronTab" file.  Amicron needs a CLI window for displaying the 
output of the commands it runs...but it can be made as small or 
large as you wish.  Assuming that you have placed Amicron in your 
command directory (c:), you can start it by typing the following 
line into a "newcli" window:
    Amicron
Then you can size and move the window anywhere you want, just be 
sure not to type anything else into the window because that would 
prevent cron tasks from running (read: printing something in that 
window).

I have an entry in my startup-sequence file that looks like this:
   run newcli con:0/140/160/50/CronTask s:startcron
The "s:startcron" file contains one line:
   Amicron
This automatically sets up a tiny CronTask window and runs Amicron 
in it.

This program was originally written by Steve R.  Sampson (UUCP:
sys1!killer!sampson), who very kindly responded to my request for
a PD cron that I could port to Minix.  I haven't done that yet
(My new Amiga 2000 came in right after I received the cron
program <grin>) but will do so ASAP.  The modifications to make
it run on the Amiga were very minor!

Rick Schaeffer          UUCP:  seismo!uunet!iscuva!ricks
E. 13611 26th Ave.      Phone: (509)928-3533
Spokane, WA  99216

---- Changes up to Version 2.4
V2.31& V2.32
Besides changing the paths for CronTab (s:) & CronErr (t:) to more
decent Amiga places, I encountered a bug when I wanted to start
cron a special program on xmas. After some investigation I found
out that the localtime() function returns months only in the range
from  0 to 11. So it was not surprising  that my "12" in the month
field of CronTab was completely ignored. 
To not have the user adapt to the computer by having him to supply
months in the range from 0 to 11, I now increase the localtime()
month by one, so the documentation above is correct again. 

V2.33
Then I started wondering what that CronErr file was doing in the
first place, since all errors where displayed in the CLI window.
That instantly lead to the removal of this Unix artefact.
I'm aware of the need for a stderr output, nevertheless Cron should
always be attached to a CLI, so we can get rid of CronErr. 

V2.4 (a = Aztec C V3.4b , L = Lattice C V4.0)
I experienced a loss of aprox. one second per minute in the AmiCron
wakeups, since it was send to sleep for a fixed amount of time (59
seconds). The time Cron did spent in "bed" increased with the
length of the command call and the workload of the machine
(especially I/O ints. like disk access). 
So I now align to the to the next minute and keep this alignment by
tranquilizing the task only for the remaining time 'till the next
minute. Although the goal of starting it on the minute may only work
if there is no heavy workload on your machine, this delay is at least
not cumulative, like the one in the original version.
Another odd thing is that the Delay() function (nasty AmigaDog) 
obviously creates 5 I/O ints. per second (measured with SysMon
by Perry S. Kivolovitz). 
Although I couldn't detect any performance decreases caused by these
interrupts, I decided to use the TimeDelay function from the Timer.c
RKM example by Rob Peck in version 2.4 of AmiCron. Besides creating
no I/O ints., I found that the TimeDelay() function is not effected
by other I/O ints., so it turned out to be MUCH more accurate than
the Delay() function and therefore worth compiling & linking that
timer.c part.  
I also included the path command line parameter, a check for the 
existance of the CronTab file and tighten up the code here and there.

Some hints for the serious AmiCron addict: 
If don't wanna AmiCron to stumble  through your default path and
blast you with requesters (i.e you sometimes remove a disk with
utilities on which you have a path assigned to), why not defining
your own path in the StartCron batch file? Quite simple, but very
effective.
AmiCron can be easyly terminated (on it's next wakeup) by typing
Ctrl-C in its window or by sending it a break using the BREAK
command.  

This project/enhancement/fix is a combined effort by:
                          
______  /          
______\O                    - The Software Brewery - 
      \\              		    
       o            Sparkling, fresh software from W.-Germany
                 
     @@@@@	      Straight from the bar to your Amiga
     |~~~|\        
     | | |/        
     |___|        With our regards to the Software Distillery
---------------------------------------------------------------------

a West-German group of (hopefully professional) Amiga programmers
inspired by the Software Destillery 
(but we germans are more into brewing & drinking beer <grin>).

Programming & documentation by <CB>

<CB> is : Christian Balzer 
          Im Wingertsberg 45
          D-6108 Weiterstadt
          W. Germany

Aztec C support by Christof Bonnkirch (another CB :-) )
Further support/ideas by Peter Stark, Heiko Rath and Ralf Woitinas.

I would like to thank Steve R. Sampson for his initial PD cron, Rick
Schaeffer for his port to the Amiga, Rob Peck for all the work he
did and will (hopefully) do in the future and especially Fred Fish
for his continuous effort to spread all that fantastic PD software 
all over the world, without all of them I wouldn't have done this.   
<CB>
SHAR_EOF
if test 8033 -ne "`wc -c AmiCron.doc`"
then
echo shar: error transmitting AmiCron.doc '(should have been 8033 characters)'
fi
echo shar: extracting .startcron '(391 characters)'
cat << \SHAR_EOF > .startcron
; Edit the "path" command to suit your system, and personal preferences.
;
; Note: in my startup-sequence I make assigns for /: (to vd0:), r: (to ram:),
;       and ~: to my "home" directory (where "home" is defined as the
;       directory I'm cd'd to when I start up "shell").  Makes life a little
;       easier!

path    ~:bin /:usr/local/bin /:usr/bin r: /:bin /:etc
amicron s:crontab

SHAR_EOF
if test 391 -ne "`wc -c .startcron`"
then
echo shar: error transmitting .startcron '(should have been 391 characters)'
fi
echo shar: extracting crontab '(16 characters)'
cat << \SHAR_EOF > crontab
* * * * * date

SHAR_EOF
if test 16 -ne "`wc -c crontab`"
then
echo shar: error transmitting crontab '(should have been 16 characters)'
fi
echo shar: extracting alias4shell '(65 characters)'
cat << \SHAR_EOF > alias4shell
alias startcron  "run newcli con:0/13/640/55/CRON s:.startcron"

SHAR_EOF
if test 65 -ne "`wc -c alias4shell`"
then
echo shar: error transmitting alias4shell '(should have been 65 characters)'
fi
#	End of shell archive
exit 0

ain@j.cc.purdue.edu (Patrick White) (04/28/88)

Submitted by:	kim@amdahl.uts.amdhal.com (Kim DeVaughn)
Summary:	unix cron for the Amiga -- run a command at a particular time.
Poster Boy:	Patrick White	(ain@j.cc.purdue.edu)
Archive Name:	sources/amiga/volume4/amicron24a.s.sh.Z
Tested.
 
NOTES:
   I re-did the arc to sepatate the binaries, sources & docs.
   There are some set-up files in the docs shar.
 
 
-- Pat White   (co-moderator comp.sources/binaries.amiga)
ARPA/UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM  PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906
 
========================================
 
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	Makefile.lat
#	Makefile.mnx
#	lmake
#	Amicron24.c
#	timer.c
# This archive created: Wed Apr 27 10:12:49 1988
# By:	Patrick White (PUCC Land, USA)
echo shar: extracting Makefile.lat '(299 characters)'
cat << \SHAR_EOF > Makefile.lat
OBJS=lib:c.o AmiCron24.o timer.o

LIBS=lib:lc.lib lib:amiga.lib

NAME=AmiCron

CC=lc

CFLAGS= -csuw -dLATTICE -r -b -v

$(NAME): $(OBJS)
	Blink from $(OBJS) lib $(LIBS) VERBOSE SC SD ND to $(NAME)


AmiCron24.o: AmiCron24.c 
	$(CC) $(CFLAGS) AmiCron24.c

timer.o: timer.c 
	$(CC) $(CFLAGS) timer.c

SHAR_EOF
if test 299 -ne "`wc -c Makefile.lat`"
then
echo shar: error transmitting Makefile.lat '(should have been 299 characters)'
fi
echo shar: extracting Makefile.mnx '(145 characters)'
cat << \SHAR_EOF > Makefile.mnx
AmiCron: Amicron.o timer.o
	ln -o AmiCron timer.o Amicron.o -lc32

Amicron.o: Amicron24.c
	cc +l Amicron24.c

timer.o: timer.c
	 cc +l timer.c	 
SHAR_EOF
if test 145 -ne "`wc -c Makefile.mnx`"
then
echo shar: error transmitting Makefile.mnx '(should have been 145 characters)'
fi
echo shar: extracting lmake '(142 characters)'
cat << \SHAR_EOF > lmake
lc -M -dLATTICE -csuw -r -b -v AmiCron24 timer
Blink from lib:c.o AmiCron24.o timer.o lib lib:lc.lib lib:amiga.lib VERBOSE SC SD ND to AmiCronSHAR_EOF
if test 142 -ne "`wc -c lmake`"
then
echo shar: error transmitting lmake '(should have been 142 characters)'
fi
echo shar: extracting Amicron24.c '(9440 characters)'
cat << \SHAR_EOF > Amicron24.c
/*
 *	amicron.c	(Version 2.4(a&L) by <CB>)
 *
 *	Public Domain (p) No Rights Reserved
 *
 *	This program operates as a daemon, waking up every minute
 *	to execute the CRONTAB table.  
 *
 *	Put in startup-sequence like:
 *		run newcli con:0/140/160/50/CronTask s:startcron
 *	The startcron file needs to contains just one line:
 *		amicron
 *
 *	Some notes are included below concerning the cron table
 *	file format.  In this version the cron table file is left
 *	on disk and not moved to core, and  the command character
 *	to signify a newline '%' is not used.
 *
 *	Some cron table entry examples:
 *
 *	Print the date in the crontask window every minute:
 *		* * * * * date
 *
 *	Print the date in the crontask window on the hour, every hour:
 *		0 * * * * date
 *
 *	Run uupc at 4:30 am every day except Sat and Sun:
 *		30 4 * * 1-5 uupc -siscuva
 *
 *	Backup the files every other day at 7:30 pm:
 *		30 19 * * 1,3,5 sdbackup -s LAST dh0: incbkup_1:
 *
 */

/* 
 * Public Domain (p) by S. R. Sampson
 * Version 2.3, October 1987
 * Amiga port by Rick Schaeffer October 1987
 *
 * Rick Schaeffer          UUCP:  seismo!uunet!iscuva!ricks!ricks
 * E. 13611 26th Ave.      Phone: (509)928-3533
 * Spokane, WA  99216
 *
 * Modified path for CronTab & CronErr to suit Amiga enviroment better
 * Version 2.31  <CB> 15.12.87 
 *
 * Fixed bug with CronTab entries specifying an event by date (month)
 * i.e. "* * 24 12 * say Merry christmas", now works!
 * Version 2.32 <CB> 25.12.87
 *
 * Removed "CronErr", an obvious Unix "feature"
 * Version 2.33 <CB> 31.12.87 
 *
 * Additional support for Lattice 4.0, changed to complete sleep (no more  
 * 5 I/O ints. per second), added command line parameter for CronTab path.
 * Added feature to align Cron to start on 01 seconds, including "loss"
 * due to lengthy command calls or extensive I/O.
 * Version 2.4 <CB> 10.01.88 
 *
                          
                          
______  /          
______\O                    - The Software Brewery - 
      \\              		    
       o            Sparkling, fresh software from W.-Germany
                 
     @@@@@	      Straight from the bar to your Amiga
     |~~~|\        
     | | |/        
     |___|        With our regards to the Software Distillery

Members are (listed alphabetically):
Christian Balzer alias <CB>, Lattice C, user interfaces, beer addict. 
Christof Bonnkirch, Aztec C, telecommunications, money adict.
Heiko Rath alias <HR>, Assembler, ROM-Kernal stuff, Marabou addict. 
Peter Stark alias PS, Lattice C, IO & utilities, WordStar addict.
Ralf Woitinas alias RAF, Assembler, anything, Ray-Tracing addict.
Torsten Wronski alias MM, Assembler, anything, girls addict.

Beverages: Altenmuenster Brauer Bier, Urfraenkisches Landbier, Grohe Bock.

Send exotic drinks, comments, critizism, flames to:

The Software Brewery
Christian Balzer
Im Wingertsberg 45
D-6108 Weiterstadt
West-Germany

Our BBS "AmigaNode" isn't online yet. As soon as it becomes available, 
you'll be the first to know :-).

 *
 * Compilation notes:
 * Just use the supplied "makefile.manx" for Aztec C 3.4(b) or later. 
 * Lattice C 4.0 users just execute "lmake" or use "makefile.lattice".
 * The whole compilation and link procedure (including timer.c) from RAM
 * took me 50 seconds with Lattice 4.0 and 67 seconds with Aztec 3.4b.
 * Please note that you need to link timer.o for the TimeDelay() function
 * if you don't use make or execute lmake.
 *
 * Well, the Lattice folks claim that LATTICE get's defined by their 
 * compiler, but it didn't work for me. So, if you don't use make or lmake, 
 * or define LATTICE, you'll get blasted by (my) Lattice if ya don't remove 
 * all the lines marked with "LK" below...
 *						<CB>
 */

#include <stdio.h>
#include <time.h>

#ifndef LATTICE			/*LK*/
#include <functions.h>		/*LK*/
#endif				/*LK*/

#ifdef LATTICE			/*LK*/
#include <string.h>
#include <proto/dos.h>
#endif				/*LK -the last one*/

#define TRUE 1
#define FALSE 0

#define CRONTAB "S:CronTab"	/* Our default path */

#define MAXLINE	132
#define SIZE	64

#define TITLE "\x9B1;33mAmiCron v2.4\x9B0m by \x9B1m<CB>\x9B0m & - \x9B3mThe Software Brewery\x9B0m -\n"
#define WHERE "Im Wingertsberg 45, D-6108 Weiterstadt, \x9B1mW-Germany\x9B0m\n"
 
int	eof;
short	sleepy;
char	min[SIZE], hour[SIZE], day[SIZE],
	month[SIZE], wday[SIZE], command[SIZE];
char	*tokv[] = { min, hour, day, month, wday };
char	crontabs[200];  /* You might define quite a path! <CB> */
FILE	*fd;
 
 
/*
 *	This is the basics, ready for bells and whistles
 *
 */


void main(argc, argv)
int argc;
char *argv[];
{
	void showhelp();
	void wakeup();

	/* Below we use the same functions & variables as in wakeup()
	   just to get the current second  <CB>*/

	register struct tm *tm;
	struct tm *localtime();
	long cur_time;
 	
	/* Tell the guy out there what he might do with this deamon
	 * and who made it. <CB>*/

	printf(TITLE);
	printf(WHERE);
	printf("Usage: %s [Path & Filename]\n",argv[0]);
	printf("       or '%s ?' for help\n",argv[0]);

	/* Now let's see if the user told us to look someplace else
	 * for our input file or if he want's some more usage hints <CB> */
  
	if (argc == 2) {
		if (argv[1][0] == '?') { 
			showhelp();
			exit(10);
		}
		else (void)strcpy(crontabs, argv[1]);
		
	}
	else (void)strcpy(crontabs, CRONTAB);	
	/* If there isn't a user path, we'll use the default <CB>*/

	/*Now tell the user with what path & filename we wound up*/
	printf("CronTab path = %s \n",crontabs);

	for (;;)  {

		wakeup();

		time(&cur_time);		/* get the current time */
		tm = localtime(&cur_time);	/* break it down */

		/* Now we calculate the amount of seconds
		 * 'till the next minute <CB>*/

		sleepy = (60-tm->tm_sec);	
		/* PLEASE don't decrease the 60 above, believe me,
		 * I know what I'm doing there! <CB> */ 

		TimeDelay(sleepy,0,0);	
		/* sleep 'till next minute */
	}
}

void wakeup()
{
	register struct tm *tm;
	struct tm *localtime();
	long cur_time;
	
	char doit[80];
 	
	time(&cur_time);		/* get the current time */
	tm = localtime(&cur_time);	/* break it down */
 
	/* Now let's see if there is a CronTab file out there <CB> */ 	

	if ((fd = fopen(crontabs, "r")) == NULL) {
	fprintf(stderr, "Can't open %s\nTry again\n", crontabs);
	exit(1);
	}


	eof = FALSE;
 
	while (!eof)  {
		if (getline() && match(min,tm->tm_min) &&
		   match(hour,tm->tm_hour) && match(day,tm->tm_mday) &&
		   match(month,tm->tm_mon+1) && match(wday,tm->tm_wday))  {
		/* Weird localtime months ^ range from 0-11 !!! <CB>*/
			(void)strcpy(doit,"RUN >nil: ");
			(void)strcat(doit,command);
			(void)Execute(doit,NULL,NULL);
			}
		}
	fclose(fd);
}
 
 
/*
 *	A line consists of six fields.  The first five are:
 *
 *		minute:         0-59
 *		hour:           0-23
 *		day:            1-31
 *		month:          1-12
 *		weekday:        0-6 (Sunday = 0)
 *
 *	The fields are seperated by spaces or tabs, with the
 *	first field left justified (no leading spaces or tabs).
 *	See below for optional field syntax.
 *
 *	The last field is the command field.  This command will
 *	be executed by the CLI just as if typed from a console.
 */
 
int getline()
{
	register char *p;
	register int   i;
	char    buffer[MAXLINE], *scanner(), *fgets();
 
	if (fgets(buffer, sizeof buffer, fd) == NULL)  {
		eof = TRUE;
		return(FALSE);
		}
 
	for (p = buffer, i = 0; i < 5; i++)  {
		if ((p = scanner(tokv[i], p)) == (char *)NULL)
			return(FALSE);
		}
 
	(void)strcpy(command, p);     /* scoop the command */
	return(TRUE);
}
 
 
char *scanner(token, offset)
register char   *token;		/* target buffer to receive scanned token */
register char   *offset;	/* place holder into source buffer */
{
	while ((*offset != ' ') && (*offset != '\t') && *offset)
		*token++ = *offset++;
 
	/*
	 *      Check for possible error condition
	 */
         
	if (!*offset)
		return ((char *)NULL);
 
	*token = '\0';
        
	while ((*offset == ' ') || (*offset == '\t'))
		offset++;
 
	return (offset);
}
 
 
/*
 *	This routine will match the left string with the right number.
 *
 *	The string can contain the following syntax:
 *
 *	*		This will return TRUE for any number
 *	x,y [,z, ...]	This will return TRUE for any number given.
 *	x-y		This will return TRUE for any number within
 *			the range of x thru y.
 */
 
int match(left, right)
register char   *left;
register int    right;
{
	register int	n;
	register char	c;
 
	n = 0;

	if (!strcmp(left, "*"))
		return(TRUE);
 
	while ((c = *left++) && (c >= '0') && (c <= '9'))
		n  =  (n * 10) + c - '0';
 
	switch (c)  {
		case '\0':
			return (right == n);
 
		case ',':
			if (right == n)
				return(TRUE);
			do {
				n = 0;
				while ((c = *left++) && (c >= '0') && (c <= '9'))
					n = (n * 10) + c - '0';
 				if (right == n)
					return(TRUE);
				} while (c == ',');
			return(FALSE);
 
		case '-':
			if (right < n)
				return(FALSE);
 
			n = 0;
			while ((c = *left++) && (c >= '0') && (c <= '9'))
				n = (n * 10) + c - '0';
 
			return(right <= n);
		}
}

void showhelp()		/* by <CB> */

{ 
	printf("\nWell, you really should read the .doc file,\n");
	printf("but here are some more hints:\n");
	printf("You might specify only ONE command line parameter,\n");
	printf("the path were Amicron should look for it's command table,\n");
	printf("including the filename of the command table.\n");
	printf("If you don't supply a path, Amicron will use it's default\n");
	printf("path (S:CronTab).\n");
}
SHAR_EOF
if test 9440 -ne "`wc -c Amicron24.c`"
then
echo shar: error transmitting Amicron24.c '(should have been 9440 characters)'
fi
echo shar: extracting timer.c '(4111 characters)'
cat << \SHAR_EOF > timer.c
/* SIMPLE TIMER EXAMPLE PROGRAM: 
 *
 * Includes dynamic allocation of data structures needed to communicate
 * with the timer device as well as the actual device IO
 *
 * Author:  Rob Peck, 12/1/85 */

/* Stripped to TimeDelay & supporting functions for Cron inclusion <CB> */

#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"
#include "exec/devices.h"
#include "devices/timer.h"

long TimerBase;		/* to get at the time comparison functions */


/* *********************************************************************** */
/*	Timer function - timedelay(seconds,microseconds)

	Your task is put to sleep for the specified time interval.

	If seconds > 0, then UNIT_VBLANK is used, delay is in multiples of
	60ths of a second.  If seconds < 0, then UNIT_MICROHZ is used for 
	more precision.    

	Returns value of 0 if no errors, nonzero (and no task sleeping)

	Notice that since this is a multi-tasking system, the delays
	shown here must be considered to be only approximate.

	Also note that this function is used primarily to show how
	a timer device is accessed, including the creation of the 
	message port and a message structure (IOStdReq).   Note that
	there is a Delay(interval) function already in the DOS.library.
	(See the DOS developer's manual for details).
	
	But this Delay() function leaves LOT to be desired, <CB>.
*/
/* *********************************************************************** */

extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();

struct timerequest 
*PrepareTimer(precision)
SHORT precision;
{
	/* return a pointer to a time request.  If any problem, return NULL */

	int error;
	SHORT whichunit;

	struct MsgPort *timerport;
	struct timerequest *timermsg;
	
        timerport = CreatePort(0,0);
        if (timerport == NULL) 
		return(NULL);	/* Error during CreatePort */

	timermsg = (struct timerequest *)CreateExtIO(
					timerport,sizeof(struct timerequest));
	if (timermsg == NULL)
		{
		DeletePort(timerport);
		return(NULL);	/* Error during CreateExtIO */
		}
	
	if(precision)	/* if true, use precision timer  ( under 1 second ) */
		whichunit = UNIT_MICROHZ;
	else
		whichunit = UNIT_VBLANK;

	error = OpenDevice(TIMERNAME, whichunit, timermsg, 0);
	if (error != 0)
		{
		DeleteExtIO(timermsg,sizeof(struct timerequest));
		DeletePort(timerport);
		return(NULL);	/* Error during OpenDevice */
		}
	return(timermsg);
}

int
GetTimerBase()
{
	int tbase;
	struct timerequest *tr;
	tr = PrepareTimer();
	tbase = (int)tr->tr_node.io_Device;		
	DeleteTimer(tr);
	return(tbase);
}

int 
TimeDelay(seconds,microseconds,precision)
		/* more precise timer than AmigaDOS Delay() */
ULONG seconds,microseconds;
int precision;
{
	int precise;
	struct timerequest *tr;
	if(seconds < 0 || precision != 0)
				/* do delay in terms of microseconds */ 
		precise = TRUE; /* yes, use the precision timer.     */
	else 
		precise = FALSE; /* no, not necessary */

	tr = PrepareTimer(precise);
					/* get a pointer to an initialized
					 * timer request block */
	if(tr == NULL) return(-1);	/* any nonzero return says timedelay
					 * routine didn't work. */
	WaitForTimer(tr,seconds,microseconds);

	DeleteTimer(tr);	/* deallocate temporary structures */
	return(0);
}			/* end of timedelay */


int
WaitForTimer(tr,seconds,microseconds)
ULONG seconds,microseconds;
struct timerequest *tr;
{
	tr->tr_node.io_Command = TR_ADDREQUEST;   /* add a new timer request */
        tr->tr_time.tv_secs =  seconds;        	/* seconds */
        tr->tr_time.tv_micro = microseconds; 	/* microseconds */
        DoIO( tr );             		/* post request to the timer */
						/* goes to sleep till done */
	return(0);
}

int
DeleteTimer(tr)
struct timerequest *tr;
{
	struct MsgPort *tp;

	tp = tr->tr_node.io_Message.mn_ReplyPort;
	if(tr != 0)
	{
		CloseDevice(tr);
		DeleteExtIO(tr,sizeof(struct timerequest));
	}
	if(tp != 0)
		DeletePort(tp);
	return(0);		
}
SHAR_EOF
if test 4111 -ne "`wc -c timer.c`"
then
echo shar: error transmitting timer.c '(should have been 4111 characters)'
fi
#	End of shell archive
exit 0