Merge from vendor branch NTPD:
[dragonfly.git] / lib / libc / stdlib / strtonum.c
1 /* $OpenBSD: strtonum.c,v 1.5 2004/07/16 18:36:05 otto Exp $ */
2 /* $DragonFly: src/lib/libc/stdlib/strtonum.c,v 1.1 2004/08/15 16:01:11 joerg Exp $ */
3 /*
4  * Copyright (c) 2004 Ted Unangst and Todd Miller
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdlib.h>
23
24 #define INVALID         1
25 #define TOOSMALL        2
26 #define TOOLARGE        3
27
28 static struct errval {
29         const char *errstr;
30         int err;
31 } ev[4] = {
32         { NULL,         0 },
33         { "invalid",    EINVAL },
34         { "too small",  ERANGE },
35         { "too large",  ERANGE },
36 };
37
38 unsigned long long
39 strtonum(const char *numstr, long long minval, unsigned long long umaxval,
40          const char **errstrp)
41 {
42         long long ll, maxval = (long long)umaxval;
43         unsigned long long ull = 0;
44         char *ep;
45         int error = 0;
46
47         ev[0].err = errno;
48         errno = 0;
49         if (umaxval > LLONG_MAX ) {
50                 if (minval < 0) {
51                         error = INVALID;
52                         goto done;
53                 }
54                 ull = strtoull(numstr, &ep, 10);
55                 if (numstr == ep || *ep != '\0')
56                         error = INVALID;
57                 else if ((ull == ULLONG_MAX && errno == ERANGE) ||
58                          ull > umaxval)
59                         error = TOOLARGE;
60                 else if (ull < minval)
61                         error = TOOSMALL;
62         } else {
63                 if (minval > maxval || maxval < minval) {
64                         error = INVALID;
65                         goto done;
66                 }
67                 ll = strtoll(numstr, &ep, 10);
68                 if (numstr == ep || *ep != '\0')
69                         error = INVALID;
70                 else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
71                         error = TOOSMALL;
72                 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
73                         error = TOOLARGE;
74                 ull = (unsigned long long)ll;
75         }
76 done:
77         if (errstrp != NULL)
78                 *errstrp = ev[error].errstr;
79         errno = ev[error].err;
80         if (error)
81                 ull = 0;
82
83         return(ull);
84 }