BIND 10 trac1324, updated. f9e81512329b71d6b5d94bafa789c63e763b2a72 [1324] Changed PROGNAME to static char * Build program modules as C files Removed malloc.h

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Nov 18 01:35:05 UTC 2011


The branch, trac1324 has been updated
       via  f9e81512329b71d6b5d94bafa789c63e763b2a72 (commit)
      from  a4c51111cc0fc28c6517a11f8ae88682ab8e6996 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f9e81512329b71d6b5d94bafa789c63e763b2a72
Author: John DuBois <johnd at isc.org>
Date:   Thu Nov 17 17:17:58 2011 -0800

    [1324]
    Changed PROGNAME to static char *
    Build program modules as C files
    Removed malloc.h

-----------------------------------------------------------------------

Summary of changes:
 tests/tools/perfdhcp/{cloptions.cc => cloptions.c} |    1 +
 tests/tools/perfdhcp/cloptions.h                   |    8 ++++++++
 tests/tools/perfdhcp/{dkdebug.cc => dkdebug.c}     |    0 
 tests/tools/perfdhcp/perfdhcp.h                    |    2 --
 tests/tools/perfdhcp/{procconf.cc => procconf.c}   |    3 +--
 tests/tools/perfdhcp/procconf.h                    |    8 ++++++++
 tests/tools/perfdhcp/tests/Makefile.am             |    6 +++---
 7 files changed, 21 insertions(+), 7 deletions(-)
 rename tests/tools/perfdhcp/{cloptions.cc => cloptions.c} (99%)
 rename tests/tools/perfdhcp/{dkdebug.cc => dkdebug.c} (100%)
 rename tests/tools/perfdhcp/{procconf.cc => procconf.c} (99%)

