@@ -27,7 +27,7 @@ typedef struct Params_t {
27
27
char * url ;
28
28
char * location ;
29
29
int window ;
30
- int hours ;
30
+ int timeframe ;
31
31
size_t command ;
32
32
} params_t ;
33
33
@@ -112,41 +112,99 @@ bool parse_location(char *location_str, params_t *params) {
112
112
return true;
113
113
}
114
114
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 ) {
116
117
char * p ;
117
118
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
+ }
119
128
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 ) {
121
182
fprintf (stderr ,
122
183
"Error: estimated duration %s must be between 1 and 360 minutes (6 "
123
184
"hours)\n" ,
124
185
duration_str );
125
186
return false;
126
187
}
127
188
128
- params -> window = ( int ) conv ;
189
+ params -> window = window ;
129
190
return true;
130
191
}
131
192
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 );
139
197
return false;
140
198
}
141
- params -> hours = ( int ) conv ;
199
+ params -> timeframe = timeframe ;
142
200
return true;
143
201
}
144
202
145
203
bool parse_args (int argc , char * argv [], params_t * params ) {
146
204
default_args (params );
147
205
148
206
if (argc < 2 ) {
149
- // we need hours , at least
207
+ // we need timeframe , at least
150
208
return false;
151
209
}
152
210
@@ -182,7 +240,7 @@ bool parse_args(int argc, char *argv[], params_t *params) {
182
240
if (i == argc ) {
183
241
return false;
184
242
}
185
- if (!parse_hours (argv [i ], params )) {
243
+ if (!parse_timeframe (argv [i ], params )) {
186
244
return false;
187
245
}
188
246
i ++ ;
@@ -202,16 +260,16 @@ bool parse_args(int argc, char *argv[], params_t *params) {
202
260
203
261
void print_usage (char * name , params_t * params ) {
204
262
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 );
206
264
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\
208
266
(default %s) carbon intensity is at its lowest. Assumes command will complete\n\
209
267
complete within a default %d minute duration window. If no command is supplied,\n\
210
268
the program will just block until the best time.\n\n" ,
211
269
params -> location , params -> window );
212
270
printf ("OPTIONS:\n\
213
271
-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\
215
273
-u <sdk url> url prefix of Carbon Aware API server to consult OR\n\
216
274
full path to Carbon Aware CLI executable\n" );
217
275
}
@@ -225,7 +283,7 @@ void format_params(params_t *params, size_t iso8601_size, char *iso8601_format,
225
283
226
284
time (& now );
227
285
// add time this way isn't necessarily portable!
228
- now = now + params -> hours * 60 * 60 ;
286
+ now = now + params -> timeframe * 60 ;
229
287
time_tm = gmtime (& now );
230
288
size = snprintf (end , iso8601_size , iso8601_format ,
231
289
time_tm -> tm_year + 1900 , // years from 1900
0 commit comments