WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

Samples from Users
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Winbatch Version of Unix Cron scheduler

Keywords: 	 Unix cron scheduler

Here is my Winbatch Cron program. Its works best as a compiled exe. This post is the documentation. The attached file contains the cron.wbt file along with a sample crontab.txt file

Ron Laird 11-09-99


Documentation for Winbatch Cron version 1.8
November 08, 1998

This program implements a scheduler similar to UNIX Cron. It uses for input a file 
called 'crontab.txt' and for logging it produces a file called 'cronlog.txt'. This 
program is hardcoded to use as its home 'c:\cron'. Through testing I have determined 
this the best location. A typical installation would call for a directory called 
'cron' on drive 'c:' with a subdirectory called 'scripts'. WBCron can run a program 
from anywhere, but DOES NOT set the default directory. It is up to the executing 
program or script to set their own default directory at runtime.

When WBCron is started it goes through an initialization and then waits until the next 
full minute at 00 seconds before any scheduled jobs are run. This ensures that all 
jobs are evaluated on the minute. On the minute WBCron check the timestamp on the 
'crontab.txt file'. If the file has changed since the last minute it rereads the 
file, stripping out all comments. If the timestamp has not changed, jobs stored in 
an internal list are evaluated.

The command line executed can not contain spaces. Therefore,
'c:\cron\scripts\notepad mytxt.txt' is OK, but 'c:\cron\my program\notepad text.txt' 
is not. You could run 'text.txt' but the associated text editor would start, which
in most cases is notepad. This limitation is due to my use of the 'ParseData (line)'
function in WinBatch. I may change this in the future, but the ParseData data function 
is fast and was chosen for this reason. For scripts that I develop I don't use command 
line parameters.

Three are three limitations with this program. 
1. Ranges and specific values cannot exist in the same element. Break the schedule 
into two line (see examples)

2. You can only execute as many commands as can be executed in 60 seconds. WBCron needs 
to evaluate the schedule every 60 seconds and must sleep first. This is really not 
a problem since I would expect that 20 scheduled jobs or so per minute would
be good enough for most anyone. I have not really seen a limitation on the number 
of scheduled jobs, just a limit on the number that can executed in the same minute. 
This also depends alot on the speed of your CPU.

3. WBCron evaluates time based on a 24 hour clock. WBCron does not support a schedule 
spanning midnight. The range 22-02 is not supported. Break the schedule into 22-23 
and on another line 00-02. (The crontab file will be discussed below)

When this program is run on a Win95 or Win98 machine it will place itself in the toolbar.
It will terminate quietly when Windows shutsdown. Right clicking on the toolbar Icon 
will give you an option to quit cron. The option to quit will show up on the next full 
minute. The quickest way to make cron stop doing something is to have a shortcut to the 
crontab.txt file. Open the file and comment out the line in the schedule. 

When this program is run on an NT machine it hides itself with no icon. It is meant to 
be used with srvany from the NT resource kit. When run with srvany be sure to set the 
default run directory to c:\cron. (see the documentation that comes with srvany)

All schedules that are invoked with cron log to the cronlog.txt file in the cron 
directory.

The values minute, hour, date, month, day of week provide for a very powerful scheduling
tool. If your schedules are not working as expected go back and closely examine your 
schedule. Comment your schedule. Comments are stripped out and do not affect the 
performance of cron.

There is an internal keyword 'deletelog' When deletelog is scheduled it renames the 
cronlog.txt file to cronlog.bak. This provides a simple of way of maintaining the cron
log. Use deltelog as often as you like.

Installing Cron.exe
Create a directory c:\cron. Copy the cron.wbt or cron.exe into the c:\cron directory. Run
cron.exe at startup on win95 or win98. If running on NT cron can be started with srvany.exe
A crontab.txt file must be present in the c:\cron directory for cron to run. If the 
crontab.txt file is not found, cron will shutdown and log an error message. For security a 
file based version of its schedule must be found, it is the only way to know what program
cron will execute next.