-----------------------------------------------------------------------
diff --git a/tests/tools/perfdhcp/cloptions.c b/tests/tools/perfdhcp/cloptions.c
new file mode 100644
index 0000000..cfc9acd
--- /dev/null
+++ b/tests/tools/perfdhcp/cloptions.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2011  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.
+ */
+
+#include <stdio.h>
+#include "procconf.h"
+#include "perfdhcp.h"
+#include "cloptions.h"
+#include "dkdebug.h"
+
+static void printHelp(const char* progName, const char* usage);
+static void initialize(void);
+
+// The current version information
+const char* VERSION = "perfdhcp v1.0 2011-10-30";
+static const char* PROGNAME = "perfdhcp";
+
+static int v6 = 0;                      // DHCPv6 operation (-6)
+static int initialOnly = 0;             // Do only initial exchange (-i)
+static unsigned rate = 0;               // Request rate (-r)
+static unsigned numRequest = 0;         // Number of requests (-n)
+static double dropTime = 0.0;           // Response timeout (-d)
+static double testPeriod = 0.0;         // Test period (-p)
+static const char* server = NULL;       // Server to contact
+static const char* maxDropOpt = NULL;   // Max dropped responses (-D)
+static const char* localName = NULL;    // Local host/interface (-l)
+
+/*
+ * Return value:
+ * 0 if the command has been satisfied and the program should exit 0.
+ * 2 for usage error, in which case an error message will have been printed.
+ * 1 if argument processing was successful and the program should continue.
+ */
+int
+procArgs(int argc, const char* argv[]) {
+    char usage[] =
+        "Usage:\n\
+perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
+         [-d<drop-time>] [-D<max-drop>] [-l<local-addr|interface>] [-i]\n\
+         [-x<diagnostic-selector>] [server]\n";
+    int v4 = 0;                 /* DHCPv4 operation explicitly requested */
+    const char* msg;            /* Failure message from procOpts() */
+    int help = 0;               /* Help requested */
+    int versionReq = 0;         /* Version requested */
+    const char* diagStr = NULL; /* Diagnostics requested (-x) */
+
+    /* option descriptions */
+    confvar_t optConf[] = {
+        { 'h', NULL,        CF_SWITCH,    &help,        1 },
+        { 'v', NULL,        CF_SWITCH,    &versionReq,  1 },
+        { '4', NULL,        CF_SWITCH,    &v4,          1 },
+        { '6', NULL,        CF_SWITCH,    &v6,          1 },
+        { 'i', NULL,        CF_SWITCH,    &initialOnly, 1 },
+        { 'l', NULL,        CF_NE_STRING, &localName,   0 },
+        { 'r', NULL,        CF_POS_INT,   &rate,        0 },
+        { 'n', NULL,        CF_POS_INT,   &numRequest,  0 },
+        { 'd', NULL,        CF_POS_FLOAT, &dropTime,    0 },
+        { 'p', NULL,        CF_POS_FLOAT, &testPeriod,  0 },
+        { 'D', NULL,        CF_NE_STRING, &maxDropOpt,  0 },
+        { 'x', NULL,        CF_STRING,    &diagStr,     0 },
+        { '\0', NULL,       CF_ENDLIST,   NULL,         0 }
+    };
+
+    /* diagnostic map */
+    const struct dkdesc diagLetters[] = {
+        { 's', DK_SOCK },
+        { 'm', DK_MSG },
+        { 'p', DK_PACKET },
+        { 'a', DK_ALL },
+        { '\0', 0 }
+    };
+
+    initialize();
+    /* Process command line options */
+    msg = procOpts(&argc, &argv, optConf, NULL, PROGNAME, NULL);
+    if (msg != NULL) {
+        fprintf(stderr, "%s: %s\n", PROGNAME, msg);
+        return(2);
+    }
+
+    if (help) {
+        printHelp(PROGNAME, usage);
+        return(0);
+    }
+    if (versionReq) {
+        printf("%s\n", VERSION);
+        return(0);
+    }
+    if (diagStr != NULL) {
+        char c;
+        if ((c = dk_setup(diagStr, diagLetters)) != '\0') {
+            fprintf(stderr,
+                    "%s: Invalid selector character given with -x: '%c'\n",
+                    PROGNAME, c);
+            return(2);
+        }
+    }
+
+    if (v4 && v6) {
+        fprintf(stderr, "%s: Must not give -4 and -6 together.\n", PROGNAME);
+        return(2);
+    }
+    switch (argc) {
+    case 0:
+        if (v6 && localName != NULL) {
+            server = "all";
+        } else {
+            if (v6) {
+                fprintf(stderr,
+                        "%s: Use -l to specify an interface name.\n\%s\n",
+                        PROGNAME, usage);
+            }
+            else {
+                fprintf(stderr, "%s: Must specify a DHCP server.\n\%s\n",
+                        PROGNAME, usage);
+            }
+            return(2);
+        }
+        break;
+    case 1:
+        server = argv[0];
+        break;
+    default:
+        fprintf(stderr, "%s: Too many arguments.\n\%s\n", PROGNAME, usage);
+        return(2);
+    }
+    return(1);
+}
+
+/*
+ * Initialize values set by procArgs().
+ * Initialized though they are static to allow for repeated calls for testing.
+ */
+static void
+initialize(void) {
+    v6 = 0;
+    initialOnly = 0;
+    rate = 0;
+    numRequest = 0;
+    dropTime = 0.0;
+    testPeriod = 0.0;
+    maxDropOpt = NULL;
+    localName = NULL;
+    server = NULL;
+}
+
+static void
+printHelp(const char* progName, const char* usage) {
+    printf(
+        "%s: Execute a performance test against a DHCP server.\n\
+%s\n\
+The [server] argument is the name/address of the DHCP server to contact. \n\
+For DHCPv4 operation, exchanges are initiated by transmitting a DHCP\n\
+DISCOVER to this address.  For DHCPv6 operation, exchanges are initiated\n\
+by transmitting a DHCP SOLICIT to this address.  In the DHCPv6 case, the\n\
+special name \"all\" can be used to refer to\n\
+All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2), or\n\
+the special name \"servers\" to refer to All_DHCP_Servers (the multicast\n\
+address FF05::1:3).  The [server] argument is optional only in the case\n\
+that -l is used to specify an interface, in which case [server] defaults\n\
+to \"all\".\n\
+\n\
+Exchanges are initiated by transmitting a DHCP SOLICIT to\n\
+All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2) via\n\
+this interface.\n\
+\n\
+The default is to perform a single 4-way exchange, effectively pinging the\n\
+server.  The -r option is used to set up a performance test.\n\
+\n\
+Options:\n\
+-4: DHCPv4 operation (default). This is incompatible with the -6 option.\n\
+-6: DHCPv6 operation. This is incompatible with the -4 option.\n\
+-h: Print this help.\n\
+-i: Do only the initial part of an exchange: DO or SA, depending on\n\
+    whether -6 is given.\n\
+-l<local-addr|interface>: For DHCPv4 operation, specify the local\n\
+    hostname/address to use when communicating with the server.  By\n\
+    default, the interface address through which traffic would normally be\n\
+    routed to the server is used.\n\
+    For DHCPv6 operation, specify the name of the network interface via\n\
+    which exchanges are initiated.  This must be specified unless a server\n\
+    name is given, in which case the interface through which traffic would\n\
+    normally be routed to the server is used.\n\
+-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA) exchanges per\n\
+    second.  A periodic report is generated showing the number of exchanges\n\
+    which were not completed, as well as the average response latency.  The\n\
+    program continues until interrupted, at which point a final report is\n\
+    generated.\n\
+-v: Report the version number of this program.\n\
+-x<diagnostic-selector>: Include extended diagnostics in the output.\n\
+    <diagnostic-selector> is a string of characters, each specifying an\n\
+    operation for which verbose output is desired.  The selector characters\n\
+    are:\n\
+    [TO BE ADDED]\n\
+\n\
+The remaining options are used only in conjunction with -r:\n\
+\n\
+-d<drop-time>: Specify the time after which a request is treated as having\n\
+    been lost.  The value is given in seconds and may contain a fractional\n\
+    component.  The default is 1 second.\n\
+-D<max-drop>: Abort the test if more than <max-drop> requests have been\n\
+    dropped.  Use -D0 to abort if even a single request has been dropped. \n\
+    If <max-drop> includes the suffix \"%%\", it specifies a maximum\n\
+    percentage of requests that may be dropped before abort.  In this\n\
+    case, testing of the threshold begins after 10 requests have been\n\
+    expected to be received.\n\
+-n<num-request>: Initiate <num-request> transactions.  No report is\n\
+    generated until all transactions have been initiated/waited-for, after\n\
+    which a report is generated and the program terminates.\n\
+-p<test-period>: Send requests for the given test period, which is\n\
+    specified in the same manner as -d.  This can be used as an\n\
+    alternative to -n, or both options can be given, in which case the\n\
+    testing is completed when either limit is reached.\n\
+\n\
+Exit status:\n\
+The exit status is:\n\
+0 on complete success.\n\
+1 for a general error.\n\
+2 if an error is found in the command line arguments.\n\
+3 if there are no general failures in operation, but one or more exchanges\n\
+  are not successfully completed.\n",
+        progName, usage);
+}
+
+int
+isV6(void) {
+    return v6;
+}
+
+int
+getInitialOnly(void) {
+    return initialOnly;
+}
+
+unsigned
+getRate(void) {
+    return rate;
+}
+
+unsigned
+getNumRequest(void) {
+    return numRequest;
+}
+
+double
+getDropTime(void) {
+    return dropTime;
+}
+
+double
+getTestPeriod(void) {
+    return testPeriod;
+}
+
+const char *
+getServer(void) {
+    return server;
+}
+
+const char *
+getLocalName(void) {
+    return localName;
+}
+
+const char *
+getMaxDrop(void) {
+    return maxDropOpt;
+}
diff --git a/tests/tools/perfdhcp/cloptions.cc b/tests/tools/perfdhcp/cloptions.cc
deleted file mode 100644
index 46346f0..0000000
--- a/tests/tools/perfdhcp/cloptions.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2011  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.
- */
-
-#include <stdio.h>
-#include "procconf.h"
-#include "perfdhcp.h"
-#include "cloptions.h"
-#include "dkdebug.h"
-
-static void printHelp(const char* progName, const char* usage);
-static void initialize(void);
-
-// The current version information
-const char* VERSION = "perfdhcp v1.0 2011-10-30";
-
-static int v6 = 0;                      // DHCPv6 operation (-6)
-static int initialOnly = 0;             // Do only initial exchange (-i)
-static unsigned rate = 0;               // Request rate (-r)
-static unsigned numRequest = 0;         // Number of requests (-n)
-static double dropTime = 0.0;           // Response timeout (-d)
-static double testPeriod = 0.0;         // Test period (-p)
-static const char* server = NULL;       // Server to contact
-static const char* maxDropOpt = NULL;   // Max dropped responses (-D)
-static const char* localName = NULL;    // Local host/interface (-l)
-
-/*
- * Return value:
- * 0 if the command has been satisfied and the program should exit 0.
- * 2 for usage error, in which case an error message will have been printed.
- * 1 if argument processing was successful and the program should continue.
- */
-int
-procArgs(int argc, const char* argv[]) {
-    char usage[] =
-        "Usage:\n\
-perfdhcp [-hv] [-4|-6] [-r<rate>] [-n<num-request>] [-p<test-period>]\n\
-         [-d<drop-time>] [-D<max-drop>] [-l<local-addr|interface>] [-i]\n\
-         [-x<diagnostic-selector>] [server]\n";
-    int v4 = 0;                 /* DHCPv4 operation explicitly requested */
-    const char* msg;            /* Failure message from procOpts() */
-    int help = 0;               /* Help requested */
-    int versionReq = 0;         /* Version requested */
-    const char* diagStr = NULL; /* Diagnostics requested (-x) */
-
-    /* option descriptions */
-    confvar_t optConf[] = {
-        { 'h', NULL,        CF_SWITCH,    &help,        1 },
-        { 'v', NULL,        CF_SWITCH,    &versionReq,  1 },
-        { '4', NULL,        CF_SWITCH,    &v4,          1 },
-        { '6', NULL,        CF_SWITCH,    &v6,          1 },
-        { 'i', NULL,        CF_SWITCH,    &initialOnly, 1 },
-        { 'l', NULL,        CF_NE_STRING, &localName,   0 },
-        { 'r', NULL,        CF_POS_INT,   &rate,        0 },
-        { 'n', NULL,        CF_POS_INT,   &numRequest,  0 },
-        { 'd', NULL,        CF_POS_FLOAT, &dropTime,    0 },
-        { 'p', NULL,        CF_POS_FLOAT, &testPeriod,  0 },
-        { 'D', NULL,        CF_NE_STRING, &maxDropOpt,  0 },
-        { 'x', NULL,        CF_STRING,    &diagStr,     0 },
-        { '\0', NULL,       CF_ENDLIST,   NULL,         0 }
-    };
-
-    /* diagnostic map */
-    const struct dkdesc diagLetters[] = {
-        { 's', DK_SOCK },
-        { 'm', DK_MSG },
-        { 'p', DK_PACKET },
-        { 'a', DK_ALL },
-        { '\0', 0 }
-    };
-
-    initialize();
-    /* Process command line options */
-    msg = procOpts(&argc, &argv, optConf, NULL, PROGNAME, NULL);
-    if (msg != NULL) {
-        fprintf(stderr, "%s: %s\n", PROGNAME, msg);
-        return(2);
-    }
-
-    if (help) {
-        printHelp(PROGNAME, usage);
-        return(0);
-    }
-    if (versionReq) {
-        printf("%s\n", VERSION);
-        return(0);
-    }
-    if (diagStr != NULL) {
-        char c;
-        if ((c = dk_setup(diagStr, diagLetters)) != '\0') {
-            fprintf(stderr,
-                    "%s: Invalid selector character given with -x: '%c'\n",
-                    PROGNAME, c);
-            return(2);
-        }
-    }
-
-    if (v4 && v6) {
-        fprintf(stderr, "%s: Must not give -4 and -6 together.\n", PROGNAME);
-        return(2);
-    }
-    switch (argc) {
-    case 0:
-        if (v6 && localName != NULL) {
-            server = "all";
-        } else {
-            if (v6) {
-                fprintf(stderr,
-                        "%s: Use -l to specify an interface name.\n\%s\n",
-                        PROGNAME, usage);
-            }
-            else {
-                fprintf(stderr, "%s: Must specify a DHCP server.\n\%s\n",
-                        PROGNAME, usage);
-            }
-            return(2);
-        }
-        break;
-    case 1:
-        server = argv[0];
-        break;
-    default:
-        fprintf(stderr, "%s: Too many arguments.\n\%s\n", PROGNAME, usage);
-        return(2);
-    }
-    return(1);
-}
-
-/*
- * Initialize values set by procArgs().
- * Initialized though they are static to allow for repeated calls for testing.
- */
-static void
-initialize(void) {
-    v6 = 0;
-    initialOnly = 0;
-    rate = 0;
-    numRequest = 0;
-    dropTime = 0.0;
-    testPeriod = 0.0;
-    maxDropOpt = NULL;
-    localName = NULL;
-    server = NULL;
-}
-
-static void
-printHelp(const char* progName, const char* usage) {
-    printf(
-        "%s: Execute a performance test against a DHCP server.\n\
-%s\n\
-The [server] argument is the name/address of the DHCP server to contact. \n\
-For DHCPv4 operation, exchanges are initiated by transmitting a DHCP\n\
-DISCOVER to this address.  For DHCPv6 operation, exchanges are initiated\n\
-by transmitting a DHCP SOLICIT to this address.  In the DHCPv6 case, the\n\
-special name \"all\" can be used to refer to\n\
-All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2), or\n\
-the special name \"servers\" to refer to All_DHCP_Servers (the multicast\n\
-address FF05::1:3).  The [server] argument is optional only in the case\n\
-that -l is used to specify an interface, in which case [server] defaults\n\
-to \"all\".\n\
-\n\
-Exchanges are initiated by transmitting a DHCP SOLICIT to\n\
-All_DHCP_Relay_Agents_and_Servers (the multicast address FF02::1:2) via\n\
-this interface.\n\
-\n\
-The default is to perform a single 4-way exchange, effectively pinging the\n\
-server.  The -r option is used to set up a performance test.\n\
-\n\
-Options:\n\
--4: DHCPv4 operation (default). This is incompatible with the -6 option.\n\
--6: DHCPv6 operation. This is incompatible with the -4 option.\n\
--h: Print this help.\n\
--i: Do only the initial part of an exchange: DO or SA, depending on\n\
-    whether -6 is given.\n\
--l<local-addr|interface>: For DHCPv4 operation, specify the local\n\
-    hostname/address to use when communicating with the server.  By\n\
-    default, the interface address through which traffic would normally be\n\
-    routed to the server is used.\n\
-    For DHCPv6 operation, specify the name of the network interface via\n\
-    which exchanges are initiated.  This must be specified unless a server\n\
-    name is given, in which case the interface through which traffic would\n\
-    normally be routed to the server is used.\n\
--r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA) exchanges per\n\
-    second.  A periodic report is generated showing the number of exchanges\n\
-    which were not completed, as well as the average response latency.  The\n\
-    program continues until interrupted, at which point a final report is\n\
-    generated.\n\
--v: Report the version number of this program.\n\
--x<diagnostic-selector>: Include extended diagnostics in the output.\n\
-    <diagnostic-selector> is a string of characters, each specifying an\n\
-    operation for which verbose output is desired.  The selector characters\n\
-    are:\n\
-    [TO BE ADDED]\n\
-\n\
-The remaining options are used only in conjunction with -r:\n\
-\n\
--d<drop-time>: Specify the time after which a request is treated as having\n\
-    been lost.  The value is given in seconds and may contain a fractional\n\
-    component.  The default is 1 second.\n\
--D<max-drop>: Abort the test if more than <max-drop> requests have been\n\
-    dropped.  Use -D0 to abort if even a single request has been dropped. \n\
-    If <max-drop> includes the suffix \"%%\", it specifies a maximum\n\
-    percentage of requests that may be dropped before abort.  In this\n\
-    case, testing of the threshold begins after 10 requests have been\n\
-    expected to be received.\n\
--n<num-request>: Initiate <num-request> transactions.  No report is\n\
-    generated until all transactions have been initiated/waited-for, after\n\
-    which a report is generated and the program terminates.\n\
--p<test-period>: Send requests for the given test period, which is\n\
-    specified in the same manner as -d.  This can be used as an\n\
-    alternative to -n, or both options can be given, in which case the\n\
-    testing is completed when either limit is reached.\n\
-\n\
-Exit status:\n\
-The exit status is:\n\
-0 on complete success.\n\
-1 for a general error.\n\
-2 if an error is found in the command line arguments.\n\
-3 if there are no general failures in operation, but one or more exchanges\n\
-  are not successfully completed.\n",
-        progName, usage);
-}
-
-int
-isV6(void) {
-    return v6;
-}
-
-int
-getInitialOnly(void) {
-    return initialOnly;
-}
-
-unsigned
-getRate(void) {
-    return rate;
-}
-
-unsigned
-getNumRequest(void) {
-    return numRequest;
-}
-
-double
-getDropTime(void) {
-    return dropTime;
-}
-
-double
-getTestPeriod(void) {
-    return testPeriod;
-}
-
-const char *
-getServer(void) {
-    return server;
-}
-
-const char *
-getLocalName(void) {
-    return localName;
-}
-
-const char *
-getMaxDrop(void) {
-    return maxDropOpt;
-}
diff --git a/tests/tools/perfdhcp/cloptions.h b/tests/tools/perfdhcp/cloptions.h
index e54bd13..981d7e2 100644
--- a/tests/tools/perfdhcp/cloptions.h
+++ b/tests/tools/perfdhcp/cloptions.h
@@ -17,6 +17,10 @@
 #ifndef CLOPTIONS_H
 #define CLOPTIONS_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdint.h>
 #include "procconf.h"
 
