patterncModerate
timeleft utility
Viewed 0 times
utilitytimeleftstackoverflow
Problem
This utility tells you how much time is left until the time you set before.
Setting time:
Using utility:
Code:
Setting time:
> timeleft set '2017/04/25;15:00:00'Using utility:
> timeleft
2 days, 10 hours, 40 minutes, 25 seconds remaining...Code:
#include // strcmp
#include // fopen, fclose, fprintf, fscanf, sscanf
#include // time, mktime
#define TIME_PATH "time.txt"
static void printRemainingTime(time_t t) {
const char *s = "%d days, %d hours, %d minutes, %d seconds remaining...\n";
int days = t / 86400; t -= days * 86400;
int hours = t / 3600; t -= hours * 3600;
int minutes = t / 60; t -= minutes * 60;
int seconds = t;
fprintf(stdout, s, days, hours, minutes, seconds);
}
int main(int argc, char **argv) {
int status = 0;
if (argc = ref) fprintf(stdout, "It's over!\n");
else printRemainingTime(ref - now);
}
fclose(f);
}
} else if (argc == 3 && strcmp(argv[1], "set") == 0) {
int Y, M, D, h, m, s;
if (sscanf(argv[2], "%d/%d/%d;%d:%d:%d", &Y,&M,&D,&h,&m,&s) != 6) {
fprintf(stderr, "Invalid time format\n");
} else if (Y >= 2038) {
fprintf(stderr, "Do not plan too far ahead!\n");
} else {
struct tm t = { s, m, h, D, M - 1, Y - 1900, -1, -1, -1 };
time_t ut = mktime(&t);
if (ut < 0) {
fprintf(stderr, "Parsing/range error\n");
status = 1;
} else {
FILE *f = fopen(TIME_PATH, "w");
if (!f) {
fprintf(stderr, "Failed to save time\n");
status = 1;
} else {
fprintf(f, "%ld", (long) ut);
fclose(f);
}
}
}
} else {
fprintf(stderr, "Usage: ");
if (argv[0]) fprintf(stderr, "%s ", argv[0]);
fprintf(stderr, "[set YYYY/MM/DD;hh:mm:ss]\n");
}
return status;
}Solution
-
It doesn't compile without warnings under
-
Expecting a semi-colon in the command-line arguments is inconvenient: it means that you always have to quote the argument when running the program from the shell:
It would be better to use some other input format, one that doesn't use shell meta-characters.
-
[Recommendation deleted following threat of violence in comments.]
-
Separating the declaration of
then the compilation succeeds without warning under both Clang and GCC, but the output is nonsense:
But if you had written instead:
then Clang detects the problem:
It doesn't compile without warnings under
clang -Wextra:$ clang -Wall -Wextra cr161559.c
cr161559.c:43:69: warning: missing field 'tm_gmtoff' initializer
[-Wmissing-field-initializers]
struct tm t = { s, m, h, D, M - 1, Y - 1900, -1, -1, -1 };-
Expecting a semi-colon in the command-line arguments is inconvenient: it means that you always have to quote the argument when running the program from the shell:
$ timeleft set 2017/04/25;15:00:00
Invalid time format
bash: 15:00:00: command not foundIt would be better to use some other input format, one that doesn't use shell meta-characters.
-
[Recommendation deleted following threat of violence in comments.]
-
Separating the declaration of
s from the call to fprintf means that you won't get a warning (at least not from current versions of Clang or GCC) if the format string doesn't match the arguments. For example, if you accidentally omitted one of the arguments:const char *s = "%d days, %d hours, %d minutes, %d seconds remaining...\n";
/* ... */
fprintf(stdout, s, days, hours, minutes);then the compilation succeeds without warning under both Clang and GCC, but the output is nonsense:
$ timeleft
1 days, 22 hours, 33 minutes, 142630783 seconds remaining...But if you had written instead:
printf("%d days, %d hours, %d minutes, %d seconds remaining...\n",
days, hours, minutes);then Clang detects the problem:
cr161559.c:12:45: warning: more '%' conversions than data arguments [-Wformat]
printf("%d days, %d hours, %d minutes, %d seconds remaining...\n",
~^Code Snippets
$ clang -Wall -Wextra cr161559.c
cr161559.c:43:69: warning: missing field 'tm_gmtoff' initializer
[-Wmissing-field-initializers]
struct tm t = { s, m, h, D, M - 1, Y - 1900, -1, -1, -1 };$ timeleft set 2017/04/25;15:00:00
Invalid time format
bash: 15:00:00: command not foundconst char *s = "%d days, %d hours, %d minutes, %d seconds remaining...\n";
/* ... */
fprintf(stdout, s, days, hours, minutes);$ timeleft
1 days, 22 hours, 33 minutes, 142630783 seconds remaining...printf("%d days, %d hours, %d minutes, %d seconds remaining...\n",
days, hours, minutes);Context
StackExchange Code Review Q#161559, answer score: 15
Revisions (0)
No revisions yet.