WARNING: Cron will execute any program you tell it to. This includes delete and format.
Use cron at your own risk and only with scripts and programs that have been debugged.


Crontab.txt File Format

The following rules apply to the crontab file.
1. all fields are space delimited
2. all numbers are two digits 01,02,03,12,13 etc.
3. ranges can be numbers 01-10 etc and keywords Mon-Thu etc.
ranges cannot span Dec and ranges cannot span Sat 
4. multiple numbers within the same field are separated by ',' or '-' not both
5. The month and DayofWeek fields use words. Case is insignificant.
Mon Tue Wed Thu Fri Sat Sun Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec

# Crontab version 1.8 sample crontab.txt
#
# usage 
# usage [min hour date month dayofweek include\path\filename]
#
# A '#' sign makes it a comment
# Each element is space delimited. Multiple items are separated by ','. 
# Ranges of items are separated by '-'.
# A valid schedule consists of 6 elements separated by spaces.
# All items less then 10 must have a leading zero 01,02 etc 
# valid key words are:
# Sun Mon Tue Wed Thu Fri Sat Weekday(Mon-Fri) Weekend(Sat,Sun)
# Month names Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
# 
# Delete and backup cronlog.txt at midnight the 1st of every month
00 00 01 * * deletelog
# 
# Run every min every hour every month every day of the week
# * * * * * notepad.exe
#
# Run every min every hour every month every day of the week if its Tuesday
# * * * * Tue notepad.exe
#
# Run every weekday(Mon-Fri) at 10am
# 00 10 * * weekday notepad.exe
#
# Specific values
# Run 1,3,5,7 minutes after the hours of 10am and 11am in Aug and Nov if it is Mon or Wed
# regardless of the date
# 01,03,05,07 10,14 * Aug,Nov Mon,Wed notepad.exe
#
# Ranges of values
# Run every 1,2,3,4,5,6,7 mins after the hour of 10,11,12,13,14 dur Aug,Sep,Oct,Nov only if
# the 30th of the month and is Mon Tue or Wed
# 01-07 10-14 30 Aug-Nov Mon-Wed notepad.exe
#
# Ranges and Values cannot exist in the same element 1,2,3,4-7 is unsupported at this time
# 

cron.wbt

