Received: from j.cc.purdue.edu by VM.CC.PURDUE.EDU ; Thu, 12 May 88 16:02:53 EST
Received: by j.cc.purdue.edu (5.54/1.14)
    id AA05756; Thu, 12 May 88 15:46:15 EST
Date: Thu, 12 May 88 15:46:15 EST
From: ain@j.cc.purdue.edu (Patrick White)
Message-Id: <8805122046.AA05756@j.cc.purdue.edu>
To: fys-ma@fintuvm.BITNET
Subject: amicron sources
 
Newsgroups: comp.sources.amiga
Subject: amicron (sources)
Keywords: part 1 of 1, uncompiled
Approved: ain@j.cc.purdue.edu    (Patrick White)
 
Program Name:    amicron  (sources)
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.
   Fixed the shar -- added a newline to the end of the lmake file so this would
unshar correctly.  Pat 5/9/88
 
 
-- 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 '(143 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 AmiCron
SHAR_EOF
if test 143 -ne "`wc -c lmake`"
then
echo shar: error transmitting lmake '(should have been 143 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
