includes `strdup()` and `strndup()`
`strndup()` follows the latest standard, meaning that it copies at most _n_ chars, not _n_ + 1.
-also, no standard specifies that `strndup()` should return less than _n_ if `strlen(s) + 1` < _n_, but this implementation does so.
+Also, no standard specifies that `strndup()` should return less than _n_ if `strlen(s) + 1` < _n_, but this implementation does so.
---
### strlcat
includes `strlcat()` and `strlcpy()`
+
+---
+
+### strtonum
+
+includes `strtonum()`
--- /dev/null
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/* https://git.datadissipation.net */
+#ifndef STRTONUM_H_
+ #define STRTONUM_H_ 1
+
+ #ifdef STRTONUM_INCLUDE_LIBC
+ #include <errno.h>
+ #include <limits.h>
+ #include <stdlib.h>
+ #endif /* STRTONUM_INCLUDE_LIBC */
+
+ #ifndef HAVE_STRTONUM
+ #define strtonum i_strtonum_
+long long i_strtonum_(const char *numstr, long long minval, long long maxval,
+ const char **errstrp);
+ #endif /* !HAVE_STRTONUM */
+
+ #ifdef STRTONUM_IMPLEMENTATION
+ #define I_INVALID_ 1
+ #define I_TOOSMALL_ 2
+ #define I_TOOLARGE 3
+
+long long
+i_strtonum_(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ int error = 0;
+ char *ep;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval) {
+ error = I_INVALID_;
+ } else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = I_INVALID_;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = I_TOOSMALL_;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = I_TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
+ #endif /* STRTONUM_IMPLEMENTATION */
+#endif /* !STRTONUM_H_ */