;***************************************************************************
;** 
;** Winbatch Cron
;** 17 Sep 1999 Ronald Laird
;** Purpose: Duplicate the function of Unix Cron for Win32
;** Inputs:  crontab.txt
;** Outputs: cronlog.txt
;** Revisions:  1.1 inital cut
;**             1.2 added dayofweek for param 5
;**             1.3 added service stuff for NT
;**             1.4 added only read crontab if it changes
;**                 added quiet termination (intcontrol (12,5,0,0,0))
;**             1.5 reorganized source code for readability
;**             1.6 added internal 'deletelog' command
;**             1.7 added range for day of week
;**             1.8 added range for month names
ver = "Cron 1.8.1"  ; initalize version number
;***************************************************************************
; to do
; allow both range and individual events on single line
; allow spaces in command line
;***************************************************************************
;** 
;** Main Program Loop
;** 
;** Purpose: All major work is done is this routine, calls all others
;** Inputs: 
;** Outputs: 
;** Revisions: 
;***************************************************************************
gosub initalize
If FileExist("crontab.txt")
  While(@TRUE)
    gosub readfile
	 gosub gettime
		for i = 1 to ItemCount(internalsched,"|")
		  line = ItemExtract (i, internalsched,"|")
		  linecount = i		  
		  ParseData (line)
		  if param0 < 6 
		    msg = "line %linecount% contains less than 6 parms"
		    gosub logging
		    Continue  ; skip current sched line try next one                          
		  endif

	     ; Parse Minute Value
		  schedminute = param1	 
		  if schedminute == "*" 
		    schedminute = computerminute
		  else
		   ;schedule is a range
		  if StrIndex (schedminute, "-", 1, @FWDSCAN) != @FALSE
		    start = ItemExtract (1, schedminute, "-")
		    finish = ItemExtract(2, schedminute, "-")		    
			 tempminute =""
			 for minsx = start to finish
			   if minsx <= 9 then minsx = strcat("0","%minsx%")
			   tempminute = ItemInsert (minsx, -1, tempminute , ",")
			 next
			   schedminute = tempminute
				if ItemLocate(computerminute, schedminute, ",") !=@FALSE then schedminute = computerminute
			 else
			   ;schedule is not a range
			   if ItemLocate(computerminute, schedminute, ",") !=@FALSE then schedminute = computerminute
		    endif
		   endif
		  
		  ;Parse Hour Value
		  schedhour = param2	    
		  if schedhour == "*"
		    schedhour = computerhour
		  else
		    ;schedule is a range
		    if StrIndex (schedhour, "-", 1, @FWDSCAN) != @FALSE
		      start = ItemExtract (1, schedhour, "-")
		      finish = ItemExtract(2, schedhour, "-")		    
			   temphours =""
			   for hours = start to finish
			     if hours <= 9 then hours = strcat("0","%hours%")
			     temphours = ItemInsert (hours, -1, temphours , ",")
			   next
			   schedhour = temphours
				if Itemlocate(computerhour, schedhour, ",") !=@FALSE then schedhour = computerhour
			 else
			   ;sched is not range
			   if Itemlocate(computerhour, schedhour, ",") !=@FALSE then schedhour = computerhour
			 endif
		  endif

		  ;Parse Day Value
		  schedday = param3	  
		  if schedday == "*"
	       schedday = computerday
		  else
		    if StrIndex (schedday, "-", 1, @FWDSCAN) != @FALSE
		      start = ItemExtract (1, schedday, "-")
		      finish = ItemExtract(2, schedday, "-")		    
			   tempdays =""
			   for days = start to finish
			    if days <= 9 then days = strcat("0","%days%")
			    tempdays = ItemInsert (days, -1, tempdays , ",")
			   next
			   schedday = tempdays
				if ItemLocate(computerday, schedday, ",") !=@FALSE then schedday = computerday
			 else
			   if ItemLocate(computerday, schedday, ",") !=@FALSE then schedday = computerday
		    endif
		  endif

		  ;Parse Month Value
		  schedmonth = Strupper(param4)	 
		  if schedmonth == "*"
		    schedmonth = computermonth
		  else
 		    if ItemLocate (schedmonth, monthlist, ",") !=0
 		      tempmonth=""
		      mon = ItemLocate(schedmonth,monthlist, ",")
			   if mon <= 9 then mon = strcat("0","%mon%")
			   tempmonth = ItemInsert(mon,-1, tempmonth, ",")
 			   schedmonth = tempmonth
		    endif

		    if StrIndex(schedmonth, ",", 1, @FWDSCAN) !=@FALSE
		      tempmonth =""
		      for months = 1 to ItemCount(schedmonth, ",")
		        mon = ItemLocate((ItemExtract(months,schedmonth,",")),monthlist, ",")				
 			     if mon <= 9 then mon = strcat("0","%mon%")
				  tempmonth = ItemInsert(mon,-1, tempmonth, ",")
 		      next
			     schedmonth = tempmonth
		    endif

		    if StrIndex(schedmonth, "-", 1, @FWDSCAN) !=@FALSE
		      start = ItemLocate((ItemExtract(1, schedmonth, "-")), monthlist, ",")
			   finish = ItemLocate((ItemExtract(2, schedmonth, "-")),monthlist, ",")        
			   tempmonth =""
			   for months = start to finish
			     if months <= 9 then months = strcat("0","%months%")
			     tempmonth = ItemInsert (months, -1, tempmonth, ",") 
			   next
				  schedmonth = tempmonth
		    endif
		    if ItemLocate(computermonth, schedmonth, ",") !=@FALSE then schedmonth = computermonth
		  endif

		  ;Parse Day of Week Value
		  schedweekday = strupper(param5)
	     if schedweekday == "*"
		    schedweekday = computerweekday
		  else
		    if StrIndex(schedweekday, "-", 1,@FWDSCAN) !=@FALSE  ; schedule is a range of days
		      ;lookup day index of fist day in range by dayname
			   start = ItemLocate((ItemExtract(1, schedweekday, "-")), daylist, ",")		 
			   ;lookup day index of second day in range by dayname
			   finish = ItemLocate((ItemExtract(2, schedweekday, "-")), daylist, ",")
			   tempday=""
			   for days = start to finish
			     if days <= 6 then days = strcat("0","%days%")
				  ;lookup day in daylist by day number and insert dayname into tempday
				  tempday = ItemInsert((ItemExtract(days, daylist, ",")), -1, tempday, ",") 
			   next
			   schedweekday = tempday
		    endif 
			 if schedweekday == "WEEKDAY" then schedweekday = "MON,TUE,WED,TUR,FRI"
		    if schedweekday == "WEEKEND" then schedweekday = "SAT,SUN"
			 if ItemLocate(computerweekday, schedweekday, ",") !=@FALSE then schedweekday = computerweekday
  		  endif
		 
		  filename = param6
	 	  ; Determine if it's time for something to run
		  if computerminute == schedminute 
			 if computerhour == schedhour
			   if computerday == schedday
				  if computermonth == schedmonth
				    if computerweekday == schedweekday
				      ;do stuff  
						if filename == "deletelog"
						  gosub logbackup
						else
						  errormode(@Off)
				        runstat = run("%filename%","%param7%")
				        errormode(@Cancel)
				        if runstat == @TRUE
					       msg = "run %filename% %param7% OK"
						    gosub logging
				        else
					       msg = "run %filename% %param7% BAD"
						    gosub logging
						  endif
						endif  ; filename
				    endif  ; schedweekday
				  endif  ; schedmonth
				endif  ; scheday
			 endif  ; schedhour
		  endif ; schedminute
      next ; line of interal schedule
    drop(linecount,param0,param1,param2,param3,param4,param5,param6,line)
    gosub sleep
    click = IntControl(1007, 0, 1, ver, "shell32.dll|40")
    if click == "2"
      q = AskYesNo('Cron', 'Quit Cron YES/NO?')
      If q == @YES
	     msg = "%ver% Exiting"
		  gosub logging
		  exit
	   endif
    endif
  EndWhile
