root/src/system/libnetwork/netresolv/nameser/ns_ttl.c
/*      $NetBSD: ns_ttl.c,v 1.8 2012/03/13 21:13:39 christos Exp $      */

/*
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
 * Copyright (c) 1996,1999 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/cdefs.h>
#ifndef lint
#ifdef notdef
static const char rcsid[] = "Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp";
#else
//__RCSID("$NetBSD: ns_ttl.c,v 1.8 2012/03/13 21:13:39 christos Exp $");
#endif
#endif

/* Import. */

#include "port_before.h"

#include <arpa/nameser.h>

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

#include "port_after.h"

#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif

/* Forward. */

static int      fmt1(int t, char s, char **buf, size_t *buflen);

/* Macros. */

#define T(x) if ((x) < 0) return (-1)

/* Public. */

int
ns_format_ttl(u_long src, char *dst, size_t dstlen) {
        char *odst = dst;
        int secs, mins, hours, days, weeks, x;
        char *p;

        secs = (int)(src % 60);   src /= 60;
        mins = (int)(src % 60);   src /= 60;
        hours = (int)(src % 24);  src /= 24;
        days = (int)(src % 7);    src /= 7;
        weeks = (int)src;       src = 0;

        x = 0;
        if (weeks) {
                T(fmt1(weeks, 'W', &dst, &dstlen));
                x++;
        }
        if (days) {
                T(fmt1(days, 'D', &dst, &dstlen));
                x++;
        }
        if (hours) {
                T(fmt1(hours, 'H', &dst, &dstlen));
                x++;
        }
        if (mins) {
                T(fmt1(mins, 'M', &dst, &dstlen));
                x++;
        }
        if (secs || !(weeks || days || hours || mins)) {
                T(fmt1(secs, 'S', &dst, &dstlen));
                x++;
        }

        if (x > 1) {
                int ch;

                for (p = odst; (ch = *p) != '\0'; p++)
                        if (isascii(ch) && isupper(ch))
                                *p = tolower(ch);
        }

        assert(INT_MIN <= (dst - odst) && (dst - odst) <= INT_MAX);
        return (int)(dst - odst);
}

#ifndef _LIBC
int
ns_parse_ttl(const char *src, u_long *dst) {
        u_long ttl, tmp;
        int ch, digits, dirty;

        ttl = 0;
        tmp = 0;
        digits = 0;
        dirty = 0;
        while ((ch = *src++) != '\0') {
                if (!isascii(ch) || !isprint(ch))
                        goto einval;
                if (isdigit(ch)) {
                        tmp *= 10;
                        tmp += (ch - '0');
                        digits++;
                        continue;
                }
                if (digits == 0)
                        goto einval;
                if (islower(ch))
                        ch = toupper(ch);
                switch (ch) {
                case 'W':  tmp *= 7;    /*FALLTHROUGH*/
                case 'D':  tmp *= 24;   /*FALLTHROUGH*/
                case 'H':  tmp *= 60;   /*FALLTHROUGH*/
                case 'M':  tmp *= 60;   /*FALLTHROUGH*/
                case 'S':  break;
                default:   goto einval;
                }
                ttl += tmp;
                tmp = 0;
                digits = 0;
                dirty = 1;
        }
        if (digits > 0) {
                if (dirty)
                        goto einval;
                else
                        ttl += tmp;
        } else if (!dirty)
                goto einval;
        *dst = ttl;
        return (0);

 einval:
        errno = EINVAL;
        return (-1);
}
#endif

/* Private. */

static int
fmt1(int t, char s, char **buf, size_t *buflen) {
        char tmp[50];
        size_t len;

        len = SPRINTF((tmp, "%d%c", t, s));
        if (len + 1 > *buflen)
                return (-1);
        strcpy(*buf, tmp);
        *buf += len;
        *buflen -= len;
        return (0);
}

/*! \file */