Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 09cb4b8

Browse files
committed
Allow timeframe and duration to be specified in a 1d12h30m format
1 parent d46d68c commit 09cb4b8

File tree

1 file changed

+77
-19
lines changed

1 file changed

+77
-19
lines changed

circa.c

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ typedef struct Params_t {
2727
char *url;
2828
char *location;
2929
int window;
30-
int hours;
30+
int timeframe;
3131
size_t command;
3232
} params_t;
3333

@@ -112,41 +112,99 @@ bool parse_location(char *location_str, params_t *params) {
112112
return true;
113113
}
114114

115-
bool parse_window_duration(char *duration_str, params_t *params) {
115+
// parse string to integer between 1 & max - a return value of 0 is an error
116+
int parse_number(char *str, const long max, const char *field, const char *help) {
116117
char *p;
117118
errno = 0;
118-
long conv = strtol(duration_str, &p, 10);
119+
long conv = strtol(str, &p, 10);
120+
121+
if (errno != 0 || *p != '\0' || conv > max || conv < 1) {
122+
fprintf(stderr, "Error: %s %s %s\n", field, str, help);
123+
return 0;
124+
}
125+
126+
return (int)conv;
127+
}
119128

120-
if (errno != 0 || *p != '\0' || conv > 6 * 60 || conv < 1) {
129+
// parse 0d0h0m into minutes - a return value of 0 is an error
130+
int parse_duration(char *str, const char* field) {
131+
int days = 0;
132+
int hours = 0;
133+
int mins = 0;
134+
char *match = str;
135+
size_t size = strnlen(str, 10);
136+
char *day_str = strtok(match, "d");
137+
if (day_str) {
138+
size_t day_size = strnlen(day_str, 10);
139+
if (day_size < size) {
140+
days = parse_number(day_str, 3, field, "must be between 1 and 3 days");
141+
if (days == 0) {
142+
return 0;
143+
}
144+
size -= day_size + 1;
145+
match = NULL;
146+
}
147+
}
148+
char *hour_str = strtok(match, "h");
149+
if (hour_str) {
150+
size_t hour_size = strnlen(hour_str, 10);
151+
if (hour_size < size) {
152+
hours = parse_number(hour_str, 48, field, "must be between 1 and 48 hours");
153+
if (hours == 0) {
154+
return 0;
155+
}
156+
size -= hour_size + 1;
157+
match = NULL;
158+
}
159+
}
160+
char *min_str = strtok(match, "m");
161+
if (min_str) {
162+
size_t min_size = strnlen(min_str, 10);
163+
if (min_size < size) {
164+
mins = parse_number(min_str, 90, field, "must be between 1 and 90 minutes");
165+
if (mins == 0) {
166+
return 0;
167+
}
168+
} else {
169+
// no units, so default to hours
170+
hours = parse_number(hour_str, 48, field, "must be between 1 and 48 hours");
171+
if (hours == 0) {
172+
return 0;
173+
}
174+
}
175+
}
176+
return days * 24 * 60 + hours * 60 + mins;
177+
}
178+
179+
bool parse_window_duration(char *duration_str, params_t *params) {
180+
int window = parse_duration(duration_str, "estimated duration");
181+
if (window == 0 || window > 6 * 60) {
121182
fprintf(stderr,
122183
"Error: estimated duration %s must be between 1 and 360 minutes (6 "
123184
"hours)\n",
124185
duration_str);
125186
return false;
126187
}
127188

128-
params->window = (int)conv;
189+
params->window = window;
129190
return true;
130191
}
131192

132-
bool parse_hours(char *hours_str, params_t *params) {
133-
char *p;
134-
errno = 0;
135-
long conv = strtol(hours_str, &p, 10);
136-
137-
if (errno != 0 || *p != '\0' || conv > 24 || conv < 1) {
138-
fprintf(stderr, "Error: hours %s must be between 1 and 24\n", hours_str);
193+
bool parse_timeframe(char *hours_str, params_t *params) {
194+
int timeframe = parse_duration(hours_str, "timeframe");
195+
if (timeframe == 0 || timeframe > 24 * 60) {
196+
fprintf(stderr, "Error: timeframe %s must be between 1 and 24 hours\n", hours_str);
139197
return false;
140198
}
141-
params->hours = (int)conv;
199+
params->timeframe = timeframe;
142200
return true;
143201
}
144202

145203
bool parse_args(int argc, char *argv[], params_t *params) {
146204
default_args(params);
147205

148206
if (argc < 2) {
149-
// we need hours, at least
207+
// we need timeframe, at least
150208
return false;
151209
}
152210

@@ -182,7 +240,7 @@ bool parse_args(int argc, char *argv[], params_t *params) {
182240
if (i == argc) {
183241
return false;
184242
}
185-
if (!parse_hours(argv[i], params)) {
243+
if (!parse_timeframe(argv[i], params)) {
186244
return false;
187245
}
188246
i++;
@@ -202,16 +260,16 @@ bool parse_args(int argc, char *argv[], params_t *params) {
202260

203261
void print_usage(char *name, params_t *params) {
204262
printf("OVERVIEW: Circa - carbon nice scripting\n\n");
205-
printf("USAGE: %s [option ...] hours [command [argument ...]]\n\n", name);
263+
printf("USAGE: %s [option ...] timeframe [command [argument ...]]\n\n", name);
206264
printf("DESCRIPTION:\n\
207-
Run COMMAND at somepoint in the next few HOURS (between 1 and 24) when local\n\
265+
Run COMMAND at somepoint in the TIMEFRAME (between 1 and 24 hours) when local\n\
208266
(default %s) carbon intensity is at its lowest. Assumes command will complete\n\
209267
complete within a default %d minute duration window. If no command is supplied,\n\
210268
the program will just block until the best time.\n\n",
211269
params->location, params->window);
212270
printf("OPTIONS:\n\
213271
-l <location> specify location to check for carbon intensity\n\
214-
-d <duration> estimated window of runtime of command/task in minutes\n\
272+
-d <duration> estimated window of runtime of command/task in hours\n\
215273
-u <sdk url> url prefix of Carbon Aware API server to consult OR\n\
216274
full path to Carbon Aware CLI executable\n");
217275
}
@@ -225,7 +283,7 @@ void format_params(params_t *params, size_t iso8601_size, char *iso8601_format,
225283

226284
time(&now);
227285
// add time this way isn't necessarily portable!
228-
now = now + params->hours * 60 * 60;
286+
now = now + params->timeframe * 60;
229287
time_tm = gmtime(&now);
230288
size = snprintf(end, iso8601_size, iso8601_format,
231289
time_tm->tm_year + 1900, // years from 1900

0 commit comments

Comments
 (0)