On Mon, 13 Apr 2020 20:27:30 -0600, Bob Beck wrote:
> In my hearts desire I'd love for "R" to be chosen for each line once at start
> up. (so in
> the above example the things are randomly distributed). but not sure how har
> d that is..
>
> If it saves code and effort I really think this is only useful for hours and
> minutes
Here's a version that uses a suggestion from Theo to support ranges
like "0~30" to mean a random number between 0 and 30 and just a
bare "~" to mean a random value in the valid range for that field.
The random values are chosen when the file is parsed which means
that on reload due to crontab edit they will change. I was trying
to avoid that initially but now I don't think it is a big deal.
- todd
Index: usr.sbin/cron/entry.c
===================================================================
RCS file: /cvs/src/usr.sbin/cron/entry.c,v
retrieving revision 1.49
diff -u -p -u -r1.49 entry.c
--- usr.sbin/cron/entry.c 13 Jun 2018 11:27:30 -0000 1.49
+++ usr.sbin/cron/entry.c 14 Apr 2020 01:52:13 -0000
@@ -450,13 +450,30 @@ static int
get_range(bitstr_t *bits, int low, int high, const char *names[],
int ch, FILE *file)
{
- /* range = number | number "-" number [ "/" number ]
+ /* range = number | number* "~" number* | number "-" number ["/" number]
*/
int i, num1, num2, num3;
+ /* XXX - parse ~, X~Y, X~ and ~Y */
+
+ if (ch == '~') {
+ /* '~' means a random number [high, low]
+ */
+ num1 = arc4random_uniform(high - low + 1) + low;
+ ch = get_char(file);
+ if (ch == EOF)
+ return (EOF);
+
+ if (EOF == set_element(bits, low, high, num1)) {
+ unget_char(ch, file);
+ return (EOF);
+ }
+ return (ch);
+ }
+
if (ch == '*') {
- /* '*' means "first-last" but can still be modified by /step
+ /* '*' means "high-low" but can still be modified by /step
*/
num1 = low;
num2 = high;
@@ -464,30 +481,45 @@ get_range(bitstr_t *bits, int low, int h
if (ch == EOF)
return (EOF);
} else {
- ch = get_number(&num1, low, names, ch, file, ",- \t\n");
+ ch = get_number(&num1, low, names, ch, file, ",-~ \t\n");
if (ch == EOF)
return (EOF);
- if (ch != '-') {
- /* not a range, it's a single number.
- */
- if (EOF == set_element(bits, low, high, num1)) {
- unget_char(ch, file);
- return (EOF);
- }
- return (ch);
- } else {
- /* eat the dash
+ switch (ch) {
+ case '-':
+ case '~':
+ num3 = ch;
+
+ /* eat the dash/tilde
*/
ch = get_char(file);
if (ch == EOF)
return (EOF);
- /* get the number following the dash
+ /* get the number following the dash/tilde
*/
ch = get_number(&num2, low, names, ch, file, "/, \t\n");
if (ch == EOF || num1 > num2)
return (EOF);
+
+ /* if it's a standard range, we're done here.
+ */
+ if (num3 == '-')
+ break;
+
+ /* get a random number in the range [num1, num2]
+ */
+ num3 = num1;
+ num1 = arc4random_uniform(num2 - num3 + 1) + num3;
+ /* FALLTHROUGH */
+ default:
+ /* not a range, it's a single number.
+ */
+ if (EOF == set_element(bits, low, high, num1)) {
+ unget_char(ch, file);
+ return (EOF);
+ }
+ return (ch);
}
}