HelenOS sources

root/uspace/app/date/date.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. main
  2. read_date_from_arg
  3. read_time_from_arg
  4. tm_sanity_check
  5. is_leap_year
  6. usage

/*
 * Copyright (c) 2012 Maurizio Lombardi
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <device/clock_dev.h>
#include <errno.h>
#include <loc.h>
#include <time.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <str.h>

#define NAME   "date"

static errno_t read_date_from_arg(char *wdate, struct tm *t);
static errno_t read_time_from_arg(char *wdate, struct tm *t);
static errno_t tm_sanity_check(struct tm *t);
static bool is_leap_year(int year);

static void usage(void);

static int days_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

int
main(int argc, char **argv)
{
        errno_t rc;
        int c;
        category_id_t cat_id;
        size_t        svc_cnt;
        service_id_t  *svc_ids = NULL;
        service_id_t  svc_id;
        char          *svc_name = NULL;
        bool          read_only = true;
        char          *wdate = NULL;
        char          *wtime = NULL;
        struct tm     t;
        int           n_args = argc;

        while ((c = getopt(argc, argv, "hd:t:")) != -1) {
                switch (c) {
                case 'h':
                        usage();
                        return 0;
                case 'd':
                        if (wdate) {
                                usage();
                                return 1;
                        }
                        wdate = (char *)optarg;
                        read_only = false;
                        n_args -= 2;
                        break;
                case 't':
                        if (wtime) {
                                usage();
                                return 1;
                        }
                        wtime = (char *)optarg;
                        read_only = false;
                        n_args -= 2;
                        break;
                case '?':
                        usage();
                        return 1;
                }
        }

        if (n_args != 1) {
                printf(NAME ": Unrecognized parameter\n");
                usage();
                return 1;
        }

        /* Get the id of the clock category */
        rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
        if (rc != EOK) {
                printf(NAME ": Cannot get clock category id\n");
                goto exit;
        }

        /* Get the list of available services in the clock category */
        rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
        if (rc != EOK) {
                printf(NAME ": Cannot get the list of services in the clock "
                    "category\n");
                goto exit;
        }

        /* Check if there are available services in the clock category */
        if (svc_cnt == 0) {
                printf(NAME ": No available service found in "
                    "the clock category\n");
                goto exit;
        }

        /* Get the name of the clock service */
        rc = loc_service_get_name(svc_ids[0], &svc_name);
        if (rc != EOK) {
                printf(NAME ": Cannot get the name of the service\n");
                goto exit;
        }

        /* Get the service id for the device */
        rc = loc_service_get_id(svc_name, &svc_id, 0);
        if (rc != EOK) {
                printf(NAME ": Cannot get the service id for device %s",
                    svc_name);
                goto exit;
        }

        /* Connect to the device */
        async_sess_t *sess = loc_service_connect(svc_id, INTERFACE_DDF, 0);
        if (!sess) {
                printf(NAME ": Cannot connect to the device\n");
                goto exit;
        }

        /* Read the current date/time */
        rc = clock_dev_time_get(sess, &t);
        if (rc != EOK) {
                printf(NAME ": Cannot read the current time\n");
                goto exit;
        }

        if (read_only) {
                /* Print the current time and exit */
                printf("%02d/%02d/%d ", t.tm_mday,
                    t.tm_mon + 1, 1900 + t.tm_year);
                printf("%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec);
        } else {
                if (wdate) {
                        rc = read_date_from_arg(wdate, &t);
                        if (rc != EOK) {
                                printf(NAME ": error, date format not "
                                    "recognized\n");
                                usage();
                                goto exit;
                        }
                }
                if (wtime) {
                        rc = read_time_from_arg(wtime, &t);
                        if (rc != EOK) {
                                printf(NAME ": error, time format not "
                                    "recognized\n");
                                usage();
                                goto exit;
                        }
                }

                rc = tm_sanity_check(&t);
                if (rc != EOK) {
                        printf(NAME ": error, invalid date/time\n");
                        goto exit;
                }

                rc = clock_dev_time_set(sess, &t);
                if (rc != EOK) {
                        printf(NAME ": error, Unable to set date/time\n");
                        goto exit;
                }
        }

exit:
        free(svc_name);
        free(svc_ids);
        return rc;
}

