HiveBrain v1.2.0
Get Started
← Back to all entries
patterncModerate

timeleft utility

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
utilitytimeleftstackoverflow

Problem

This utility tells you how much time is left until the time you set before.

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 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 found


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 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 found
const 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.