home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cenvi23.zip
/
CRON.CMM
< prev
next >
Wrap
Text File
|
1996-02-08
|
20KB
|
677 lines
/*
* Cron.cmm
*
* This script is designed to be left running all the time. At times specified
* in the crontab file, other scripts and programs are run.
*
* CRONTAB format is each line as such:
* MINUTE HOUR DAY_OF_MONTH MONTH DAY_OF_WEEK Command
*
* All fields are 0-based, except day of month. So the possible values are 0 to
* 1 less than you would expect. Sunday is 0 as is January.
*
* You can actually specify numbers in the field, or put in a * to match
* anything. You can use Words for month or day, use the first three letters.
* You can use numeric ranges or lists of numbers, such as:
*
* 1-4,5,6,8-10
*
*
* Ranges (and * which is consider min-max) can have a step, such as
* "* / 5" which means every five units. Spaces are not allowed.
*
* The day of month and day of week will both set off a match, so the entry
* will be run if EITHER matches. Use a dash in either field to match nothing.
*
*
* This version is designed to work on any CEnvi platform. If you come across
* something that does not work, please report it to us.
*
* Also note that this program uses some of the .CMM scripts distributed with
* CEnvi. If it cannot find them, some file types will not work. Currently
* supported file types and systems are:
*
*
* .NCF, .NLM Netware
* .BAT All (Netware uses a batch interpreter script)
* .CMD OS/2
* .COM,.EXE All except Netware
* .CMM All
*
* Any other extension will be done in the most generic way for that system.
* Hopefully, it will work.
*
* If you preceed the particular command with a '=', it is done synchronously
* as appropriate, usually on the same screen as cron. Don't let such
* applications hang or ask for input, because it is unlikely anyone will
* be around to do it. In this case, cron will be stuck waiting.
*
* The default is to launch the job asynchronously.
*/
// The cron.tab's default location
if( defined(_NWNLM_) )
{
crontab = "sys:/cron.tab";
} else {
crontab = "c:\\cron.tab";
}
seconds = 1;
// The last datestamp of the cron.tab file
last_time = 0;
/* ---------------------------------------------------------------------- */
/* Here is a C definition of the structure we are using, for easy of
* modification
*
* struct cron_entry {
* char *command;
* BYTE minute[60]; // We use flags for each of these fields
* BYTE hour[24];
* BYTE day[31];
* BYTE month[12];
* BYTE weekday[7];
* };
*/
/* ---------------------------------------------------------------------- */
/*
* Process a single numeric field, filling in the entries of the array
* to match. Return 0 on success, 1 on failure. Eat up all white space
* after the field.
*/
process_field(line,entry_array,max,text_strings,offset)
{
// By default, nothing is turned on.
for( i=0;i<max;i++ ) entry_array[i] = 0;
comma_ok = 0;
while( line[0] && !isspace(line[0]) )
{
if( comma_ok==1 && line[0]==',' ) line++;
comma_ok = 1;
if( line[0]=='-' ) { line++; continue; }
if( isdigit(line[0]) || line[0]=='*' )
{
first = 0; end = max-1; step = 1;
// First get a possible range
if( isdigit(line[0]) )
{
while( isdigit(line[0]) )
{ first = 10*first + line[0]-'0'; line++; }
if( line[0]=='-' )
{
line++;
end = 0;
while( isdigit(line[0]) )
{ end = 10*end + line[0]-'0'; line++; }
} else end = first;
}
else line++;
if( end<offset || end>=max+offset )
{
printf("Value is out of the valid range of %d-%d.\n",offset,max-1+offset);
return 1;
}
// And there may be a step value
if( line[0]=='/' )
{
line++;
step = 0;
while( isdigit(line[0]) )
{ step = 10*step + line[0]-'0'; line++; }
}
// Finally, set all those entries on.
for( i=first;i<=end;i+=step ) entry_array[i-offset] = 1;
} else {
if( text_strings==NULL || !isalpha(line[0]) ) return 1;
for( i=0;i<=GetArraySpan(text_strings);i++ )
if( !strnicmp(text_strings[i],line,3) )
{
entry_array[i-offset] = 1;
line+=3; break;
}
if( i>GetArraySpan(text_strings) )
{
printf("Unrecognized text name for this field.\n");
return 1;
}
}
}
while( isspace(line[0]) ) line++;
return 0;
}
months =
{ "jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec" };
days =
{ "sun","mon","tue","wed","thu","fri","sat" };
/*
* Process a single line from the cron.tab file and return an entry structure
* describing it. If the line is blank, a comment, or illegal return NULL;
*/
process_cron_line(line,line_number)
{
while( isspace(line[0]) ) line++;
// Ignore comments or blank lines.
if( line[0]=='\n' || line[0]=='\0' || line[0]=='#' ) return NULL;
// The line's format is described in the comments at the top of this file.
if( process_field(line,entry.minute,60,NULL,0) )
{ printf("Illegal entry field 1 on line %d.\n",line_number); return NULL; }
if( process_field(line,entry.hour,24,NULL,0) )
{ printf("Illegal entry field 2 on line %d.\n",line_number); return NULL; }
if( process_field(line,entry.day,32,NULL,1) )
{ printf("Illegal entry field 3 on line %d.\n",line_number); return NULL; }
if( process_field(line,entry.month,12,months,0) )
{ printf("Illegal entry field 4 on line %d.\n",line_number); return NULL; }
if( process_field(line,entry.weekday,7,days,0) )
{ printf("Illegal entry field 5 on line %d.\n",line_number); return NULL; }
strcpy(entry.command,line);
s = strlen(entry.command) - 1;
if( entry.command[s]=='\n' ) entry.command[s] = '\0';
return entry;
}
/* ---------------------------------------------------------------------- */
print_at_then_return(col,row,text)
{
pos = ScreenCursor();
ScreenCursor(col,row);
printf("%s",text); fflush(stdout);
ScreenCursor(pos.col,pos.row);
}
/* ---------------------------------------------------------------------- */
/*
* Read the cron.tab file in, creating a cron_entry structure. This structure
* is returned. Return NULL if unable to read in the cron.tab or if the
* cron.tab is empty.
*/
read_crontab()
{
sprintf(buffer,"Reading CRONTAB...",timebuf);
print_at_then_return(60,0,buffer);
Undefine(entries); entry_count = 0; line_number = 0;
buffer = ""; SetArraySpan(buffer,512);
if( (fp = fopen(crontab,"r"))==NULL )
{
return NULL;
}
while( !feof(fp) )
{
line_number++;
if( fgets(buffer,512,fp)==NULL ) break;
entry = process_cron_line(buffer,line_number);
if( entry!=NULL ) entries[entry_count++] = entry;
}
fclose(fp);
file = Directory(crontab);
if( file==NULL )
{
printf("Unable to get timestamp from crontab file.\n");
return NULL;
}
last_time = file[0].Write;
return defined(entries)?entries:NULL;
}
/*
* The particular entry should be executed now using the system-dependant
* way of executing them. The file's type is checked and used.
*/
cron_execute(command)
{
exec = "";
// For cool printing of date-time.
timebuf = ""; SetArraySpan(timebuf,256);
strftime(timebuf,256,"%m/%d/%y %H:%M:%S",localtime(time()));
sprintf(buffer2,"LAST CRON: [%s] %s",timebuf,command);
sprintf(buffer,"%-80s",buffer2);
print_at_then_return(0,2,buffer);
sync = 0;
if( command[0]=='=' ) { command++; sync = 1; }
if( (end = strchr(command,' '))==NULL )
end = command + strlen(command) - 4;
else
end -= 4;
//
// Each type of executable that we know about is done for every system as
// well as we can.
//
if( defined(_NWNLM_) && !strnicmp(end,".NCF",4) )
{
system(command);
return;
}
if( defined(_NWNLM_) && !strnicmp(end,".NLM",4) )
{
spawn(P_NOWAIT,command);
return;
}
if( !strnicmp(end,".CMM",4) )
{
if( sync )
{
Interpret(command,INTERP_FILE|INTERP_NOINHERIT_LOCAL|
INTERP_NOINHERIT_GLOBAL);
return;
}
if( defined(_NWNLM_) )
{
sprintf(exec,"load cenvi %s",command);
system(exec);
return;
}
if( defined(_WINDOWS_) )
{
sprintf(exec,"cenviw %s",command);
spawn(P_NOWAIT,exec);
return;
}
if( defined(_DOS_) )
{
sprintf(exec,"cenvid %s",command);
spawn(P_SWAP,exec);
return;
}
if( defined(_DOS32_) )
{
sprintf(exec,"cenvid32 %s",command);
spawn(P_NOWAIT,exec);
return;
}
if( defined(_OS2_) )
{
sprintf(exec,"cenvi2 %s",command);
spawn(P_NOWAIT,exec);
return;
}
if( defined(_NTCON_) || defined(_95CON_) )
{
sprintf(exec,"cenvint %s",command);
spawn(P_NOWAIT,exec);
return;
}
if( defined(_NTWIN_) || defined(_95WIN_) )
{
sprintf(exec,"cenviwnt %s",command);
spawn(P_NOWAIT,exec);
return;
}
// Hmmm, an unrecognized version of CEnvi. Well, this is the most generic
// way I can launch such a script.
sprintf(exec,"cenvi %s",command);
spawn(P_NOWAIT,exec);
return;
}
if( !defined(_NWNLM_) && (!strnicmp(end,".EXE",4) || !strnicmp(end,".COM",4)) )
{
if( defined(_OS2_) )
{
if( sync )
spawn(P_WAIT,command);
else
system("start /c %s",command);
return;
}
spawn(sync?P_WAIT:P_NOWAIT,command);
return;
}
if( defined(_OS2_) && !strnicmp(end,".CMD",4) )
{
spawn(sync?P_WAIT:P_NOWAIT,command);
return;
}
if( !strnicmp(end,".BAT",4) )
{
if( defined(_NWNLM_) )
{
if( sync )
{
sprintf(exec,"batch %s",command);
Interpret(exec,INTERP_FILE|INTERP_NOINHERIT_LOCAL|
INTERP_NOINHERIT_GLOBAL);
} else {
sprintf(exec,"load cenvi batch %s",command);
spawn(P_NOWAIT,exec);
}
return;
}
if( defined(_DOS_) )
spawn(sync?P_WAIT:P_SWAP,command);
else
spawn(sync?P_WAIT:P_NOWAIT,command);
return;
}
if( defined(_NWNLM_) )
{
spawn(P_NOWAIT,command);
return;
}
if( defined(_OS2_) )
{
sprintf(exec,"start cmd.exe /c %s",command);
} else {
if ( !strnicmp("start ",command,6) )
sprintf(exec,"%s",command);
else
sprintf(exec,"start command.com /c %s",command);
}
system(exec);
}
/*
* Go through each entry and see if it should be executed at this time.
*/
cron_checks(entries)
{
current_time = localtime(time());
doit = 0;
for( i=0;entries && i<=GetArraySpan(entries);i++ )
{
if( entries[i].minute[current_time.tm_min] &&
entries[i].hour[current_time.tm_hour] &&
entries[i].month[current_time.tm_mon] &&
// Remember, the two day fields both can match
(entries[i].day[current_time.tm_mday-1] ||
entries[i].weekday[current_time.tm_wday] )
)
// Needed to stop CEnvi from passing the variable by reference.
{
cron_execute(=entries[i].command);
doit = 1;
}
}
if( doit) update_list(entries);
}
/*
* Check if the crontab file has been changed
*/
cron_changed()
{
file = Directory(crontab);
if( file==NULL ) return 0;
return last_time!=file[0].Write;
}
/*
* Keeps a running clock on the screen.
*/
update_display()
{
timebuf = ""; SetArraySpan(timebuf,256);
strftime(timebuf,256,"%m/%d/%y %H:%M:%S",localtime(time()));
sprintf(buffer,"%18s",timebuf);
print_at_then_return(60,0,buffer);
}
/* ---------------------------------------------------------------------- */
num_days = { 31,28,31,30,31,30,31,31,30,31,30,31 };
/*
* Given an entry, figure out the next time it will be run. Return a structure
* describing that time (something to be printed). Return NULL if it
* will never again be run.
*/
next_time(entry)
{
current_time = localtime(time());
// first, determine the next month it is going to happen. It could either
// be this month from now to the end of the month, or one of the next months
// any time during the month. If we wrap around months, we must also increment
// the year.
// Note, 0 and 13 are both this month. However, 0 is limited by this day & time
// forward only.
for( month=0;month<13;month++ )
{
try_month = (current_time.tm_mon+month)%12;
// We wrapped into next year.
if( month+current_time.tm_mon==12 ) current_time.tm_year++;
// First, if cannot execute this month, we continue;
if( entry.month[try_month]==0 ) continue;
// We find the next day that matched. Note, if the month==0, we do no wrapping
start_day = (month==0)?(current_time.tm_mday-1):0;
// We ignore leap years, tough.
for( day=start_day;day<num_days[try_month];day++ )
{
tmp.tm_sec = 0; tmp.tm_min = 0; tmp.tm_hour = 0;
tmp.tm_mon = try_month; tmp.tm_mday = day+1;
// rough approximation of DST
tmp.tm_isdst = (try_month>2 && try_month<10)
tmp.tm_year = current_time.tm_year;
new = localtime(mktime(tmp));
if( (entry.day[day]==0) && (entry.weekday[new.tm_wday]==0) )
continue;
// Ok, this month and day is the next possible choice. Let's find a time that will
// work. Again, if month==0, it must be later than now.
start_hour = 0;
if( month==0 && day==start_day ) start_hour = current_time.tm_hour;
for( hour=start_hour;hour<24;hour++ )
{
if( entry.hour[hour]==0 ) continue;
// Finally, the minute: there must be some better way to do all this...
start_min = 0;
// Start one minute after now - the 'now' minute has already been done.
if( month==0 && day==start_day && hour==start_hour )
start_min = current_time.tm_min+1;
for( minute = start_min;minute<60;minute++ )
{
if( entry.minute[minute] )
{
// FOUND IT!!!!
current_time.tm_mon = try_month;
current_time.tm_mday = day+1;
current_time.tm_hour = hour;
current_time.tm_min = minute;
return current_time;
}
}
}
}
}
// We couldn't find a match, return never execute again. With the entry format
// I believe this really means it can never execute period.
return NULL;
}
datesort(elem1,elem2)
{
if( elem1.tm_year<elem2.tm_year ) return -1;
if( elem1.tm_year>elem2.tm_year ) return 1;
if( elem1.tm_mon<elem2.tm_mon ) return -1;
if( elem1.tm_mon>elem2.tm_mon ) return 1;
if( elem1.tm_mday<elem2.tm_mday ) return -1;
if( elem1.tm_mday>elem2.tm_mday ) return 1;
if( elem1.tm_hour<elem2.tm_hour ) return -1;
if( elem1.tm_hour>elem2.tm_hour ) return 1;
if( elem1.tm_min<elem2.tm_min ) return -1;
if( elem1.tm_min>elem2.tm_min ) return 1;
return 0;
}
/*
* Keep a list of all upcoming events on the screen
*/
update_list(entries)
{
ScreenCursor(1,7); printf("Upcoming Events:\n");
j = 0;
undefine(next);
// First we build a table of the next time these entries will be going off
// along with a text representation of such.
for( i=0;entries && i<=GetArraySpan(entries);i++ )
{
ret = next_time(entries[i]);
if( ret!=NULL )
{
// rough approximation of DST
ret.tm_isdst = (ret.tm_mon>2 && ret.tm_mon<10)
next[j] = ret = localtime(mktime(ret));
next[j++].command = entries[i].command;
}
}
if( defined(next) ) qsort(next,"datesort");
for( i=0;i<10;i++ )
{
ScreenCursor(0,9+i);
if( i<j )
{
strftime(buf,"%a, %b %d, %Y at %I:%M %p ",next[i]);
strcat(buf,next[i].command);
printf("%-79s\n",buf);
} else {
printf(" \n");
}
}
ScreenCursor(0,19);
printf("-------------------------------------------------------------------------------\n");
}
/* ---------------------------------------------------------------------- */
/*
* Edit the crontab file using an appropriate editor for the system.
*/
invoke_editor()
{
the_editor = "notepad";
if( defined(_DOS_) || defined(_DOS32_) )
{
mode = defined(_DOS32_) ? P_WAIT : P_SWAP; the_editor = "edit";
} else
mode = P_NOWAIT;
if( defined(_OS2_) ) the_editor = "e";
if( defined(_NWNLM_) ) the_editor = "edit";
if( defined(EDITOR) ) the_editor = EDITOR;
spawn(mode,the_editor,crontab);
}
/* ---------------------------------------------------------------------- */
main(argc,argv)
{
ScreenClear();
printf("CMM Cron, Version 1.1.\n");
printf(" [Q] Quit [E] Edit Crontab\n\n");
// You can specify the crontab as the first argument.
if( argc>=2 ) crontab = argv[1];
Undefine(entries);
entries = read_crontab();
printf("-------------------------------------------------------------------------------\n");
printf("Events will be processed as necessary. You can go away now. To update the\n");
printf("CRON.TAB at any time, simply edit and save it. Cron will automatically load it.\n");
printf("-------------------------------------------------------------------------------\n");
update_list(entries);
while( 1 )
{
// Get current time, determine how many seconds until the next minute.
// Use 61 instead of 60 to make sure we have flipped over to the next
// minute.
counter = 61 - localtime(time()).tm_sec;
// Wait one minute
while( counter>0 )
{
if( kbhit() )
switch( toupper(getch()) )
{
case 'Q': exit(0);
case 'E': invoke_editor(); break;
}
update_display(); // Prints a timer.
Suspend(seconds * 1000); // wait some seconds.
counter -= seconds; // Note that we waited.
}
if( cron_changed() )
{
printf("Crontab file has changed.\n");
Undefine(entries);
entries = read_crontab();
update_list(entries);
}
cron_checks(entries);
}
}