@@ -46,4 +50,8 @@ const char* getServer(void);    // Server to contact
 const char* getLocalName(void); // Local host/interface (-l)
 const char* getMaxDrop(void);   // Max dropped responses (-D)
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/tests/tools/perfdhcp/dkdebug.c b/tests/tools/perfdhcp/dkdebug.c
new file mode 100644
index 0000000..88f62dd
--- /dev/null
+++ b/tests/tools/perfdhcp/dkdebug.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011  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.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "dkdebug.h"
+
+/*
+ * The set of diagnostic bits set by dk_setup(), and used by the other
+ * functions to test offered diagnostics against.
+ */
+static unsigned dk_diag_mask = 0;
+
+char
+dk_setup(const char* diag_str, const struct dkdesc* diags) {
+    dk_diag_mask = 0;
+    int i;
+
+    for (; *diag_str != '\0'; diag_str++) {
+        for (i = 0; diags[i].keyletter != '\0'; i++) {
+            if (diags[i].keyletter == *diag_str) {
+                dk_diag_mask |= diags[i].mask;
+                break;
+            }
+        }
+        if (diags[i].keyletter == '\0') {
+            return(*diag_str);
+        }
+    }
+    return('\0');
+}
+
+void
+dkprintf(unsigned diag_req, const char format[], ...) {
+    va_list ap;
+
+    va_start(ap,format);
+    vdkprintf(diag_req, format, ap);
+    va_end(ap);
+}
+
+void
+vdkprintf(unsigned diag_req, const char format[], va_list ap) {
+    if (diag_req & dk_diag_mask) {
+        vfprintf(stderr, format, ap);
+    }
+}
+
+int
+dk_set(unsigned diag_req) {
+    return((diag_req & dk_diag_mask) != 0);
+}
diff --git a/tests/tools/perfdhcp/dkdebug.cc b/tests/tools/perfdhcp/dkdebug.cc
deleted file mode 100644
index 88f62dd..0000000
--- a/tests/tools/perfdhcp/dkdebug.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2011  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.
- */
-
-#include <stdio.h>
-#include <stdarg.h>
-#include "dkdebug.h"
-
-/*
- * The set of diagnostic bits set by dk_setup(), and used by the other
- * functions to test offered diagnostics against.
- */
-static unsigned dk_diag_mask = 0;
-
-char
-dk_setup(const char* diag_str, const struct dkdesc* diags) {
-    dk_diag_mask = 0;
-    int i;
-
-    for (; *diag_str != '\0'; diag_str++) {
-        for (i = 0; diags[i].keyletter != '\0'; i++) {
-            if (diags[i].keyletter == *diag_str) {
-                dk_diag_mask |= diags[i].mask;
-                break;
-            }
-        }
-        if (diags[i].keyletter == '\0') {
-            return(*diag_str);
-        }
-    }
-    return('\0');
-}
-
-void
-dkprintf(unsigned diag_req, const char format[], ...) {
-    va_list ap;
-
-    va_start(ap,format);
-    vdkprintf(diag_req, format, ap);
-    va_end(ap);
-}
-
-void
-vdkprintf(unsigned diag_req, const char format[], va_list ap) {
-    if (diag_req & dk_diag_mask) {
-        vfprintf(stderr, format, ap);
-    }
-}
-
-int
-dk_set(unsigned diag_req) {
-    return((diag_req & dk_diag_mask) != 0);
-}
diff --git a/tests/tools/perfdhcp/perfdhcp.h b/tests/tools/perfdhcp/perfdhcp.h
index c957187..af461b9 100644
--- a/tests/tools/perfdhcp/perfdhcp.h
+++ b/tests/tools/perfdhcp/perfdhcp.h
@@ -21,8 +21,6 @@
 extern "C" {
 #endif
 
-#define PROGNAME "perfdhcp"
-
 /*
  * The masks associated with keyletters, used in dkdesc structures for setup
  * and passed in the diag_req argument to the output/test functions to
diff --git a/tests/tools/perfdhcp/procconf.c b/tests/tools/perfdhcp/procconf.c
new file mode 100644
index 0000000..8fac58a
--- /dev/null
+++ b/tests/tools/perfdhcp/procconf.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2011  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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include "procconf.h"
+
+static char errmsg[256];    /* for returning error descriptions */
+static const char* pc_name;
+static const char* pc_usage;
+
+#define INTERNAL_ERROR -1
+#define USAGE_ERROR -2
+
+/*
+ * error: printf-style interface to print an error message or write it into
+ * global errmsg.  If a usage message has been given (the indicator that errors
+ * should be handled internally), the message is printed to stderr and the
+ * program is exited.  If not, it is written into errmsg.
+ * Input variables:
+ * errtype is the error type.  If USAGE_ERROR, the program's usage is included
+ *     in error messages, and the exit status is 2; otherwise the exit status
+ *     is 1.
+ * format and the remaining arguments are as for printf().
+ */
+static void
+error(const int errtype, const char* format, ...) {
+    va_list ap;
+
+    va_start(ap,format);
+    if (pc_usage != NULL) { /* error messages should be printed directly */
+        fprintf(stderr, "%s: ", pc_name);
+        vfprintf(stderr, format, ap);
+        putc('\n', stderr);
+        if (errtype == USAGE_ERROR) {
+            fputs(pc_usage, stderr);
+        }
+        exit(errtype == USAGE_ERROR ? 2 : 1);
+    } else {
+        vsnprintf(errmsg, sizeof(errmsg), format, ap);
+    }
+    va_end(ap);
+}
+
+/*
+ * Allocate memory, with error checking.
+ * On allocation failure, error() is called; see its description.
+ * The memory is zeroed before being returned.
+ */
+static void*
+pc_malloc(size_t size) {
+    void* ret = calloc(1, size);
+    if (ret == NULL) {
+        error(INTERNAL_ERROR, "Out of memory");
+    }
+    return(ret);
+}
+
+/*
+ * Generate an error message describing an error in the value passed with an
+ * option.  This is a front end for error(); see its usage for details.
+ * Input variables:
+ * expected: A description of what was expected for the value.
+ * varDesc: The descriptor for the option.
+ * value: The value that was given with the option.
+ * detail: If non-null, additional detail to append regardign the problem.
+ */
+static void
+opterror(const char* expected, const char* value, const confvar_t* varDesc,
+         const char* detail) {
+    if (detail == NULL) {
+        detail = "";
+    }
+    error(USAGE_ERROR,
+          "Invalid value given for option -%c: expected %s, got: %s%s",
+          varDesc->outind, expected, value, detail);
+}
+
+/*
+ * Add an option flag or value assignment to the options database.
+ * This does all option-type-specific processing, and generates linked lists
+ * of option structures.
+ *
+ * Input variables:
+ * value is the string value assigned to the option, for options that take
+ *     values.
+ * varDesc is the description structure for this option.
+ *
+ * Output variables:
+ * The option data is stored in a malloced confval structure, which is appended
+ * to the option list.  The first element of the list is pointed to by first.
+ * first should be NULL if the list contains no elements; in this case it is
+ * set to point to the new structure.  Otherwise the structure is appended to
+ * the element pointed to by last (it is updated to point to that structure).
+ * The 'next' element of the new structure is set to NULL; this is the list
+ * termination indicator when traversing it.
+ *
+ * Return value:
+ * 0 if option was ignored.
+ * 1 if option was processed & added to option chain.
+ * On error, a string describing the error is stored in the global errmsg and
+ * -1 is returned.
+ */
+static int
+addOptVal(const char* value, const confvar_t* varDesc,
+          confval** first, confval** last) {
+    const void* addr;           /* address, if any at which to store value */
+    confval data;               /* data for this option/value */
+    confval *ret_data;          /* allocated structure to add to list */
+    int seen = *first != NULL;  /* has this option been seen before? */
+    char* ptr;        /* character that terminated processing in strtox() */
+    int err;                    /* bad numeric value found? */
+
+    /* if first instance of this option, store result to given addr */
+    addr = seen ? NULL : varDesc->addr;
+    switch (varDesc->type) {
+    case CF_CHAR:
+        if (strlen(value) > 1) {    /* length 0 is OK; gives null char */
+            opterror("a single character", value, varDesc, NULL);
+            return(-1);
+        }
+        data.value.charval = *value;
+        if (addr != NULL) {
+            *(char*)addr = *value;
+        }
+        break;
+    case CF_STRING:
+    case CF_NE_STRING:
+        if (varDesc->type == CF_NE_STRING && *value == '\0') {
+            opterror("a non-empty string", value, varDesc, NULL);
+            return(-1);
+        }
+        data.value.string = value;
+        if (addr != NULL) {
+            *(const char**)addr = value;
+        }
+        break;
+    case CF_INT:
+    case CF_NON_NEG_INT:
+    case CF_POS_INT:
+        /* todo: check for out-of-range result */
+        errno = 0;
+        data.value.intval = strtol(value, &ptr, 0);
+        if (errno == ERANGE) {
+            opterror("an integer", value, varDesc,
+                     " (out of range)");
+            return(-1);
+        }
+        err = *value == '\0' || *ptr != '\0';
+        switch (varDesc->type) {
+        case CF_INT:
+            if (err) {
+                opterror("an integer", value, varDesc, NULL);
+                return(-1);
+            }
+            break;
+        case CF_NON_NEG_INT:
+            if (err || data.value.intval < 0) {
+                opterror("a non-negative integer", value, varDesc,
+                         NULL);
+                return(-1);
+            }
+            data.value.nnint = data.value.intval;
+            break;
+        case CF_POS_INT:
+            if (err || data.value.intval <= 0) {
+                opterror("a positive integer", value, varDesc, NULL);
+                return(-1);
+            }
+            data.value.nnint = data.value.intval;
+            break;
+        default:
+            /* To avoid complaints from -Wall */
+            ;
+        }
+        if (addr != NULL) {
+            *(int*)addr = data.value.intval;
+        }
+        break;
+    case CF_FLOAT:
+    case CF_NON_NEG_FLOAT:
+    case CF_POS_FLOAT:
+        /* todo: check for out-of-range result */
+        errno = 0;
+        data.value.floatval = strtod(value, &ptr);
+        if (errno == ERANGE) {
+            opterror("a number", value, varDesc, " (out of range)");
+            return(-1);
+        }
+        err = *value == '\0' || *ptr != '\0';
+        switch (varDesc->type) {
+        case CF_FLOAT:
+            if (err) {
+                opterror("a number", value, varDesc, NULL);
+                return(-1);
+            }
+            break;
+        case CF_NON_NEG_FLOAT:
+            if (err || data.value.floatval < 0) {
+                opterror("a non-negative number", value, varDesc,
+                         NULL);
+                return(-1);
+            }
+            break;
+        case CF_POS_FLOAT:
+            if (err || data.value.floatval <= 0) {
+                opterror("a positive number", value, varDesc, NULL);
+                return(-1);
+            }
+            break;
+        default:
+            /* To avoid complaints from -Wall */
+            ;
+        }
+        if (addr != NULL) {
+            *(double*)addr = data.value.floatval;
+        }
+        break;
+    case CF_SWITCH:
+        data.value.switchval = varDesc->value;
+        value = "1";    /* for debugging */
+        if (addr != NULL) {
+            *(int*)addr = varDesc->value;
+        }
+        break;
+    case CF_ENDLIST:
+        /* To avoid complaints from -Wall */
+        ;
+    }
+    data.strval = value;
+    data.next = NULL;
+    if ((ret_data = (confval*)pc_malloc(sizeof(confval))) == NULL) {
+        return(-1);
+    }
+    *ret_data = data;
+    if (seen) {
+        (*last)->next = ret_data;
+    } else {
+        *first = ret_data;
+    }
+    *last = ret_data;
+    return(1);
+}
+
+/*
+ * Input variables:
+ * argc, argv: Command line data.
+ * optConf[]: Option description structures.
+ *
+ * Output variables:
+ * See addOptVal().
+ * After processing, argc will be the number of non-option arguments and argv
+ * will start with the first non-option argument.
+ *
+ * Return value:
+ * On success, the number of options processed.
+ * On error, a string describing the error is stored in the global errmsg and
+ * -1 is returned.
+ */
+static int
+procCmdLineArgs(int* argc, const char** argv[], const confvar_t optConf[],
+                confval** perOptRecordsFirst, confval** perOptRecordsLast) {
+    char* p;
+    extern char* optarg;    /* For getopt */
+    extern int optind;      /* For getopt */
+    extern int optopt;      /* For getopt */
+    char optstr[514];       /* List of option chars, for getopt */
+    unsigned optCharToConf[256];        /* Map option char/num to confvar */
+    int optchar;            /* value returned by getopt() */
+    int confNum;       /* to iterate over confvars */
+    int count = 0;          /* number of options processed */
+
+    p = optstr;
+    *(p++) = ':';
+    for (confNum = 0; optConf[confNum].type != CF_ENDLIST; confNum++) {
+        unsigned outind = optConf[confNum].outind;
+        if (outind < 256 && isprint(outind)) {
+            *(p++) = (char)outind;
+            switch (optConf[confNum].type) {
+            case CF_SWITCH:
+                break;
+            default:
+                *(p++) = ':';
+                break;
+            }
+            optCharToConf[outind] = confNum;
+        }
+    }
+
+    *p = '\0';
+    optind = 1;
+    while ((optchar = getopt(*argc, *argv, optstr)) != -1)
+    {
+        int ind;
+        int ret;
+
+        if (optchar == '?') {
+            error(USAGE_ERROR, "Unknown option character '%c'", optopt);
+            return(-1);
+        } else if (optchar == ':') {
+            error(USAGE_ERROR, "No value given for option -%c", optopt);
+            return(-1);
+        }
+        ind = optCharToConf[optchar];
+        switch (ret = addOptVal(optarg, &optConf[ind],
+                                &perOptRecordsFirst[ind],
+                                &perOptRecordsLast[ind])) {
+        case 1:
+            count++;
+            break;
+        case 0:
+            break;
+        default:
+            return(ret);
+        }
+    }
+    *argc -= optind;
+    *argv += optind;
+    return(count);
+}
+
+/*
+ * Input variables:
+ * argc, argv: Command line data.
+ * optConf[]: Option description structures.
+ * name: Name of program, for messages.
+ * usage: Usage message.  If non-null, on error a message is printed to stderr
+ *    and the program exits.
+ *
+ * Output variables:
+ * Option values are stored at the value given by any confvar that has a
+ * non-null address. 
+ * If confdatda is not null, the processed option values are stored in
+ * confdata.
+ * A pointer to the start of the values for each option is stored in
+ * confdata->optVals[].values at the same offset as the option appears in
+ * confdata[].
+ * For any option for option characters/indexes that have been used,
+ * confdata->map[index] is set to the same data.
+ * After processing, argc will have been adjusted to be the number of
+ * non-option arguments and argv will have been adjusted to start with the
+ * first non-option argument.
+ * The malloced data structures returned in confdata are:
+ *   optVals
+ *   optVals[0].values
+ *   If any option characters/indexes are used, map.  If not used, this will be
+ *     a null pointer.
+ *
+ * Return value:
+ * On success, NULL.
+ * On error, a message describing the problem.
+ */
+const char*
+procOpts(int* argc, const char** argv[], const confvar_t optConf[],
+         confdata_t* confdata, const char name[],
+         const char usage[]) {
+    /*
+     * First & last records in the linked lists maintained for each option.
+     * These will point to arrays indexed by option number, giving one pointer
+     * (each) per option, used to maintain/return the list of values seen for
+     * that option (see the description of first & last in addOptVal()
+     */
+    confval** perOptRecordsFirst;
+    confval** perOptRecordsLast;
+
+    /* Number of configuration options given in optConf */
+    unsigned numConf;
+    unsigned maxOptIndex = 0;   /* The highest option index number seen */
+    /* number of option instances + assignments given */
+    int numOptsFound;
+    int optNum;    /* to iterate through the possible options */
+    int i;         /* index into the global list of option value structures */
+    confval** valuePointers;    /* global list of value structures */
+
+    pc_name = name;
+    pc_usage = usage;
+    for (numConf = 0; optConf[numConf].type != CF_ENDLIST; numConf++) {
+        unsigned outind = optConf[numConf].outind;
+
+        if ((outind & ~CF_NOTFLAG) > maxOptIndex) {
+            maxOptIndex = outind & ~CF_NOTFLAG;
+        }
+    }
+    if (numConf == 0) {
+        error(INTERNAL_ERROR, "Empty confvar list");
+        return(errmsg);
+    }
+    if ((perOptRecordsFirst = (confval**)pc_malloc(sizeof(confval*) * numConf))
+            == NULL || (perOptRecordsLast =
+            (confval**)pc_malloc(sizeof(confval*) * numConf)) == NULL) {
+        return(errmsg);
+    }
+
+    numOptsFound = procCmdLineArgs(argc, argv, optConf, perOptRecordsFirst,
+                                   perOptRecordsLast);
+    free(perOptRecordsLast);
+    perOptRecordsLast = NULL;
+
+    if (numOptsFound < 0)
+    {
+        free(perOptRecordsFirst);
+        return(errmsg);
+    }
+    if (confdata == NULL) {
+        free(perOptRecordsFirst);
+        return NULL;
+    }
+
+    /*
+     * All options have been read & initial processing done.
+     * An array of pointers is now generated for the options.
+     */
+    if ((valuePointers =
+            (confval**)pc_malloc(sizeof(confval*) * numOptsFound)) == NULL ||
+            (confdata->optVals =
+            (cf_option*)pc_malloc(sizeof(cf_option) * numConf)) == NULL) {
+        return(errmsg);
+    }
+    /* If option characters / indexes are used, allocate a map for them */
+    if (maxOptIndex == 0) {
+	confdata->map = NULL;
+    } else {
+        if ((confdata->map = (cf_option**)pc_malloc(sizeof(cf_option) *
+             (maxOptIndex+1))) == NULL) {
+            return(errmsg);
+        }
+    }
+
+    /*
+     * Store the linked lists of option values into arrays.
+     * Pointers to all option instances are stored in valuePointers,
+     * with the values for each particular option being contiguous.
+     */
+    i = 0;
+    for (optNum = 0; optNum < numConf; optNum++) {
+        unsigned outind = optConf[optNum].outind;
+        confval* optval;
+
+        confdata->optVals[optNum].num = 0;
+        confdata->optVals[optNum].values = &valuePointers[i];
+        if (outind != 0) {
+            confdata->map[outind & ~CF_NOTFLAG] = &confdata->optVals[optNum];
+        }
+        for (optval = perOptRecordsFirst[optNum]; optval != NULL;
+                 optval = optval->next) {
+            confdata->optVals[optNum].num++;
+            valuePointers[i++] = optval;
+        }
+    }
+    free(perOptRecordsFirst);
+    return(NULL);
+}
+
+/*
+ * Free the malloced data stored in confdata elements by ProcOpts()
+ */
+void
+confdataFree(confdata_t *confdata) {
+    if (confdata->map != NULL) {
+        free(confdata->map);
+        confdata->map = NULL;
+    }
+    free(confdata->optVals[0].values);
+    free(confdata->optVals);
+    confdata->optVals = NULL;
+}
diff --git a/tests/tools/perfdhcp/procconf.cc b/tests/tools/perfdhcp/procconf.cc
deleted file mode 100644
index ac7a445..0000000
--- a/tests/tools/perfdhcp/procconf.cc
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Copyright (C) 2011  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.
- */
-
-#include <string.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include "procconf.h"
-
-static char errmsg[256];    /* for returning error descriptions */
-static const char* pc_name;
-static const char* pc_usage;
-
-#define INTERNAL_ERROR -1
-#define USAGE_ERROR -2
-
-/*
- * error: printf-style interface to print an error message or write it into
- * global errmsg.  If a usage message has been given (the indicator that errors
- * should be handled internally), the message is printed to stderr and the
- * program is exited.  If not, it is written into errmsg.
- * Input variables:
- * errtype is the error type.  If USAGE_ERROR, the program's usage is included
- *     in error messages, and the exit status is 2; otherwise the exit status
- *     is 1.
- * format and the remaining arguments are as for printf().
- */
-static void
-error(const int errtype, const char* format, ...) {
-    va_list ap;
-
-    va_start(ap,format);
-    if (pc_usage != NULL) { /* error messages should be printed directly */
-        fprintf(stderr, "%s: ", pc_name);
-        vfprintf(stderr, format, ap);
-        putc('\n', stderr);
-        if (errtype == USAGE_ERROR) {
-            fputs(pc_usage, stderr);
-        }
-        exit(errtype == USAGE_ERROR ? 2 : 1);
-    } else {
-        vsnprintf(errmsg, sizeof(errmsg), format, ap);
-    }
-    va_end(ap);
-}
-
-/*
- * Allocate memory, with error checking.
- * On allocation failure, error() is called; see its description.
- * The memory is zeroed before being returned.
- */
-static void*
-pc_malloc(size_t size) {
-    void* ret = calloc(1, size);
-    if (ret == NULL) {
-        error(INTERNAL_ERROR, "Out of memory");
-    }
-    return(ret);
-}
-
-/*
- * Generate an error message describing an error in the value passed with an
- * option.  This is a front end for error(); see its usage for details.
- * Input variables:
- * expected: A description of what was expected for the value.
- * varDesc: The descriptor for the option.
- * value: The value that was given with the option.
- * detail: If non-null, additional detail to append regardign the problem.
- */
-static void
-opterror(const char* expected, const char* value, const confvar_t* varDesc,
-         const char* detail) {
-    if (detail == NULL) {
-        detail = "";
-    }
-    error(USAGE_ERROR,
-          "Invalid value given for option -%c: expected %s, got: %s%s",
-          varDesc->outind, expected, value, detail);
-}
-
-/*
- * Add an option flag or value assignment to the options database.
- * This does all option-type-specific processing, and generates linked lists
- * of option structures.
- *
- * Input variables:
- * value is the string value assigned to the option, for options that take
- *     values.
- * varDesc is the description structure for this option.
- *
- * Output variables:
- * The option data is stored in a malloced confval structure, which is appended
- * to the option list.  The first element of the list is pointed to by first.
- * first should be NULL if the list contains no elements; in this case it is
- * set to point to the new structure.  Otherwise the structure is appended to
- * the element pointed to by last (it is updated to point to that structure).
- * The 'next' element of the new structure is set to NULL; this is the list
- * termination indicator when traversing it.
- *
- * Return value:
- * 0 if option was ignored.
- * 1 if option was processed & added to option chain.
- * On error, a string describing the error is stored in the global errmsg and
- * -1 is returned.
- */
-static int
-addOptVal(const char* value, const confvar_t* varDesc,
-          confval** first, confval** last) {
-    const void* addr;           /* address, if any at which to store value */
-    confval data;               /* data for this option/value */
-    confval *ret_data;          /* allocated structure to add to list */
-    int seen = *first != NULL;  /* has this option been seen before? */
-    char* ptr;        /* character that terminated processing in strtox() */
-    int err;                    /* bad numeric value found? */
-
-    /* if first instance of this option, store result to given addr */
-    addr = seen ? NULL : varDesc->addr;
-    switch (varDesc->type) {
-    case CF_CHAR:
-        if (strlen(value) > 1) {    /* length 0 is OK; gives null char */
-            opterror("a single character", value, varDesc, NULL);
-            return(-1);
-        }
-        data.value.charval = *value;
-        if (addr != NULL) {
-            *(char*)addr = *value;
-        }
-        break;
-    case CF_STRING:
-    case CF_NE_STRING:
-        if (varDesc->type == CF_NE_STRING && *value == '\0') {
-            opterror("a non-empty string", value, varDesc, NULL);
-            return(-1);
-        }
-        data.value.string = value;
-        if (addr != NULL) {
-            *(const char**)addr = value;
-        }
-        break;
-    case CF_INT:
-    case CF_NON_NEG_INT:
-    case CF_POS_INT:
-        /* todo: check for out-of-range result */
-        errno = 0;
-        data.value.intval = strtol(value, &ptr, 0);
-        if (errno == ERANGE) {
-            opterror("an integer", value, varDesc,
-                     " (out of range)");
-            return(-1);
-        }
-        err = *value == '\0' || *ptr != '\0';
-        switch (varDesc->type) {
-        case CF_INT:
-            if (err) {
-                opterror("an integer", value, varDesc, NULL);
-                return(-1);
-            }
-            break;
-        case CF_NON_NEG_INT:
-            if (err || data.value.intval < 0) {
-                opterror("a non-negative integer", value, varDesc,
-                         NULL);
-                return(-1);
-            }
-            data.value.nnint = data.value.intval;
-            break;
-        case CF_POS_INT:
-            if (err || data.value.intval <= 0) {
-                opterror("a positive integer", value, varDesc, NULL);
-                return(-1);
-            }
-            data.value.nnint = data.value.intval;
-            break;
-        default:
-            /* To avoid complaints from -Wall */
-            ;
-        }
-        if (addr != NULL) {
-            *(int*)addr = data.value.intval;
-        }
-        break;
-    case CF_FLOAT:
-    case CF_NON_NEG_FLOAT:
-    case CF_POS_FLOAT:
-        /* todo: check for out-of-range result */
-        errno = 0;
-        data.value.floatval = strtod(value, &ptr);
-        if (errno == ERANGE) {
-            opterror("a number", value, varDesc, " (out of range)");
-            return(-1);
-        }
-        err = *value == '\0' || *ptr != '\0';
-        switch (varDesc->type) {
-        case CF_FLOAT:
-            if (err) {
-                opterror("a number", value, varDesc, NULL);
-                return(-1);
-            }
-            break;
-        case CF_NON_NEG_FLOAT:
-            if (err || data.value.floatval < 0) {
-                opterror("a non-negative number", value, varDesc,
-                         NULL);
-                return(-1);
-            }
-            break;
-        case CF_POS_FLOAT:
-            if (err || data.value.floatval <= 0) {
-                opterror("a positive number", value, varDesc, NULL);
-                return(-1);
-            }
-            break;
-        default:
-            /* To avoid complaints from -Wall */
-            ;
-        }
-        if (addr != NULL) {
-            *(double*)addr = data.value.floatval;
-        }
-        break;
-    case CF_SWITCH:
-        data.value.switchval = varDesc->value;
-        value = "1";    /* for debugging */
-        if (addr != NULL) {
-            *(int*)addr = varDesc->value;
-        }
-        break;
-    case CF_ENDLIST:
-        /* To avoid complaints from -Wall */
-        ;
-    }
-    data.strval = value;
-    data.next = NULL;
-    if ((ret_data = (confval*)pc_malloc(sizeof(confval))) == NULL) {
-        return(-1);
-    }
-    *ret_data = data;
-    if (seen) {
-        (*last)->next = ret_data;
-    } else {
-        *first = ret_data;
-    }
-    *last = ret_data;
-    return(1);
-}
-
-/*
- * Input variables:
- * argc, argv: Command line data.
- * optConf[]: Option description structures.
- *
- * Output variables:
- * See addOptVal().
- * After processing, argc will be the number of non-option arguments and argv
- * will start with the first non-option argument.
- *
- * Return value:
- * On success, the number of options processed.
- * On error, a string describing the error is stored in the global errmsg and
- * -1 is returned.
- */
-static int
-procCmdLineArgs(int* argc, const char** argv[], const confvar_t optConf[],
-                confval** perOptRecordsFirst, confval** perOptRecordsLast) {
-    char* p;
-    extern char* optarg;    /* For getopt */
-    extern int optind;      /* For getopt */
-    extern int optopt;      /* For getopt */
-    char optstr[514];       /* List of option chars, for getopt */
-    unsigned optCharToConf[256];        /* Map option char/num to confvar */
-    int optchar;            /* value returned by getopt() */
-    int confNum;       /* to iterate over confvars */
-    int count = 0;          /* number of options processed */
-
-    p = optstr;
-    *(p++) = ':';
-    for (confNum = 0; optConf[confNum].type != CF_ENDLIST; confNum++) {
-        unsigned outind = optConf[confNum].outind;
-        if (outind < 256 && isprint(outind)) {
-            *(p++) = (char)outind;
-            switch (optConf[confNum].type) {
-            case CF_SWITCH:
-                break;
-            default:
-                *(p++) = ':';
-                break;
-            }
-            optCharToConf[outind] = confNum;
-        }
-    }
-
-    *p = '\0';
-    optind = 1;
-    while ((optchar = getopt(*argc, const_cast<char**>(*argv), optstr)) != -1)
-    {
-        int ind;
-        int ret;
-
-        if (optchar == '?') {
-            error(USAGE_ERROR, "Unknown option character '%c'", optopt);
-            return(-1);
-        } else if (optchar == ':') {
-            error(USAGE_ERROR, "No value given for option -%c", optopt);
-            return(-1);
-        }
-        ind = optCharToConf[optchar];
-        switch (ret = addOptVal(optarg, &optConf[ind],
-                                &perOptRecordsFirst[ind],
-                                &perOptRecordsLast[ind])) {
-        case 1:
-            count++;
-            break;
-        case 0:
-            break;
-        default:
-            return(ret);
-        }
-    }
-    *argc -= optind;
-    *argv += optind;
-    return(count);
-}
-
-/*
- * Input variables:
- * argc, argv: Command line data.
- * optConf[]: Option description structures.
- * name: Name of program, for messages.
- * usage: Usage message.  If non-null, on error a message is printed to stderr
- *    and the program exits.
- *
- * Output variables:
- * Option values are stored at the value given by any confvar that has a
- * non-null address. 
- * If confdatda is not null, the processed option values are stored in
- * confdata.
- * A pointer to the start of the values for each option is stored in
- * confdata->optVals[].values at the same offset as the option appears in
- * confdata[].
- * For any option for option characters/indexes that have been used,
- * confdata->map[index] is set to the same data.
- * After processing, argc will have been adjusted to be the number of
- * non-option arguments and argv will have been adjusted to start with the
- * first non-option argument.
- * The malloced data structures returned in confdata are:
- *   optVals
- *   optVals[0].values
- *   If any option characters/indexes are used, map.  If not used, this will be
- *     a null pointer.
- *
- * Return value:
- * On success, NULL.
- * On error, a message describing the problem.
- */
-const char*
-procOpts(int* argc, const char** argv[], const confvar_t optConf[],
-         confdata_t* confdata, const char name[],
-         const char usage[]) {
-    /*
-     * First & last records in the linked lists maintained for each option.
-     * These will point to arrays indexed by option number, giving one pointer
-     * (each) per option, used to maintain/return the list of values seen for
-     * that option (see the description of first & last in addOptVal()
-     */
-    confval** perOptRecordsFirst;
-    confval** perOptRecordsLast;
-
-    /* Number of configuration options given in optConf */
-    unsigned numConf;
-    unsigned maxOptIndex = 0;   /* The highest option index number seen */
-    /* number of option instances + assignments given */
-    int numOptsFound;
-    int optNum;    /* to iterate through the possible options */
-    int i;         /* index into the global list of option value structures */
-    confval** valuePointers;    /* global list of value structures */
-
-    pc_name = name;
-    pc_usage = usage;
-    for (numConf = 0; optConf[numConf].type != CF_ENDLIST; numConf++) {
-        unsigned outind = optConf[numConf].outind;
-
-        if ((outind & ~CF_NOTFLAG) > maxOptIndex) {
-            maxOptIndex = outind & ~CF_NOTFLAG;
-        }
-    }
-    if (numConf == 0) {
-        error(INTERNAL_ERROR, "Empty confvar list");
-        return(errmsg);
-    }
-    if ((perOptRecordsFirst = (confval**)pc_malloc(sizeof(confval*) * numConf))
-            == NULL || (perOptRecordsLast =
-            (confval**)pc_malloc(sizeof(confval*) * numConf)) == NULL) {
-        return(errmsg);
-    }
-
-    numOptsFound = procCmdLineArgs(argc, argv, optConf, perOptRecordsFirst,
-                                   perOptRecordsLast);
-    free(perOptRecordsLast);
-    perOptRecordsLast = NULL;
-
-    if (numOptsFound < 0)
-    {
-        free(perOptRecordsFirst);
-        return(errmsg);
-    }
-    if (confdata == NULL) {
-        free(perOptRecordsFirst);
-        return NULL;
-    }
-
-    /*
-     * All options have been read & initial processing done.
-     * An array of pointers is now generated for the options.
-     */
-    if ((valuePointers =
-            (confval**)pc_malloc(sizeof(confval*) * numOptsFound)) == NULL ||
-            (confdata->optVals =
-            (cf_option*)pc_malloc(sizeof(cf_option) * numConf)) == NULL) {
-        return(errmsg);
-    }
-    /* If option characters / indexes are used, allocate a map for them */
-    if (maxOptIndex == 0) {
-	confdata->map = NULL;
-    } else {
-        if ((confdata->map = (cf_option**)pc_malloc(sizeof(cf_option) *
-             (maxOptIndex+1))) == NULL) {
-            return(errmsg);
-        }
-    }
-
-    /*
-     * Store the linked lists of option values into arrays.
-     * Pointers to all option instances are stored in valuePointers,
-     * with the values for each particular option being contiguous.
-     */
-    i = 0;
-    for (optNum = 0; optNum < numConf; optNum++) {
-        unsigned outind = optConf[optNum].outind;
-        confval* optval;
-
-        confdata->optVals[optNum].num = 0;
-        confdata->optVals[optNum].values = &valuePointers[i];
-        if (outind != 0) {
-            confdata->map[outind & ~CF_NOTFLAG] = &confdata->optVals[optNum];
-        }
-        for (optval = perOptRecordsFirst[optNum]; optval != NULL;
-                 optval = optval->next) {
-            confdata->optVals[optNum].num++;
-            valuePointers[i++] = optval;
-        }
-    }
-    free(perOptRecordsFirst);
-    return(NULL);
-}
-
-/*
- * Free the malloced data stored in confdata elements by ProcOpts()
- */
-void
-confdataFree(confdata_t *confdata) {
-    if (confdata->map != NULL) {
-        free(confdata->map);
-        confdata->map = NULL;
-    }
-    free(confdata->optVals[0].values);
-    free(confdata->optVals);
-    confdata->optVals = NULL;
-}
diff --git a/tests/tools/perfdhcp/procconf.h b/tests/tools/perfdhcp/procconf.h
index fd29c00..73994a7 100644
--- a/tests/tools/perfdhcp/procconf.h
+++ b/tests/tools/perfdhcp/procconf.h
@@ -22,6 +22,10 @@
 #ifndef PROCCONF_H
 #define PROCCONF_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <limits.h> /* for UINT_MAX */
 
 /*
@@ -125,4 +129,8 @@ procOpts(int* argc, const char** argv[], const confvar_t optConf[],
  */
 void confdataFree(confdata_t *confdata);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/tests/tools/perfdhcp/tests/Makefile.am b/tests/tools/perfdhcp/tests/Makefile.am
index 54a7045..629172c 100644
--- a/tests/tools/perfdhcp/tests/Makefile.am
+++ b/tests/tools/perfdhcp/tests/Makefile.am
@@ -15,9 +15,9 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += cloptions_unittest.cc
-run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/cloptions.cc
-run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/procconf.cc
-run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/dkdebug.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/cloptions.c
+run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/procconf.c
+run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/dkdebug.c
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)




More information about the bind10-changes mailing list