else
 gosub fatal
endif
exit
;END PROGRAM


;***************************************************************************
;** 
;**   Logging Subroutine
;** 
;** Purpose: Open a file and log events
;** Inputs: 
;** Outputs: cronlog.txt
;** Revisions: 
;***************************************************************************
:logging
log = FileOpen("cronlog.txt","APPEND")
FileWrite(log,"%now% %msg%")
FileClose(log)
return


;***************************************************************************
;** 
;**    Sleep Subroutne
;** 
;** Purpose: Sleep untill next full minute. Keep sleep time from drifting
;** Inputs: 
;** Outputs: 
;** Revisions: 
;***************************************************************************
:sleep
sleepuntil = TimeAdd(adjustedtime,"0000:00:00:00:01:00") ; Adds 1 minute to last time lookup
TimeWait(sleepuntil)  ; Waits for the next time to occur
return


;***************************************************************************
;** 
;**   Get Time Subroutine
;** 
;** Purpose:  Take system time and parse into usefull variables.
;** Inputs: 
;** Outputs: 
;** Revisions: 
;***************************************************************************
:gettime
now = TimeYmdHms ( )
computerweekday= strupper(Itemextract("1", (TimeDate()), " "))
computerminute = ItemExtract("5", now, ":")
computerhour = ItemExtract("4", now, ":")
computerday = ItemExtract("3", now, ":")
computermonth = ItemExtract("2", now, ":")
computeryear = ItemExtract("1", now, ":")
adjustedtime = strcat(computeryear,":",computermonth,":",computerday, ":",computerhour,":", computerminute,":", "00")
return


