diff options
-rw-r--r-- | usr.bin/dig/dig.c | 121 | ||||
-rw-r--r-- | usr.bin/dig/dig.h | 8 | ||||
-rw-r--r-- | usr.bin/dig/dighost.c | 67 | ||||
-rw-r--r-- | usr.bin/dig/lib/isc/Makefile.inc | 4 | ||||
-rw-r--r-- | usr.bin/dig/lib/isc/include/isc/parseint.h | 53 | ||||
-rw-r--r-- | usr.bin/dig/lib/isc/lex.c | 4 | ||||
-rw-r--r-- | usr.bin/dig/lib/isc/parseint.c | 50 | ||||
-rw-r--r-- | usr.bin/dig/nslookup.c | 32 |
8 files changed, 108 insertions, 231 deletions
diff --git a/usr.bin/dig/dig.c b/usr.bin/dig/dig.c index edcca689ee9..a9df70f46ea 100644 --- a/usr.bin/dig/dig.c +++ b/usr.bin/dig/dig.c @@ -14,11 +14,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.c,v 1.12 2020/02/24 13:49:38 jsg Exp $ */ +/* $Id: dig.c,v 1.13 2020/09/13 09:33:39 florian Exp $ */ /*! \file */ #include <sys/cdefs.h> +#include <errno.h> #include <stdlib.h> #include <time.h> #include <unistd.h> @@ -633,7 +634,9 @@ plus_option(const char *option, isc_boolean_t is_batchfile, { isc_result_t result; char option_store[256]; - char *cmd, *value, *ptr, *code; + char *cmd, *value, *ptr, *code, *ep; + const char *errstr; + long lval; uint32_t num; isc_boolean_t state = ISC_TRUE; size_t n; @@ -721,10 +724,9 @@ plus_option(const char *option, isc_boolean_t is_batchfile, goto need_value; if (!state) goto invalid_option; - result = parse_uint(&num, value, COMMSIZE, - "buffer size"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse buffer size"); + num = strtonum(value, 0, COMMSIZE, &errstr); + if (errstr != NULL) + fatal("buffer size is %s: '%s'", errstr, value); lookup->udpsize = num; break; default: @@ -820,13 +822,12 @@ plus_option(const char *option, isc_boolean_t is_batchfile, lookup->edns = 0; break; } - result = parse_uint(&num, - value, - 255, - "edns"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse " - "edns"); + num = strtonum(value, 0, 255, + &errstr); + if (errstr != NULL) + fatal("edns is %s: " + "'%s'", errstr, + value); lookup->edns = num; break; case 'f': @@ -839,14 +840,14 @@ plus_option(const char *option, isc_boolean_t is_batchfile, lookup->ednsflags = 0; break; } - result = parse_xint(&num, - value, - 0xffff, - "ednsflags"); - if (result != ISC_R_SUCCESS) + errno = 0; + lval = strtol(value, &ep, 0); + if (value[0] == '\0' || *ep != + '\0' || lval < 0 || lval > + 0xffff || errno != 0) fatal("Couldn't parse " "ednsflags"); - lookup->ednsflags = num; + lookup->ednsflags = lval; break; case 'n': FULLCHECK("ednsnegotiation"); @@ -929,9 +930,9 @@ plus_option(const char *option, isc_boolean_t is_batchfile, goto need_value; if (!state) goto invalid_option; - result = parse_uint(&num, value, MAXNDOTS, "ndots"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse ndots"); + num = strtonum(value, 0, MAXNDOTS, &errstr); + if (errstr != NULL) + fatal("ndots is %s: '%s'", errstr, value); ndots = num; break; case 's': @@ -992,9 +993,9 @@ plus_option(const char *option, isc_boolean_t is_batchfile, lookup->opcode = (dns_opcode_t)num; break; } - result = parse_uint(&num, value, 15, "opcode"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse opcode"); + num = strtonum(value, 0, 15, &errstr); + if (errstr != NULL) + fatal("opcode is %s: '%s'", errstr, value); lookup->opcode = (dns_opcode_t)num; break; default: @@ -1035,10 +1036,11 @@ plus_option(const char *option, isc_boolean_t is_batchfile, goto need_value; if (!state) goto invalid_option; - result = parse_uint(&lookup->retries, value, - MAXTRIES - 1, "retries"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse retries"); + lookup->retries = strtonum(value, 0, + MAXTRIES - 1, &errstr); + if (errstr != NULL) + fatal("retries is %s: '%s'", errstr, + value); lookup->retries++; break; default: @@ -1121,8 +1123,9 @@ plus_option(const char *option, isc_boolean_t is_batchfile, } else if (value == NULL) break; - result = parse_uint(&splitwidth, value, - 1023, "split"); + splitwidth = strtonum(value, 0, 1023, &errstr); + if (errstr != NULL) + fatal("split is %s: '%s'", errstr, value); if ((splitwidth % 4) != 0U) { splitwidth = ((splitwidth + 3) / 4) * 4; fprintf(stderr, ";; Warning, split must be " @@ -1138,8 +1141,6 @@ plus_option(const char *option, isc_boolean_t is_batchfile, */ if (splitwidth) splitwidth += 3; - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse split"); break; case 't': /* stats */ FULLCHECK("stats"); @@ -1185,10 +1186,9 @@ plus_option(const char *option, isc_boolean_t is_batchfile, goto need_value; if (!state) goto invalid_option; - result = parse_uint(&timeout, value, MAXTIMEOUT, - "timeout"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse timeout"); + timeout = strtonum(value, 0, MAXTIMEOUT, &errstr); + if (errstr != NULL) + fatal("timeout is %s: '%s'", errstr, value); if (timeout == 0) timeout = 1; break; @@ -1217,10 +1217,11 @@ plus_option(const char *option, isc_boolean_t is_batchfile, goto need_value; if (!state) goto invalid_option; - result = parse_uint(&lookup->retries, value, - MAXTRIES, "tries"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse tries"); + lookup->retries = strtonum(value, 0, MAXTRIES, + &errstr); + if (errstr != NULL) + fatal("tries is %s: '%s'", errstr, + value); if (lookup->retries == 0) lookup->retries = 1; break; @@ -1276,6 +1277,7 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, in_port_t srcport; char *hash, *cmd; uint32_t num; + const char *errstr; while (strpbrk(option, single_dash_opts) == &option[0]) { /* @@ -1352,10 +1354,10 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, case 'b': hash = strchr(value, '#'); if (hash != NULL) { - result = parse_uint(&num, hash + 1, MAXPORT, - "port number"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse port number"); + num = strtonum(hash + 1, 0, MAXPORT, &errstr); + if (errstr != NULL) + fatal("port number is %s: '%s'", errstr, + hash + 1); srcport = num; *hash = '\0'; } else @@ -1399,9 +1401,9 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, strlcpy(keyfile, value, sizeof(keyfile)); return (value_from_next); case 'p': - result = parse_uint(&num, value, MAXPORT, "port number"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse port number"); + num = strtonum(value, 0, MAXPORT, &errstr); + if (errstr != NULL) + fatal("port number is %s: '%s'", errstr, value); port = num; return (value_from_next); case 'q': @@ -1447,10 +1449,11 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, uint32_t serial; (*lookup)->rdtype = dns_rdatatype_ixfr; (*lookup)->rdtypeset = ISC_TRUE; - result = parse_uint(&serial, &value[5], - MAXSERIAL, "serial number"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse serial number"); + serial = strtonum(&value[5], 0, MAXSERIAL, + &errstr); + if (errstr != NULL) + fatal("serial number is %s: '%s'", + errstr, &value[5]); (*lookup)->ixfr_serial = serial; (*lookup)->section_question = plusquest; (*lookup)->comments = pluscomm; @@ -1585,6 +1588,7 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, char *input; int i; isc_boolean_t need_clone = ISC_TRUE; + const char *errstr; /* * The semantics for parsing the args is a bit complex; if @@ -1690,13 +1694,12 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, lookup->rdtype = dns_rdatatype_ixfr; lookup->rdtypeset = ISC_TRUE; - result = parse_uint(&serial, - &rv[0][5], - MAXSERIAL, - "serial number"); - if (result != ISC_R_SUCCESS) - fatal("Couldn't parse " - "serial number"); + serial = strtonum(&rv[0][5], 0, + MAXSERIAL, &errstr); + if (errstr != NULL) + fatal("serial number " + "is %s: '%s'", + errstr, &rv[0][5]); lookup->ixfr_serial = serial; lookup->section_question = plusquest; diff --git a/usr.bin/dig/dig.h b/usr.bin/dig/dig.h index e47fdd9e563..6e19df3853f 100644 --- a/usr.bin/dig/dig.h +++ b/usr.bin/dig/dig.h @@ -298,14 +298,6 @@ void setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only); isc_result_t -parse_uint(uint32_t *uip, const char *value, uint32_t max, - const char *desc); - -isc_result_t -parse_xint(uint32_t *uip, const char *value, uint32_t max, - const char *desc); - -isc_result_t parse_netprefix(isc_sockaddr_t **sap, const char *value); void diff --git a/usr.bin/dig/dighost.c b/usr.bin/dig/dighost.c index c7366abd88b..4bffe54aebd 100644 --- a/usr.bin/dig/dighost.c +++ b/usr.bin/dig/dighost.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dighost.c,v 1.25 2020/02/25 18:10:17 florian Exp $ */ +/* $Id: dighost.c,v 1.26 2020/09/13 09:33:39 florian Exp $ */ /*! \file * \note @@ -56,7 +56,6 @@ #include <isc/hex.h> #include <isc/log.h> #include <isc/netaddr.h> -#include <isc/parseint.h> #include <isc/result.h> #include <isc/serial.h> #include <isc/sockaddr.h> @@ -911,49 +910,20 @@ setup_text_key(void) { isc_buffer_free(&namebuf); } -static isc_result_t -parse_uint_helper(uint32_t *uip, const char *value, uint32_t max, - const char *desc, int base) { - uint32_t n; - isc_result_t result = isc_parse_uint32(&n, value, base); - if (result == ISC_R_SUCCESS && n > max) - result = ISC_R_RANGE; - if (result != ISC_R_SUCCESS) { - printf("invalid %s '%s': %s\n", desc, - value, isc_result_totext(result)); - return (result); - } - *uip = n; - return (ISC_R_SUCCESS); -} - -isc_result_t -parse_uint(uint32_t *uip, const char *value, uint32_t max, - const char *desc) { - return (parse_uint_helper(uip, value, max, desc, 10)); -} - -isc_result_t -parse_xint(uint32_t *uip, const char *value, uint32_t max, - const char *desc) { - return (parse_uint_helper(uip, value, max, desc, 0)); -} - static uint32_t -parse_bits(char *arg, const char *desc, uint32_t max) { - isc_result_t result; +parse_bits(char *arg, uint32_t max) { uint32_t tmp; + const char *errstr; - result = parse_uint(&tmp, arg, max, desc); - if (result != ISC_R_SUCCESS) - fatal("couldn't parse digest bits"); + tmp = strtonum(arg, 0, max, &errstr); + if (errstr != NULL) + fatal("digest bits is %s: '%s'", errstr, arg); tmp = (tmp + 7) & ~0x7U; return (tmp); } isc_result_t parse_netprefix(isc_sockaddr_t **sap, const char *value) { - isc_result_t result = ISC_R_SUCCESS; isc_sockaddr_t *sa = NULL; struct in_addr in4; struct in6_addr in6; @@ -962,6 +932,7 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) { isc_boolean_t parsed = ISC_FALSE; isc_boolean_t prefix_parsed = ISC_FALSE; char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")]; + const char *errstr; REQUIRE(sap != NULL && *sap == NULL); @@ -982,10 +953,9 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) { slash = strchr(buf, '/'); if (slash != NULL) { *slash = '\0'; - result = isc_parse_uint32(&prefix_length, slash + 1, 10); - if (result != ISC_R_SUCCESS) { - fatal("invalid prefix length in '%s': %s\n", - value, isc_result_totext(result)); + prefix_length = strtonum(slash + 1, 0, 10, &errstr); + if (errstr != NULL) { + fatal("prefix length is %s: '%s'", errstr, value); } prefix_parsed = ISC_TRUE; } @@ -1048,27 +1018,27 @@ parse_hmac(const char *hmac) { digestbits = 0; } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { hmacname = DNS_TSIG_HMACSHA1_NAME; - digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160); + digestbits = parse_bits(&buf[10], 160); } else if (strcasecmp(buf, "hmac-sha224") == 0) { hmacname = DNS_TSIG_HMACSHA224_NAME; } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { hmacname = DNS_TSIG_HMACSHA224_NAME; - digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224); + digestbits = parse_bits(&buf[12], 224); } else if (strcasecmp(buf, "hmac-sha256") == 0) { hmacname = DNS_TSIG_HMACSHA256_NAME; } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { hmacname = DNS_TSIG_HMACSHA256_NAME; - digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256); + digestbits = parse_bits(&buf[12], 256); } else if (strcasecmp(buf, "hmac-sha384") == 0) { hmacname = DNS_TSIG_HMACSHA384_NAME; } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { hmacname = DNS_TSIG_HMACSHA384_NAME; - digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384); + digestbits = parse_bits(&buf[12], 384); } else if (strcasecmp(buf, "hmac-sha512") == 0) { hmacname = DNS_TSIG_HMACSHA512_NAME; } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { hmacname = DNS_TSIG_HMACSHA512_NAME; - digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512); + digestbits = parse_bits(&buf[12], 512); } else { fprintf(stderr, ";; Warning, ignoring " "invalid TSIG algorithm %s\n", buf); @@ -1346,6 +1316,7 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) { isc_buffer_t b; isc_boolean_t found = ISC_FALSE; unsigned int i; + const char *errstr; if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS) fatal("too many ednsopts"); @@ -1359,9 +1330,9 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) { } if (!found) { - result = parse_uint(&num, code, 65535, "ednsopt"); - if (result != ISC_R_SUCCESS) - fatal("bad edns code point: %s", code); + num = strtonum(code, 0, 65535, &errstr); + if (errstr != NULL) + fatal("edns code point is %s: '%s'", errstr, code); } if (lookup->ednsopts == NULL) { diff --git a/usr.bin/dig/lib/isc/Makefile.inc b/usr.bin/dig/lib/isc/Makefile.inc index 41240e1a80d..568a648f9ab 100644 --- a/usr.bin/dig/lib/isc/Makefile.inc +++ b/usr.bin/dig/lib/isc/Makefile.inc @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile.inc,v 1.6 2020/02/25 18:10:17 florian Exp $ +# $OpenBSD: Makefile.inc,v 1.7 2020/09/13 09:33:39 florian Exp $ .PATH: ${.CURDIR}/lib/isc SRCS+= assertions.c base32.c base64.c netaddr.c buffer.c bufferlist.c SRCS+= error.c event.c hash.c heap.c hex.c hmacsha.c SRCS+= lex.c log.c regex.c sockaddr.c -SRCS+= task.c result.c parseint.c refcount.c timer.c +SRCS+= task.c result.c refcount.c timer.c SRCS+= serial.c sha1.c sha2.c symtab.c diff --git a/usr.bin/dig/lib/isc/include/isc/parseint.h b/usr.bin/dig/lib/isc/include/isc/parseint.h deleted file mode 100644 index f6651cbcb12..00000000000 --- a/usr.bin/dig/lib/isc/include/isc/parseint.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or 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. - */ - -/* $Id: parseint.h,v 1.4 2020/02/22 19:47:07 jung Exp $ */ - -#ifndef ISC_PARSEINT_H -#define ISC_PARSEINT_H 1 - -#include <isc/types.h> - -/*! \file isc/parseint.h - * \brief Parse integers, in a saner way than atoi() or strtoul() do. - */ - -/*** - *** Functions - ***/ - -isc_result_t -isc_parse_uint32(uint32_t *uip, const char *string, int base); - -/*%< - * Parse the null-terminated string 'string' containing a base 'base' - * integer, storing the result in '*uip'. - * The base is interpreted - * as in strtoul(). Unlike strtoul(), leading whitespace, minus or - * plus signs are not accepted, and all errors (including overflow) - * are reported uniformly through the return value. - * - * Requires: - *\li 'string' points to a null-terminated string - *\li 0 <= 'base' <= 36 - * - * Returns: - *\li #ISC_R_SUCCESS - *\li #ISC_R_BADNUMBER The string is not numeric (in the given base) - *\li #ISC_R_RANGE The number is not representable as the requested type. - */ - -#endif /* ISC_PARSEINT_H */ diff --git a/usr.bin/dig/lib/isc/lex.c b/usr.bin/dig/lib/isc/lex.c index 86371ddbd24..4fc0e3f8422 100644 --- a/usr.bin/dig/lib/isc/lex.c +++ b/usr.bin/dig/lib/isc/lex.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lex.c,v 1.10 2020/09/13 09:32:02 florian Exp $ */ +/* $Id: lex.c,v 1.11 2020/09/13 09:33:39 florian Exp $ */ /*! \file */ @@ -25,8 +25,6 @@ #include <isc/lex.h> -#include <isc/parseint.h> - #include <errno.h> #include <string.h> #include <isc/util.h> diff --git a/usr.bin/dig/lib/isc/parseint.c b/usr.bin/dig/lib/isc/parseint.c deleted file mode 100644 index dd00f7289cf..00000000000 --- a/usr.bin/dig/lib/isc/parseint.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or 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. - */ - -/* $Id: parseint.c,v 1.4 2020/02/25 05:00:43 jsg Exp $ */ - -/*! \file */ - -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdlib.h> - -#include <isc/parseint.h> -#include <isc/result.h> - -isc_result_t -isc_parse_uint32(uint32_t *uip, const char *string, int base) { - unsigned long n; - uint32_t r; - char *e; - if (! isalnum((unsigned char)(string[0]))) - return (ISC_R_BADNUMBER); - errno = 0; - n = strtoul(string, &e, base); - if (*e != '\0') - return (ISC_R_BADNUMBER); - /* - * Where long is 64 bits we need to convert to 32 bits then test for - * equality. This is a no-op on 32 bit machines and a good compiler - * will optimise it away. - */ - r = (uint32_t)n; - if ((n == ULONG_MAX && errno == ERANGE) || (n != (unsigned long)r)) - return (ISC_R_RANGE); - *uip = r; - return (ISC_R_SUCCESS); -} diff --git a/usr.bin/dig/nslookup.c b/usr.bin/dig/nslookup.c index 76b7abfe215..2776fc585ae 100644 --- a/usr.bin/dig/nslookup.c +++ b/usr.bin/dig/nslookup.c @@ -522,33 +522,49 @@ testclass(char *typetext) { static void set_port(const char *value) { uint32_t n; - isc_result_t result = parse_uint(&n, value, 65535, "port"); - if (result == ISC_R_SUCCESS) + const char *errstr; + + n = strtonum(value, 0, 65535, &errstr); + if (errstr == NULL) port = (uint16_t) n; + else + printf("port is %s: '%s'\n", errstr, value); } static void set_timeout(const char *value) { uint32_t n; - isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); - if (result == ISC_R_SUCCESS) + const char *errstr; + + n = strtonum(value, 0, UINT_MAX, &errstr); + if (errstr == NULL) timeout = n; + else + printf("timeout is %s: '%s'\n", errstr, value); } static void set_tries(const char *value) { uint32_t n; - isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); - if (result == ISC_R_SUCCESS) + const char *errstr; + + n = strtonum(value, 0, INT_MAX, &errstr); + if (errstr == NULL) tries = n; + else + printf("tries is %s: '%s'\n", errstr, value); } static void set_ndots(const char *value) { uint32_t n; - isc_result_t result = parse_uint(&n, value, 128, "ndots"); - if (result == ISC_R_SUCCESS) + const char *errstr; + + n = strtonum(value, 0, 128, &errstr); + if (errstr == NULL) ndots = n; + else + printf("ndots is %s: '%s'\n", errstr, value); } static void |