home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / ATRGF21.ZIP / ATRGF.CMD next >
OS/2 REXX Batch file  |  1993-09-20  |  36KB  |  933 lines

  1. /*
  2. program: atrgf.cmd
  3. type:    REXXSAA-OS/2, version 2.x
  4. purpose: execute command at specified time
  5. version: 2.1
  6. date:    1991-05-24
  7. changed: 1991-07-26, RGF, streamlined the code a little bit..., added colors
  8.          1992-06-01, RGF, adapted for 32bit OS/2
  9.          1993-08-02, RGF, bug fixed on /E-switch: would not take starting day
  10.                           into account (reported by Steve Hoiness,
  11.                                         <76077.3121@compuserve.com>)
  12.          1993-09-20, changed the definition of ANSI-color-sequences; gets them from
  13.                      procedure ScrColor.CMD
  14.  
  15.  
  16. author:  Rony G. Flatscher,
  17.          Wirtschaftsuniversität/Vienna
  18.          RONY@AWIWUW11.BITNET
  19.          flatscher@wu-wien.ac.at
  20.  
  21. needs:   all RxUtil-functions loaded, DATERGF.CMD, DATE2STR.CMD, SCRCOLOR.CMD
  22.  
  23. usage:   ATRGF [/W] [/T] time command
  24.          ATRGF [/W] [/T] time /NE:dayordate command
  25.          ATRGF [/W] [/T] time /E:dayordate command
  26.          ATRGF [/W] [/T] [time] /I:time command
  27.  
  28.          see enclosed Tutorial "RGFSHOW.CMD" and syntax below
  29.  
  30.  
  31. All rights reserved, copyrighted 1991 & 1992, no guarantee that it works without
  32. errors, etc. etc.
  33.  
  34. donated to the public domain granted that you are not charging anything (money
  35. etc.) for it and derivates based upon it, as you did not write it,
  36. etc. if that holds you may bundle it with commercial programs too
  37.  
  38. you may freely distribute this program, granted that no changes are made
  39. to it and that the accompanying tutorial "RGFSHOW.CMD" is being distributed
  40. together with DATERGF.CMD, DATE2STR.CMD, ATRGF.CMD, TIMEIT.CMD
  41.  
  42. Please, if you find an error, post me a message describing it, I will
  43. try to fix and rerelease it to the net.
  44.  
  45. procedures:
  46.     CHECK_TIME          check and parse time into hh:mm
  47.     SHOW_DURATION       show duration of command
  48.     DURATION            format elapsed seconds into time
  49.     NEXT_DATE           produce next date
  50.     NEXT_DAY            produce next week-day
  51.     SCHEDULE_IT         schedule command
  52.     SHOW_SLEEP_EXECUTE  show next invocation, sleep until it and execute command
  53.  
  54.  
  55. usage:   ATRGF [/W] [/T] time command
  56.          ATRGF [/W] [/T] time /NE:dayordate command
  57.          ATRGF [/W] [/T] time /E:dayordate command
  58.          ATRGF [/W] [/T] [time] /I:time command
  59.  
  60. syntax:
  61.     COMMAND ..... any command as entered thru the keyboard to start
  62.                   a program
  63.     TIME ........ on input 24hour- (military) or 12hour-format allowed,
  64.                   output will be allways in 24hour-format (military, computer)
  65.     DAYORDATE ... DAY[-DAY]|DATE[-DATE][,...]
  66.                   DAY .... 2 letter digit (MO, TU, WE, TH, FR, SA, SU)
  67.                   DATE ... 1-2 digits (1-31)
  68.                   more than one day or date must be delimited by a comma
  69.  
  70. flags:
  71.     /W  ......... execute ATRGF.CMD in a separate Window
  72.     /T  ......... Test
  73.     /NE: ........ NExt dayordate
  74.     /E:  ........ Every dayordate
  75.     /I:  ........ every time-Interval
  76.  
  77. */
  78.  
  79. SIGNAL ON HALT
  80.  
  81. IF ARG(1) = '' | ARG(1) = '?' THEN SIGNAL usage
  82.  
  83.  
  84. /* check whether RxFuncs are loaded, if not, load them */
  85. IF RxFuncQuery('SysLoadFuncs') THEN
  86. DO
  87.     /* load the load-function */
  88.     CALL RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'       
  89.  
  90.     /* load the Sys* utilities */
  91.     CALL SysLoadFuncs                                                 
  92. END
  93.  
  94. atrgf. = ''                     /* default for empty subscripts */
  95. /* defaults */
  96. atrgf.executions = 0                            /* number of executions so far */
  97. atrgf.format_date = "%yyyy-%mm-%dd"             /* format string for dates */
  98. atrgf.daynames = "MO TU WE TH FR SA SU"         /* valid daynames */
  99.  
  100.  
  101. PARSE ARG tmp                   /* as is argument */
  102.  
  103. atrgf.argument = STRIP(tmp)     /* get rid of leading & trailing blanks */
  104. atrgf.argument.upp = TRANSLATE(atrgf.argument)    /* get arguments in uppercase    */
  105.  
  106.  
  107. SAY
  108.  
  109. x1 = SUBSTR(atrgf.argument.upp, 1, 2)
  110. IF x1 = "/W" THEN                       /* start an own window ?*/
  111. DO
  112.    a1 = 3
  113.    IF SUBSTR(atrgf.argument.upp,3,1) = ' ' THEN /* find first non-blank */
  114.       a1 = VERIFY(atrgf.argument.upp,' ',,3)
  115.  
  116.    atrgf.argument = SUBSTR(atrgf.argument, a1)
  117.    '@START /C /WIN /MIN  "ATRGF 'ARG(1)'" /PGM atrgf' atrgf.argument       /* start a new window */
  118.    EXIT        /* end the program */
  119. END
  120.  
  121. x1 = SUBSTR(atrgf.argument.upp, 1, 2)
  122.  
  123. IF x1 = "/T" THEN               /* Test mode ? */
  124. DO
  125.    a1 = 3
  126.    atrgf.test = 1
  127.    IF SUBSTR(atrgf.argument.upp,3,1) = ' ' THEN /* find first non-blank */
  128.       a1 = VERIFY(atrgf.argument.upp,' ',,3)
  129.    atrgf.argument.upp = SUBSTR(atrgf.argument.upp, a1)
  130.    atrgf.argument = SUBSTR(atrgf.argument, a1)
  131. END
  132. ELSE
  133.    atrgf.test = 0
  134.  
  135. word1 = WORD(atrgf.argument.upp, 1)
  136.  
  137. PARSE VAR word1 hours ':' minutes
  138. time_in_hand = (DATATYPE(hours,'N'))    /* First argument a time-argument? */
  139.  
  140. IF time_in_hand THEN
  141.    atrgf.tim =  check_time(word1)            /* check time & get 24hourformat */
  142. ELSE
  143. DO /* no time given, therefore interval, starting immediately */
  144.    IF POS("/I:", word1) = 0 THEN
  145.    DO
  146.       errmsg = "wrong syntax; '/I:' expected."
  147.       SIGNAL error
  148.    END
  149. END
  150.  
  151. /* prepare initialization data */
  152. /* get current date and time */
  153. PARSE VALUE DATE("S") TIME("L") WITH atrgf.start.dat atrgf.start.tim
  154. atrgf.last.dat = atrgf.start.dat
  155. atrgf.last.tim = atrgf.start.tim
  156.  
  157. word2 = WORD(atrgf.argument.upp,2)     /* get parameter, if any */
  158.  
  159. SELECT
  160.    WHEN (POS("/I:", word2) > 0) | \time_in_hand THEN    /* Interval ? */
  161.         DO
  162.            atrgf.type = 1
  163.            PARSE VAR atrgf.argument.upp . "/I:" atrgf.interval .
  164.            PARSE VAR atrgf.argument . "/" . atrgf.command
  165.            atrgf.interval = check_time(atrgf.interval)
  166.  
  167.            /* decimal fraction of interval */
  168.            atrgf.interval.fract = DATERGF(atrgf.interval, "F")
  169.  
  170.            IF atrgf.tim = '' THEN         /* no start time given = start immediately */
  171.            DO
  172.                tmp = DATERGF(atrgf.start.dat atrgf.start.tim, "+", atrgf.interval.fract)
  173.                atrgf.next.dat = WORD(tmp, 1)
  174.  
  175.                IF WORDS(tmp) > 1 THEN atrgf.next.tim = SUBSTR(WORD(tmp, 2),1,5)
  176.                ELSE atrgf.next.tim = "00:00"
  177.            END
  178.            ELSE      /* starting time is given */
  179.            DO
  180.                IF atrgf.start.tim > atrgf.tim THEN /* start tomorrow, as it is already later than specified time */
  181.                DO
  182.                   atrgf.next.dat = DATERGF(atrgf.start.dat, "+", 1)
  183.                   atrgf.next.tim = atrgf.tim
  184.                END
  185.                ELSE     /* start today at specified time */
  186.                DO
  187.                   atrgf.next.dat = atrgf.start.dat
  188.                   atrgf.next.tim = atrgf.tim
  189.                END
  190.            END
  191.  
  192.            CALL schedule_it
  193.         END
  194.  
  195.    WHEN (POS("/NE:", word2) > 0) THEN   /* start on next date_or_day ? */
  196.         DO
  197.            atrgf.type = 2
  198.            PARSE VAR atrgf.argument.upp . "/NE:" dayordate .
  199.            PARSE VAR atrgf.argument . "/" . atrgf.command
  200.  
  201.            IF DATATYPE(dayordate, 'N') THEN     /* numeric */
  202.               IF dayordate < 1 OR dayordate > 31 THEN
  203.               DO
  204.                   errmsg = dayordate": invalid day-number for date"
  205.                   SIGNAL ERROR
  206.               END
  207.               ELSE
  208.               DO
  209.                    atrgf.next_date = dayordate % 1    /* get rid of leading 0 */
  210.                    atrgf.next_date_string = atrgf.next_date /* string to show */
  211.                    atrgf.next_date_no = 1             /* no. of dates */
  212.                    atrgf.next.dat = next_date(atrgf.next_date_no, atrgf.last.dat)
  213.               END
  214.            ELSE         /* weekday given */
  215.            DO
  216.                dayindex = WORDPOS(dayordate, atrgf.daynames)
  217.                IF dayindex = 0 THEN
  218.                DO
  219.                   errmsg = dayordate": invalid dayname"
  220.                   SIGNAL ERROR
  221.                END
  222.                atrgf.next_day = dayindex
  223.                atrgf.next_day_string = dayordate     /* string to show */
  224.                atrgf.next_day_no = 1                 /* no. of days */
  225.                atrgf.next.dat = next_day(atrgf.next_day_no, atrgf.last.dat)
  226.            END
  227.  
  228.            atrgf.next.tim = atrgf.tim
  229.  
  230.            CALL schedule_it
  231.            CALL show_duration
  232.         END
  233.  
  234.    WHEN (POS("/E:", word2) > 0) THEN    /* start on every date_or_day ? */
  235.         DO
  236.            atrgf.type = 3
  237.            PARSE VAR atrgf.argument.upp . "/E:" dayordate .
  238.            PARSE VAR atrgf.argument . "/" . atrgf.command
  239.  
  240.            /* Parse days or dates to execute command */
  241.            DO WHILE dayordate <> ''
  242.               PARSE VAR dayordate tmp1 ',' dayordate
  243.               PARSE VAR tmp1 day_start '-' day_end
  244.  
  245.               /* day or date ? */
  246.               IF DATATYPE(day_start, 'N') THEN     /* numeric */
  247.               DO
  248.                  IF day_start < 1 | day_start > 31 THEN
  249.                  DO
  250.                      errmsg = day_start": invalid date"
  251.                      SIGNAL ERROR
  252.                  END
  253.                  data_type = 1          /* date */
  254.               END
  255.               ELSE      /* weekday in hand */
  256.               DO
  257.                  IF WORDPOS(day_start, atrgf.daynames) = 0 THEN
  258.                  DO
  259.                     errmsg = day_start": invalid dayname"
  260.                     SIGNAL ERROR
  261.                  END
  262.                  data_type = 2          /* day */
  263.               END
  264.  
  265.               IF day_end = '' THEN      /* no interval */
  266.               DO
  267.                  IF data_type = 1 THEN  /* date in hand */
  268.                  DO
  269.                     tmp = day_start % 1         /* get rid of possible leading 0 */
  270.                     atrgf.tmp = 'x'             /* next invocation */
  271.                  END
  272.                  ELSE                  /* dayname in hand */
  273.                  DO
  274.                     tmp = WORDPOS(day_start, atrgf.daynames)
  275.                     atrgf.tmp = 'x'                  /* next invocation on dayname */
  276.                  END
  277.               END
  278.               ELSE           /* interval in hand */
  279.               DO
  280.                  IF data_type = 1 THEN       /* first token was a date: 1-31 */
  281.                  DO
  282.                     IF \DATATYPE(day_end, 'N') | day_end < 1 | day_end > 31 THEN
  283.                        DO
  284.                            errmsg = day_start'-'day_end": invalid date"
  285.                            SIGNAL ERROR
  286.                        END
  287.  
  288.                     IF day_end < day_start THEN         /* wrap around end of month ? */
  289.                     DO
  290.  
  291.                        day_start = day_start % 1            /* get rid of leading 0 */
  292.                        DO WHILE day_start < 32
  293.                           atrgf.day_start = 'x'           /* next invocation */
  294.                           day_start = day_start + 1
  295.                        END
  296.                        day_start = 1
  297.                     END
  298.  
  299.                     day_start = day_start % 1      /* get rid of leading 0 */
  300.                     DO WHILE day_start <= day_end
  301.                        atrgf.day_start = 'x'       /* next invocation */
  302.                        day_start = day_start + 1
  303.                     END
  304.                  END
  305.                  ELSE                /* first token was a day: MO-SU */
  306.                  DO
  307.                     dayindex_end = WORDPOS(day_end, atrgf.daynames)
  308.                     IF dayindex_end = 0 THEN
  309.                     DO
  310.                        errmsg = day_start'-'day_end": invalid dayname"
  311.                        SIGNAL ERROR
  312.                     END
  313.                     dayindex_start = WORDPOS(day_start, atrgf.daynames)
  314.  
  315.                     IF dayindex_end < dayindex_start THEN    /* wrap around end of week ? */
  316.                     DO
  317.                        DO WHILE dayindex_start < 8
  318.                           tmp = WORD(atrgf.daynames, dayindex_start)
  319.                           atrgf.tmp = 'x'    /* next invocation */
  320.                           dayindex_start = dayindex_start + 1
  321.                        END
  322.                        dayindex_start = 1
  323.                     END
  324.  
  325.                     DO WHILE dayindex_start <= dayindex_end
  326.                        tmp = WORD(atrgf.daynames, dayindex_start)
  327.                        atrgf.tmp = 'x'       /* next invocation */
  328.                        dayindex_start = dayindex_start + 1
  329.                     END
  330.                  END
  331.               END
  332.            END
  333.  
  334.            /* prepare ordered demo-values and invocation string */
  335.            /* prepare ordered invocation days */
  336.            atrgf.next_day_no = 0
  337.            DO i = 1 TO 7
  338.               tmp = WORD(atrgf.daynames, i)
  339.               IF atrgf.tmp <> '' THEN
  340.               DO
  341.                  IF atrgf.next_day <> '' THEN
  342.                  DO
  343.                     atrgf.next_day = atrgf.next_day i
  344.                     atrgf.next_day_string = atrgf.next_day_string', 'tmp
  345.                  END
  346.                  ELSE   /* first day-element */
  347.                  DO
  348.                     atrgf.next_day = i
  349.                     atrgf.next_day_string = tmp      /* string to show */
  350.                  END
  351.                  atrgf.next_day_no = atrgf.next_day_no + 1
  352.               END
  353.            END
  354.            IF atrgf.next_day_no = 0 THEN atrgf.next_day_no = ''
  355.  
  356.            /* prepare ordered invocation dates */
  357.            atrgf.next_date_no = 0
  358.            DO i = 1 TO 31
  359.               IF atrgf.i <> '' THEN
  360.               DO
  361.                  IF atrgf.next_date <> '' THEN
  362.                  DO
  363.                     atrgf.next_date = atrgf.next_date i
  364.                     IF (value_inhand + 1) = i THEN
  365.                     DO
  366.                         value_inhand = i
  367.                     END
  368.                     ELSE
  369.                     DO
  370.                        IF value_last_used <> value_inhand THEN
  371.                        DO
  372.                           atrgf.next_date_string = atrgf.next_date_string||'-'||value_inhand||', '||i
  373.                           value_inhand = i
  374.                           value_last_used = i
  375.                        END
  376.                        ELSE
  377.                        DO
  378.                           atrgf.next_date_string = atrgf.next_date_string||', '||i
  379.                           value_inhand = i
  380.                           value_last_used = i
  381.                        END
  382.                     END
  383.                  END
  384.                  ELSE   /* first date-element */
  385.                  DO
  386.                     atrgf.next_date = i
  387.                     atrgf.next_date_string = i       /* string to show */
  388.                     value_inhand = i
  389.                     value_last_used = i
  390.                  END
  391.                  atrgf.next_date_no = atrgf.next_date_no + 1
  392.               END
  393.            END
  394.  
  395.            IF atrgf.next_date_no = 0 THEN atrgf.next_date_no = ''
  396.            ELSE
  397.               IF value_last_used <> value_inhand THEN     /* interval left ? */
  398.               DO
  399.                  atrgf.next_date_string = atrgf.next_date_string||'-'||value_inhand
  400.                  value_inhand = 0
  401.               END
  402.  
  403.            CALL schedule_it
  404.  
  405.         END
  406.  
  407.    OTHERWISE                            /* start once on given time ? */
  408.         DO
  409.            atrgf.type = 4
  410.            PARSE VAR atrgf.argument . atrgf.command
  411.  
  412.            CALL schedule_it
  413.            CALL show_duration
  414.         END
  415. END
  416.  
  417. RETURN
  418. /* end of main routine ********************************************************/
  419.  
  420.  
  421.  
  422. /* parse & check time, return 24hour clock */
  423. CHECK_TIME: PROCEDURE
  424.     PARSE UPPER ARG tmp
  425.     time24 = 1                  /* starting with 24 hour time in mind */
  426.     time12 = POS('M', tmp)      /* AM or PM ? */
  427.     IF time12 > 0 THEN
  428.     DO
  429.       time24 = 0                /* 12 hour time in hand */
  430.       letter = SUBSTR(tmp, time12 - 1, 1)
  431.       IF \((letter = 'A') | letter = 'P') THEN
  432.       DO
  433.          errmsg = ARG(1)': not a valid AM/PM-time'
  434.          SIGNAL error
  435.       END
  436.       tmp = SUBSTR(tmp, 1, time12 - 2)  /* remove ?M */
  437.     END
  438.  
  439.     PARSE VAR tmp hours ':' minutes ':' seconds
  440.  
  441.     SELECT
  442.       WHEN hours = '' THEN hours = 0
  443.       WHEN \datatype(hours,'N') THEN     /* no numeric type */
  444.            DO
  445.               errmsg = ARG(1)": hours are not numeric"
  446.               SIGNAL error
  447.            END
  448.       WHEN (hours < 0) | (hours > 23) THEN      /* out of range    */
  449.            DO
  450.               errmsg = ARG(1)": hours out of range"
  451.               SIGNAL error
  452.            END
  453.       OTHERWISE NOP
  454.     END
  455.  
  456.     SELECT
  457.       WHEN minutes = '' THEN minutes = 0
  458.       WHEN \datatype(minutes,'N') THEN     /* no numeric type */
  459.            DO
  460.               errmsg = ARG(1)": minutes are not numeric"
  461.               SIGNAL error
  462.            END
  463.       WHEN (minutes < 0) | (minutes > 59) THEN /* out of range    */
  464.            DO
  465.               errmsg = ARG(1)": minutes out of range"
  466.               SIGNAL error
  467.            END
  468.       OTHERWISE NOP
  469.     END
  470.  
  471.     /* ignore seconds, if any */
  472.  
  473.     IF \time24 THEN             /* received a 12hour time, adjust it to 24hour time */
  474.     DO
  475.        IF (letter = 'A') & (hours = 12) THEN hours = 0
  476.        ELSE IF ((letter = 'P') & (hours < 12)) THEN hours = hours + 12
  477.     END
  478.     RETURN RIGHT(hours,2,'0')':'RIGHT(minutes,2,'0')
  479. /* end of CHECK_TIME **********************************************************/
  480.  
  481.  
  482.  
  483. /* produce next date for /NE: or /E: flags */
  484. NEXT_DATE:
  485.     date_index = ARG(1)         /* index for date-string */
  486.     last_dat = ARG(2)           /* last date to look-up */
  487.     date_index = date_index + 1
  488.     IF date_index > atrgf.next_date_no THEN
  489.        date_index = 1
  490.  
  491.     next_dat_to_produce = WORD(atrgf.next_date, date_index)
  492.  
  493.     digits = SUBSTR(last_dat, 7, 2)
  494.     eom = SUBSTR(DATERGF(last_dat, "ME"), 7, 2)
  495.  
  496.     /* already last date of month in hand ? If so, next month must be chosen */
  497.     IF digits = eom THEN digits = 99    /* already last date of month in hand ?*/
  498.  
  499.     /* next date within same month ? */
  500.     IF digits < next_dat_to_produce THEN
  501.     DO
  502.         /* already last date in month ? */
  503.         IF next_dat_to_produce < eom THEN       /* o.k. for producing new date */
  504.            result = SUBSTR(last_dat, 1, 6) || RIGHT(next_dat_to_produce,2,'0')
  505.         ELSE                                    /* date is last day of month */
  506.            result = SUBSTR(last_dat, 1, 6) || eom
  507.     END
  508.     ELSE      /* date of following month */
  509.     DO
  510.        tmp = DATERGF(last_dat, "ME", "1")       /* first date of next month */
  511.        last_day = DATERGF(tmp, "ME")            /* end of next month */
  512.        IF next_dat_to_produce < SUBSTR(last_day, 7, 2) THEN
  513.             result = SUBSTR(tmp, 1, 6) || RIGHT(next_dat_to_produce,2,'0')
  514.        ELSE result = last_day
  515.     END
  516.  
  517.     RETURN result               /* return next date and actual date_index */
  518. /* end of NEXT_DATE ***********************************************************/
  519.  
  520.  
  521.  
  522. /* produce next day for /NE: or /E: flags */
  523. NEXT_DAY:
  524.     day_index = ARG(1)          /* index for date-string */
  525.     last_dat = ARG(2)
  526.     day_index = day_index + 1
  527.  
  528.     IF day_index > atrgf.next_day_no THEN
  529.        day_index = 1
  530.  
  531.     next_day_to_produce = WORD(atrgf.next_day, day_index)
  532.  
  533.     IF DATERGF(last_dat, "DI") < next_day_to_produce THEN
  534.        result = DATERGF(last_dat, "WB", next_day_to_produce-1)
  535.     ELSE
  536.        result = DATERGF(last_dat, "WE", next_day_to_produce)
  537.  
  538.     RETURN result               /* return next date and actual day_index */
  539. /* end of NEXT_DAY ************************************************************/
  540.  
  541.  
  542.  
  543.  
  544. /* show-duration, if execution just took place once */
  545. SHOW_DURATION: PROCEDURE EXPOSE atrgf.
  546.     SAY
  547.     IF atrgf.test = 0 THEN
  548.     DO
  549.        SAY " execution started:" RIGHT(DATERGF(atrgf.last.dat, "DN")||',',12) DATE2STR(atrgf.last.dat, atrgf.format_date) SUBSTR(atrgf.last.tim,1,5)
  550.  
  551.        tmp = "   execution ended:"
  552.        IF atrgf.last.dat <> atrgf.ended.dat THEN
  553.           tmp = tmp RIGHT(DATERGF(atrgf.ended.dat, "DN")||',',12) DATE2STR(atrgf.ended.dat, atrgf.format_date)
  554.        ELSE
  555.           tmp = tmp RIGHT('',12) RIGHT('', LENGTH(DATE2STR(atrgf.ended.dat, atrgf.format_date)))
  556.  
  557.        SAY tmp  SUBSTR(atrgf.ended.tim,1,5) "(duration:" atrgf.ended.duration")"
  558.     END
  559.     ELSE
  560.     DO
  561.        x = RIGHT('',12) 'ATRGF: *** Test mode ***'
  562.        tmp = " execution started:"
  563.        SAY tmp x
  564.        tmp = "   execution ended:"
  565.        SAY tmp x
  566.     END
  567.     RETURN
  568. /* end of SHOW_DURATION ******************************************************/
  569.  
  570.  
  571.  
  572.  
  573. /* format elapsed seconds into time DURATION */
  574. DURATION: PROCEDURE
  575.  
  576.     fraction = DATERGF(ARG(1), "SECR")
  577.  
  578.     IF fraction >= 1 THEN tmp = fraction % 1 "day(s)" DATERGF(DATERGF(ARG(1), "SECR"), "FR")
  579.     ELSE tmp = DATERGF(DATERGF(ARG(1), "SECR"), "FR")
  580.  
  581.     RETURN tmp
  582. /* end of duration ************************************************************/
  583.  
  584.  
  585.  
  586.  
  587. /* calculate waiting time, before executing command */
  588. SCHEDULE_IT: PROCEDURE EXPOSE atrgf.
  589.     SELECT
  590.        WHEN atrgf.type = 1 THEN      /* interval */
  591.             DO FOREVER
  592.                IF atrgf.test = 0 THEN
  593.                   atrgf.to_wait_sec = DATERGF(atrgf.next.dat atrgf.next.tim, "-S", DATE("S") TIME("L"))
  594.                ELSE
  595.                   atrgf.to_wait_sec = DATERGF(atrgf.next.dat atrgf.next.tim, "-S", atrgf.last.dat atrgf.last.tim)
  596.  
  597.                nul = TIME("R")       /* reset timer */
  598.  
  599.                /* increment next execution until seconds to wait become positive */
  600.                DO WHILE atrgf.to_wait_sec < 0 & atrgf.test = 0
  601.                   tmp = DATERGF(atrgf.next.dat atrgf.next.tim, "+", atrgf.interval.fract)
  602.                   atrgf.next.dat = WORD(tmp, 1)       /* get next date */
  603.  
  604.                   IF WORDS(tmp) > 1 THEN atrgf.next.tim = SUBSTR(WORD(tmp, 2),1,5) /* get next time */
  605.                   ELSE atrgf.next.tim = "00:00"
  606.  
  607.                   atrgf.to_wait_sec = DATERGF(atrgf.next.dat atrgf.next.tim, "-S", DATE("S") TIME("L"))
  608.                   nul = TIME("R")       /* reset timer */
  609.                END
  610.  
  611.                atrgf.to_wait_sec = DATERGF(atrgf.to_wait_sec,"SEC")
  612.                CALL show_sleep_execute
  613.  
  614.                tmp = DATERGF(atrgf.last.dat atrgf.last.tim, "+", atrgf.interval.fract)
  615.                atrgf.next.dat = WORD(tmp, 1)    /* get date */
  616.  
  617.                IF WORDS(tmp) > 1 THEN atrgf.next.tim = SUBSTR(WORD(tmp, 2),1,5)  /* get next time */
  618.                ELSE atrgf.next.tim = "00:00"
  619.             END
  620.  
  621.        WHEN atrgf.type = 2 THEN      /* Next day or date */
  622.             DO
  623.                IF atrgf.test = 0 THEN
  624.                DO
  625.                   atrgf.to_wait_sec = DATERGF(DATERGF(atrgf.next.dat atrgf.next.tim, "-S", DATE("S") TIME("L")), "SEC")
  626.                END
  627.                ELSE
  628.                   atrgf.to_wait_sec = DATERGF(DATERGF(atrgf.next.dat atrgf.next.tim, "-S", atrgf.last.dat atrgf.last.tim), "SEC")
  629.  
  630.                nul = TIME("R")
  631.                CALL show_sleep_execute
  632.             END
  633.  
  634.        WHEN atrgf.type = 3 THEN      /* every given day or date */
  635.             DO
  636.                dates_todo = atrgf.next_date_no > 0
  637.                days_todo = atrgf.next_day_no > 0
  638.  
  639.                atrgf.next.tim = atrgf.tim       /* standard execution time */
  640.  
  641.                x1 = atrgf.last.dat
  642.  
  643. x1 = datergf(x1, "-", 1)        /* make sure, that invocation is possible on
  644.                                    same day too */
  645.  
  646.  
  647.                DO FOREVER
  648.                   IF dates_todo THEN    /* find first date after present one */
  649.                   DO
  650.                      di = DATERGF(x1, "D")      /* get day-portion of date */
  651.  
  652.                      /* if already last day of month, set index to last element */
  653.                      IF SUBSTR(DATERGF(x1, "ME"), 7,2) = di THEN
  654.                         tmp = atrgf.next_date_no
  655.                      ELSE
  656.                      DO         /* search for next date to produce */
  657.                         tmp = 1
  658.  
  659.                         DO FOREVER
  660.                            tmp0 = WORD(atrgf.next_date, tmp)
  661.                            IF tmp0 = '' | tmp0 > di THEN LEAVE
  662.                            tmp = tmp + 1
  663.                         END
  664.                         tmp = tmp - 1
  665.                      END
  666.  
  667.                      tmp1_date = next_date(tmp, x1)
  668.                   END
  669.                   ELSE tmp1_date = "99991231"
  670.  
  671.                   IF days_todo THEN     /* find first date after present one */
  672.                   DO
  673.                      di = DATERGF(x1, "DI")
  674.                      tmp = 1
  675.  
  676.                      DO FOREVER
  677.                         tmp0 = WORD(atrgf.next_day, tmp)
  678.                         IF tmp0 = '' | tmp0 > di THEN LEAVE
  679.                         tmp = tmp + 1
  680.                      END
  681.                      tmp = tmp - 1
  682.  
  683.                      tmp2_date = next_day(tmp, x1)
  684.                   END
  685.                   ELSE tmp2 = "99991231"
  686.  
  687.                   IF tmp1_date <= tmp2_date THEN        /* next to schedule: date */
  688.                       atrgf.next.dat = tmp1_date
  689.                   ELSE                                  /* next to schedule: day */
  690.                       atrgf.next.dat = tmp2_date
  691.  
  692.                   IF atrgf.test = 0 THEN        /* do it for real ? */
  693.                      atrgf.to_wait_sec = DATERGF(atrgf.next.dat atrgf.next.tim, "-S", DATE("S") TIME("L"))
  694.                   ELSE                          /* test ATRGF, show next invocation */
  695.                      atrgf.to_wait_sec = DATERGF(atrgf.next.dat atrgf.next.tim, "-S", atrgf.last.dat atrgf.last.tim)
  696.                   nul = TIME("R")               /* reset timer */
  697.  
  698.                   IF atrgf.to_wait_sec < 0 THEN /* execution lasted longer than next scheduled date! */
  699.                      x1 = atrgf.next.dat        /* get next date to execute */
  700.                   ELSE
  701.                   DO
  702.                       atrgf.to_wait_sec = DATERGF(atrgf.to_wait_sec, "SEC")
  703.                       CALL show_sleep_execute
  704.                       x1 = atrgf.last.dat
  705.                   END
  706.                END
  707.  
  708.             END
  709.  
  710.        OTHERWISE                     /* today or the next day */
  711.             DO
  712.                atrgf.next.tim = atrgf.tim
  713.  
  714.                IF atrgf.next.tim <= atrgf.last.tim THEN /* execution on next day */
  715.                   atrgf.next.dat = DATERGF(atrgf.start.dat, "+", 1)
  716.                ELSE
  717.                   atrgf.next.dat = atrgf.start.dat      /* execution on same day */
  718.  
  719.                atrgf.to_wait_sec = DATERGF(DATERGF(atrgf.next.dat atrgf.next.tim, "-S", DATE("S") TIME("L")), "SEC")
  720.                nul = TIME("R")
  721.  
  722.                CALL show_sleep_execute
  723.             END
  724.     END
  725.     RETURN
  726. /* end of SCHEDULE_IT *********************************************************/
  727.  
  728.  
  729.  
  730.  
  731. /* show time-table, sleep & execute passed command */
  732. SHOW_SLEEP_EXECUTE: PROCEDURE EXPOSE atrgf.
  733. /* define some colors to demonstrate them */
  734. esc    = '1B'x          /* define ESCape character */
  735. red    = esc||"[31m"    /* ANSI.SYS-control for red foreground */
  736. yellow = esc||"[33m"    /* ANSI.SYS-control for yellow foreground */
  737. cyan   = esc||"[36m"    /* ANSI.SYS-control for cyan foreground */
  738. normal = esc||"[0m"     /* ANSI.SYS-control for resetting attributes to normal */
  739.  
  740.     SAY
  741.     SAY "           started:" cyan||RIGHT(DATERGF(atrgf.start.dat, "DN")||',',12) DATE2STR(atrgf.start.dat, atrgf.format_date) atrgf.start.tim normal
  742.     IF atrgf.start.dat <> atrgf.last.dat | atrgf.start.tim <> atrgf.last.tim THEN
  743.     DO
  744.        SAY
  745.        SAY "    last execution:" yellow||RIGHT(DATERGF(atrgf.last.dat, "DN")||',',12) DATE2STR(atrgf.last.dat, atrgf.format_date) SUBSTR(atrgf.last.tim,1,5) normal
  746.  
  747.        IF atrgf.test = 0 THEN
  748.        DO
  749.           tmp = "   execution ended:"
  750.           IF atrgf.last.dat <> atrgf.ended.dat THEN
  751.              tmp2 = RIGHT(DATERGF(atrgf.ended.dat, "DN")||',',12) DATE2STR(atrgf.ended.dat, atrgf.format_date)
  752.           ELSE
  753.              tmp2 = RIGHT('',12) RIGHT('', LENGTH(DATE2STR(atrgf.ended.dat, atrgf.format_date)))
  754.  
  755.           tmp = tmp yellow||tmp2
  756.           SAY tmp  SUBSTR(atrgf.ended.tim,1,5) normal"(duration:" yellow||atrgf.ended.duration||normal")"
  757.        END
  758.        ELSE
  759.        DO
  760.           x = RIGHT('',12) '*** Test mode ***'
  761.           tmp = " execution started:"
  762.           SAY tmp x
  763.           tmp = "   execution ended:"
  764.           SAY tmp x
  765.        END
  766.     END
  767.  
  768.     SAY
  769.     SAY "    next execution:" cyan||RIGHT(DATERGF(atrgf.next.dat, "DN")||',',12) DATE2STR(atrgf.next.dat, atrgf.format_date) atrgf.next.tim normal
  770.  
  771.     tmp = duration(atrgf.to_wait_sec)
  772.  
  773.     SAY "      time to wait:" RIGHT("",12) cyan||tmp normal
  774.     SAY
  775.  
  776.     tmp = red
  777.     IF atrgf.type = 2 THEN           /* NEXT-date */
  778.        tmp = tmp || RIGHT("on next",12)
  779.     ELSE                             /* EVERY-date */
  780.        tmp = tmp || RIGHT("on EVERY",12)
  781.  
  782.     IF atrgf.next_date_no > 0 THEN
  783.     DO
  784.        SAY " execution date(s):" tmp yellow || atrgf.next_date_string normal
  785.     END
  786.  
  787.     IF atrgf.next_day_no > 0 THEN
  788.     DO
  789.        SAY "  execution day(s):" tmp yellow || atrgf.next_day_string normal
  790.     END
  791.  
  792.     IF atrgf.interval <> '' THEN
  793.        SAY "execution interval:" red || RIGHT("EVERY",12) || yellow  atrgf.interval normal
  794.  
  795.     IF atrgf.executions > 0 THEN
  796.        SAY " executions so far:" yellow || atrgf.executions normal"time(s)"
  797.  
  798.     SAY
  799.     SAY "command to execute:" cyan || atrgf.command normal
  800.     SAY
  801.  
  802.     IF atrgf.test > 0 THEN      /* testing mode */
  803.     DO
  804.        IF atrgf.type = 1 | atrgf.type = 3 THEN
  805.        DO
  806.           SAY '             ATRGF: *** Test mode ***'
  807.           SAY '                    Hit return to get next invocation date'
  808.           SAY '                    OR '
  809.           SAY '                    Enter EXIT to end testing mode'
  810.           PULL x
  811.           /* looping mode? If so, exit from here */
  812.           IF x = 'EXIT' & (atrgf.type = 1 | atrgf.type = 3) THEN EXIT
  813.        END
  814.  
  815.        atrgf.last.dat = atrgf.next.dat
  816.        atrgf.last.tim = atrgf.next.tim
  817.     END
  818.     ELSE
  819.     DO
  820.        x = atrgf.to_wait_sec - TIME("R")  /* deduct time needed to arrive at this position */
  821.        if x < 0 THEN x = 0
  822.        x = (x + 0.5) % 1                /* result must be an integer */
  823.        CALL SysSleep x                  /* seconds to sleep */
  824.  
  825.        SAY
  826.  
  827.        PARSE VALUE DATE("S") TIME("L") TIME("R") WITH atrgf.last.dat atrgf.last.tim .
  828.        'CALL 'atrgf.command             /* execute command */
  829.     END
  830.  
  831.     /* get actual date, time and elapsed time */
  832.     PARSE VALUE DATE("S") TIME("L") TIME("R") WITH atrgf.ended.dat atrgf.ended.tim tmp
  833.     atrgf.ended.duration = duration(tmp)
  834.     atrgf.executions = atrgf.executions + 1
  835.     RETURN
  836. /* end of SHOW_SLEEP_EXECUTE *************************************************/
  837.  
  838.  
  839.  
  840.  
  841. USAGE:
  842. /* get ANSI-color-sequences from ScrColor.CMD */
  843. PARSE VALUE ScrColor() WITH screen_normal screen_inverse text_normal text_info text_highlight text_alarm .
  844.  
  845.  
  846. SAY
  847. SAY text_info'ATRGF:'screen_normal'   execute command at specified time'
  848. SAY
  849. SAY
  850. SAY text_alarm'usage:'text_highlight'   ATRGF [/W] [/T] time command'
  851. SAY '         ATRGF [/W] [/T] time /NE:dayordate command'
  852. SAY '         ATRGF [/W] [/T] time /E:dayordate command'
  853. SAY '         ATRGF [/W] [/T] [time] /I:time command'screen_normal
  854. SAY
  855. SAY '         see enclosed Tutorial "RGFSHOW.CMD" and syntax below'
  856. SAY
  857. SAY text_alarm'syntax:'
  858. SAY text_info'   COMMAND'screen_normal' ..... any command as entetext_alarm thru the keyboard to start'
  859. SAY '                 a program'
  860. SAY text_info'   TIME'screen_normal' ........ on input 24hour- (military) or 12hour-format allowed,'
  861. SAY '                 output will be allways in 24hour-format (military, computer)'
  862. SAY text_info'   DAYORDATE'screen_normal' ... 'text_info'DAY[-DAY]|DATE[-DATE][,...]'
  863. SAY '                 DAY'screen_normal' .... 2 letter digit ('text_info'MO'screen_normal', 'text_info'TU'screen_normal',',
  864.     text_info'WE'screen_normal', 'text_info'TH'screen_normal', 'text_info'FR'screen_normal', 'text_info'SA'screen_normal','text_info'SU'screen_normal')'
  865.  
  866. SAY text_info'                 DATE'screen_normal' ... 1-2 digits ('text_info'1-31'screen_normal')'
  867. SAY '                 more than one day or date must be delimited by a comma'
  868. SAY
  869. SAY text_info'   flags:'
  870. SAY '   /W'screen_normal'  ......... execute ATRGF.CMD in a separate 'text_info'W'screen_normal'indow'
  871. SAY text_info'   /T'screen_normal'  ......... 'text_info'T'screen_normal'est mode'
  872. SAY text_info'   /NE:'screen_normal' ........ 'text_info'ne'screen_normal'xt dayordate'
  873. SAY text_info'   /E:'screen_normal'  ........ 'text_info'e'screen_normal'very dayordate'
  874. SAY text_info'   /I:'screen_normal'  ........ every time-'text_info'i'screen_normal'nterval'
  875. SAY
  876. SAY text_alarm'examples:'
  877. SAY
  878. SAY text_highlight'    ATRGF 00:00 copy *.* a:'screen_normal
  879. SAY '          ... copy all files at midnight to drive A:'
  880. SAY
  881. SAY text_highlight'    ATRGF 17:00 "beep & @echo Hey, time to go home! & PAUSE"'screen_normal
  882. SAY '          ... at 5:00pm beep, show message and wait for keystroke'
  883. SAY
  884. SAY text_highlight'    ATRGF 20:30 /NE:FR back_it_up'screen_normal
  885. SAY '          ... call "BACK_IT_UP" at 8:30pm on 'text_info'ne'screen_normal'xt friday'
  886. SAY
  887. SAY text_highlight'    ATRGF 20:30 /NE:31 back_it_up'screen_normal
  888. SAY '          ... call "BACK_IT_UP" at 8:30pm on the 'text_info'ne'screen_normal'xt last day of month'
  889. SAY
  890. SAY text_highlight'    ATRGF 20:30 /E:1-31 back_it_up'screen_normal
  891. SAY '          ... call "BACK_IT_UP" at 8:30pm on 'text_info'e'screen_normal'very day'
  892. SAY
  893. SAY text_highlight'    ATRGF 20:30 /E:FR,1,15,31 back_it_up'screen_normal
  894. SAY '          ... call "BACK_IT_UP" at 8:30pm on 'text_info'e'screen_normal'very friday, on every'
  895. SAY '              first, 15th and last day in a month'
  896. SAY
  897. SAY text_highlight'    ATRGF 17:00 /E:MO-FR "beep & @echo Hey, time to go home! & PAUSE"'screen_normal
  898. SAY '          ... at 5:00pm beep, show message and wait for keystroke mondays'
  899. SAY '              thru fridays (executing command forever on given DAYORDATE)'
  900. SAY
  901. SAY text_highlight'    ATRGF 00:00 /I:00:05 MOVE_IT.CMD -v'screen_normal
  902. SAY '          ... starting at midnight, execute every 5 minutes ('text_info'i'screen_normal'nterval)'
  903. SAY '              "move_it.cmd" with the parameter "-v"'
  904. SAY
  905. SAY text_highlight'    ATRGF /I:00:05 MOVE_IT.CMD -v'screen_normal
  906. SAY '          ... call every 5 minutes ('text_info'i'screen_normal'nterval) "move_it.cmd" with'
  907. SAY '              the parameter "-v"'
  908. SAY
  909. SAY text_highlight'    ATRGF /W 20:30 /E:FR-MO,15,31-1 back_it_up'screen_normal
  910. SAY '          ... call "BACK_IT_UP" at 8:30pm on 'text_info'e'screen_normal'very friday, saturday,'
  911. SAY '              sunday, monday, on 'text_info'e'screen_normal'very, first, 15th and last day in a month,'
  912. SAY '              execute in a separate 'text_info'w'screen_normal'indow'
  913. SAY
  914. SAY text_highlight'    ATRGF /T 20:30 /E:FR-MO,15,31-1 back_it_up'screen_normal
  915. SAY '          ... 'text_info't'screen_normal'esting of command; show invocation dates'
  916. SAY
  917. SAY text_highlight'    ATRGF /W /T 20:30 /E:FR-MO,15,31-1 back_it_up'screen_normal
  918. SAY '          ... 'text_info't'screen_normal'esting of command; show invocation dates; use a separate'
  919. SAY '              'text_info'w'screen_normal'indow for it'
  920. SAY
  921. EXIT
  922. /***************************************************/
  923.  
  924. ERROR:
  925.    /* error message on device "STDERR" */
  926.    '@ECHO ATRGF: 'errmsg' >&2'
  927.    EXIT (-1)
  928.  
  929. HALT:
  930.     SAY
  931.     SAY "User interrupted program."
  932.     EXIT
  933.