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 } 85