;***************************************************************************
;** 
;**   System Type Subroutine
;** 
;** Purpose:  Calucalte system type and configure runtime
;** Inputs: 
;** Outputs: 
;** Revisions: 
;***************************************************************************
:systemtype
;-4 Windows Platform;  
;    0 = Other  1 = Windows  2 = Windows for Workgroups  3 = Win32s  4 = Windows NT  5 = Windows 95 or 98
osint = WinMetrics(-4)
Switch osint
     case 0
          os = "Other"
          break
     case 1
          os = "Windows"
          break
     case 2
          os = "Windows for Workgroups"
          break
     case 3
          os = "Win32s"
          break
     case 4  
          os = "Windows NT"
          break
     case 5  
          os = "Windows 95/98"
          break
    case osint ; default case
          os = "UNKNOWN"
          break
EndSwitch
return


;***************************************************************************
;** 
;** 	 Read Crontab.txt file Subroutine
;** 
;** Purpose:  read imput file at startup and only when it changes
;** Inputs: 	crontab.txt
;** Outputs: 
;** Revisions: 
;***************************************************************************
:readfile
if fileexist("crontab.txt") == @False then gosub fatal
filetime = filetimecode("crontab.txt")

if oldfiletime == filetime
  ;read from array
  oldfiletime = filetime
else
  internalsched = ""
  oldfiletime = filetimecode("crontab.txt")
  schedule = FileOpen("crontab.txt","READ")
  While(@TRUE)
    line = FileRead(schedule)
	 if line == "*EOF*" Then Break
	 if StrSub (line, 1, 1) == "#" then Continue
    internalsched = ItemInsert (line, -1, internalsched,"|")
  Endwhile
  FileClose(schedule)
 endif
return


;***************************************************************************
;** 
;**  Backup and purge logs file
;** 
;** Purpose:  To provide an interalfunction to kill large logfile
;** Inputs:   cronlog.txt
;** Outputs:  cronlog.bak
;** Revisions: 
;***************************************************************************
:logbackup
FileMove ("cronlog.txt", "cronlog.bak", @FALSE)
msg = "Log backup occured %ver%"
gosub logging
return


;***************************************************************************
;** 
;**   Initalize program startup
;** 
;** Purpose:  This subroutine is only used one at program initalization
;** Inputs: 
;** Outputs: 
;** Revisions: 
;***************************************************************************
:initalize
IntControl (12, 5, 0, 0, 0);allow quite termination of application
filetime = "" ; initalize filetime timestame
oldfiletime = ""  ; initalize oldfile timestamp
monthlist ="JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC" ; initalize month list
daylist = "SUN,MON,TUE,WED,THU,FRI,SAT" ; initalize day list
now = TimeYmdHms ( )  ; initalize time
msg = "%ver% Started" ; initalize messages
gosub systemtype
if os == "Windows 95/98" then IntControl(1007, 1, 1, ver, "pifmgr.dll|14") ; run in toolbar

if os == "Windows NT"
  IntControl (1001, 1, 0, 0, 0); run as service
  IntControl (1002, 0, 0, 0, 0); hide Icon
endif

dirchange("c:\cron")  ; The cron directory is hard coded. 

gosub logging
gosub gettime
gosub sleep
return

:fatal
if os == "Windows 95/98"
  Display(5,"Cron Error","crontab file not found!")
endif
msg = "%ver% Exiting, crontab file not found"
gosub logging
exit
return

Article ID:   W14717
Filename:   Cron Scheduler - Winbatch Version.txt
File Created: 2000:09:19:16:10:18
Last Updated: 2000:09:19:16:10:18