/** Read the day, month and year from a string
 *  with the following format: DD/MM/YYYY
 */
static errno_t
read_date_from_arg(char *wdate, struct tm *t)
{
        errno_t rc;
        uint32_t tmp;

        if (str_size(wdate) != 10) /* str_size("DD/MM/YYYY") == 10 */
                return EINVAL;

        if (wdate[2] != '/' ||
            wdate[5] != '/') {
                return EINVAL;
        }

        rc = str_uint32_t(&wdate[0], NULL, 10, false, &tmp);
        if (rc != EOK)
                return rc;

        t->tm_mday = tmp;

        rc = str_uint32_t(&wdate[3], NULL, 10, false, &tmp);
        if (rc != EOK)
                return rc;

        t->tm_mon = tmp - 1;

        rc = str_uint32_t(&wdate[6], NULL, 10, false, &tmp);
        t->tm_year = tmp - 1900;

        return rc;
}

/** Read the hours, minutes and seconds from a string
 *  with the following format: HH:MM:SS or HH:MM
 */
static errno_t
read_time_from_arg(char *wtime, struct tm *t)
{
        errno_t rc;
        size_t len = str_size(wtime);
        bool sec_present = len == 8;
        uint32_t tmp;

        /* str_size("HH:MM") == 5 */
        /* str_size("HH:MM:SS") == 8 */
        if (len != 8 && len != 5)
                return EINVAL;

        if (sec_present && wtime[5] != ':')
                return EINVAL;

        if (wtime[2] != ':')
                return EINVAL;

        rc = str_uint32_t(&wtime[0], NULL, 10, false, &tmp);
        if (rc != EOK)
                return rc;

        t->tm_hour = tmp;

        rc = str_uint32_t(&wtime[3], NULL, 10, false, &tmp);
        if (rc != EOK)
                return rc;

        t->tm_min = tmp;

        if (sec_present) {
                rc = str_uint32_t(&wtime[6], NULL, 10, false, &tmp);
                t->tm_sec = tmp;
        } else
                t->tm_sec = 0;

        return rc;
}

/** Check if the tm structure contains valid values
 *
 * @param t     The tm structure to check
 *
 * @return      EOK on success or EINVAL
 */
static errno_t
tm_sanity_check(struct tm *t)
{
        int ndays;

        if (t->tm_sec < 0 || t->tm_sec > 59)
                return EINVAL;
        else if (t->tm_min < 0 || t->tm_min > 59)
                return EINVAL;
        else if (t->tm_hour < 0 || t->tm_hour > 23)
                return EINVAL;
        else if (t->tm_mday < 1 || t->tm_mday > 31)
                return EINVAL;
        else if (t->tm_mon < 0 || t->tm_mon > 11)
                return EINVAL;
        else if (t->tm_year < 0 || t->tm_year > 199)
                return EINVAL;

        if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
                ndays = 29;
        else
                ndays = days_month[t->tm_mon];

        if (t->tm_mday > ndays)
                return EINVAL;

        return EOK;
}

/** Check if a year is a leap year
 *
 * @param year   The year to check
 *
 * @return       true if it is a leap year, false otherwise
 */
static bool
is_leap_year(int year)
{
        bool r = false;

        if (year % 4 == 0) {
                if (year % 100 == 0)
                        r = year % 400 == 0;
                else
                        r = true;
        }

        return r;
}

static void
usage(void)
{
        printf("Usage: date [-d DD/MM/YYYY] [-t HH:MM[:SS]]\n");
        printf("       -d   Change the current date\n");
        printf("       -t   Change the current time\n");
        printf("       -h   Display this information\n");
}

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub