Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt	(revision 63769)
+++ CMakeLists.txt	(working copy)
@@ -3,6 +3,7 @@
   epspsi.c
   nacax.c
   naca456.c
+  namelist.c
   )
 
 BRLCAD_ADDEXEC(naca456 "${naca_srcs}" "libwdb;${OPENNURBS_LIBRARY}" NO_STRICT NO_INSTALL)
Index: fortran_arrays.h
===================================================================
--- fortran_arrays.h	(revision 0)
+++ fortran_arrays.h	(working copy)
@@ -0,0 +1,86 @@
+/*                          F O R T R A N _ A R R A Y S . H
+ * BRL-CAD
+ *
+ * Copyright (c) 2014 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @file fortran_arrays.h
+ *
+ * This file includes a set of structures and macros that are used to
+ * emulate Fortran arrays.
+ *
+ */
+#ifndef FORTRAN_ARRAYS_H
+#define FORTRAN_ARRAYS_H
+
+#include <stdlib.h>
+
+#include "vmath.h"
+
+/* The array in this structure should be 1-indexed */
+struct fortran_array {
+  int n;
+  fastf_t *nums;
+  int shared;
+};
+#define SIZE(array) array->n
+#define INDEX(array, n) array->nums[n]
+#define ALLOCATE(array, _n) do {					\
+	array = (struct fortran_array *)malloc(sizeof(struct fortran_array)); \
+	array->nums = (fastf_t *)malloc(sizeof(fastf_t) * (_n + 1));        \
+    array->shared = 0;                                                  \
+	array->n = _n;                                                      \
+  } while (0);
+#define DEALLOCATE(array) do {                  \
+    if (!array->shared) {                       \
+      free(array->nums);                        \
+    }                                           \
+    free(array);                                \
+  } while (0);
+#define SLICE(new, array, start, end) do {                              \
+	new = (struct fortran_array *)malloc(sizeof(struct fortran_array)); \
+	new->n = (end - start) + 1;                                         \
+	new->nums = array->nums + start - 1;                                \
+    new->shared = 1;                                                  \
+  } while (0);
+#define COPY(new, array, start, end) do {	\
+	VMOVEN(F2C(new), F2CI(array, start), (end - start) + 1);	\
+  } while (0);
+
+#define F2C(array) F2CI(array, 1)
+#define F2CI(array, indx) (array->nums + indx)
+
+#define C2F(array, carray, n) do {		\
+	ALLOCATE(array, n);			\
+	VMOVEN(array->nums + 1, carray, n);	\
+    } while (0);
+
+#endif /* FORTRAN_ARRAYS_H */
Index: fortran_compat.h
===================================================================
--- fortran_compat.h	(revision 0)
+++ fortran_compat.h	(working copy)
@@ -0,0 +1,51 @@
+/*                          F O R T R A N _ C O M P A T . H
+ * BRL-CAD
+ *
+ * Copyright (c) 2014 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @file fortran_compat.h
+ *
+ * This file includes all of the code related to allowing Fortran
+ * paradigms in C.
+ *
+ */
+#ifndef FORTRAN_COMPAT_H
+#define FORTRAN_COMPAT_H
+
+/* Other Fortran math functions not in C. */
+#define SIGNUM(x) ((x > 0) - (x < 0))
+#define SIGN(a, b) (a * SIGNUM(b))
+
+#include "fortran_arrays.h"
+#include "namelist.h"
+
+#endif /* FORTRAN_COMPAT_H */
Index: naca.h
===================================================================
--- naca.h	(revision 63769)
+++ naca.h	(working copy)
@@ -38,45 +38,14 @@
  *
  */
 
+#ifndef NACA_H
+#define NACA_H
+
 #include "common.h"
+
 #include "bu/defines.h"
 
-/* The array in this structure should be 1-indexed */
-struct fortran_array {
-    int n;
-    fastf_t *nums;
-};
-#define SIZE(array) array->n
-#define INDEX(array, n) array->nums[n]
-#define ALLOCATE(array, _n) do {					\
-	array = (struct fortran_array *)malloc(sizeof(struct fortran_array));	\
-	array->nums = (fastf_t *)malloc(sizeof(fastf_t) * (_n + 1));	\
-	array->n = _n;							\
-    } while (0);
-#define DEALLOCATE(array) do {			\
-	free(array->nums);			\
-	free(array);				\
-    } while (0);
-#define SLICE(new, array, start, end) do {	\
-	new = (struct fortran_array *)malloc(sizeof(struct fortran_array)); \
-	new->n = (end - start) + 1;					\
-	new->nums = array->nums + start - 1;				\
-    } while (0);
-#define COPY(new, array, start, end) do {	\
-	VMOVEN(F2C(new), F2CI(array, start), (end - start) + 1);	\
-    } while (0);
-
-#define F2C(array) F2CI(array, 1)
-#define F2CI(array, indx) (array->nums + indx)
-
-#define C2F(array, carray, n) do {		\
-	ALLOCATE(array, n);			\
-	VMOVEN(array->nums + 1, carray, n);	\
-    } while (0);
-
-#define SIGNUM(x) ((x > 0) - (x < 0))
-#define SIGN(a, b) (a * SIGNUM(b))
-
+#include "fortran_compat.h"
 /**
  * Evaluate a cubic polynomial and its 1st, 2nd, and 3rd derivatives
  * at a specified point.  The cubic is defined by the function and the
@@ -232,7 +201,7 @@
  * very dense at the nose, less dense on the forward airfoil and much
  * less dense on the aft airfoil.
  */
-void LoadX(int denCode, int nx, struct fortran_array *x);
+void LoadX(int denCode, int *nx, struct fortran_array *x);
 
 /**
  * Compute displacement and slope of the NACA 2-digit mean line.
@@ -410,6 +379,12 @@
 extern const fastf_t PSI7[];
 extern const fastf_t PSI8[];
 
+
+
+
+
+#endif /* NACA_H */
+
 /*
  * Local Variables:
  * tab-width: 8
Index: naca456.c
===================================================================
--- naca456.c	(revision 63769)
+++ naca456.c	(working copy)
@@ -38,14 +38,607 @@
  *
  */
 
+#include "common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
 #include "naca.h"
+#include "bu/malloc.h"
+#include "bu/str.h"
 
+/* Function forward-declarations */
+static void Welcome(void);
+static void ReadDataAndMakeAirfoils(void);
+static void PrintArraysNumbered(FILE *efu, struct fortran_array *x, struct fortran_array *y,
+				struct fortran_array *a, struct fortran_array *b, struct fortran_array *c, struct fortran_array *d);
+static void ScaleAirfoil(fastf_t scale, fastf_t xOrigin, fastf_t yOrigin,
+			 struct fortran_array *xupper, struct fortran_array *yupper, struct fortran_array *xlower, struct fortran_array *ylower);
+
+/* Global variables */
+static FILE *IN, *OUT, *DBG, *GNU;
+static char *dateTimeStr;
+
+const char *VERSION = "1.1 (7 November 2010)";
+
 int
-main(int argc, const char **argv)
+main(int UNUSED(argc), const char **UNUSED(argv))
 {
+    const char *FAREWELL = "End of naca456.  Files naca.out, naca.gnu and naca.dbg created.\n";
+    Welcome();
+    ReadDataAndMakeAirfoils();
+    printf("%s", FAREWELL);
     return 0;
 }
 
+/**
+ * Count the number of elements of an array that have been input thru
+ * a NAMELIST call.  This is to save the user from the error-prone
+ * process of counting the number of entries in a list.  The array is
+ * preset to a very negative value that no one would ever use for real
+ * data.  This routine simply searches for the first entry in the
+ * array that still has this value.
+ *
+ * @param[in] preset the value that was originally placed in each
+ * @param[in] a array to be counted
+ */
+static int
+CountInputArray(fastf_t preset, struct fortran_array *a)
+{
+    int k, n;
+    n = SIZE(a);
+
+    for (k = 1; k <= n; k++) {
+	if (INDEX(a, k) <= preset) {
+	    break;
+	}
+    }
+    n = k - 1; /* failed on k; k - 1 was the last good one */
+    return n;
+}
+
+/**
+ * Print a description of the mean line in the printed output
+ */
+static void
+DescribeMeanLine(FILE *efu, const char *camber, fastf_t cmax, fastf_t xmaxc, fastf_t a, fastf_t cl)
+{
+    const char *FMT2 = " Two digit mean line,  max camber=%6.3f  x of max. camber=%6.3f\n";
+    const char *FMT3 = " Three digit mean line, cl=%7.4f  x of max. camber=%6.3f\n";
+    const char *FMT3R = " Three digit mean line, cl=%7.4f  x of max. camber=%6.3f\n";
+    const char *FMT6 = " Six-series mean line, a=%7.4f   cl=%7.4f\n";
+    const char *FMT6M = " Six-series mean line (modified), cl=%7.4f  (a=0.8 always for 6M)\n";
+
+    switch(camber[0]) {
+    case '0':
+	fprintf(efu, " No camber, symmetrical section\n");
+	break;
+    case '2':
+	fprintf(efu, FMT2, cmax, xmaxc);
+	break;
+    case '3':
+	if (!bu_strcasecmp(camber, "3")) {
+	    fprintf(efu, FMT3, cl, xmaxc);
+	} else if (!bu_strcasecmp(camber, "3R")) {
+	    fprintf(efu, FMT3R, cl, xmaxc);
+	}
+	break;
+    case '6':
+	if (!bu_strcasecmp(camber, "6")) {
+	    fprintf(efu, FMT6, a, cl);
+	} else if (!bu_strcasecmp(camber, "6M")) {
+	    fprintf(efu, FMT6M, cl);
+	}
+	break;
+    }
+}
+
+/**
+ * Print a description of the profile in the printed output
+ */
+static void
+DescribeProfile(FILE *efu, const char *profile, fastf_t toc, fastf_t leIndex, fastf_t xmaxt)
+{
+    const char *FMT4 = "Four-digit profile, t/c=%7.4f\n";
+    const char *FMT4M = "Four-digit-modified profile, t/c=%7.4f\n   l.e. index=%7.4f   x of max. thickness=%7.4f\n";
+    const char *FMT6 = "Six-series profile, family= %s   t/c=%7.4f\n";
+
+    if (!bu_strcasecmp(profile, "4")) {
+	fprintf(efu, FMT4, toc);
+    } else if (!bu_strcasecmp(profile, "4M")) {
+	fprintf(efu, FMT4M, toc, leIndex, xmaxt);
+    } else {
+	fprintf(efu, FMT6, profile, toc);
+    }
+}
+
+/**
+ * Return a string with the current date and time.  You can change the
+ * first I2.2 below to I2 if you don't like a leading zero on early
+ * morning times, i.e., 6:45 instead of 06:45.
+ */
+static char *
+GetDateTimeStr(void)
+{
+    const char MONTH[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+    char *str = (char *)bu_malloc(sizeof(char) * 16, "GetDateTimeStr");
+    time_t current_time_t = time(NULL);
+    struct tm *current_time = localtime(&current_time_t);
+    char *current_month = (char *)bu_malloc(sizeof(char) * 4, "GetDateTimeStr");
+    bu_strlcpy(current_month, MONTH + current_time->tm_mon * 3, 4);
+
+    sprintf(str, "%2.2d:%2.2d%3d%3s%4d", current_time->tm_hour, current_time->tm_min, current_time->tm_mday, current_month, 1900 + current_time->tm_year);
+    return str;
+}
+
+/**
+ * Read data from the input file and define an airfoil.
+ */
+static void
+ReadDataAndMakeAirfoils(void)
+{
+
+    int i;
+    int len;
+    char *in;
+
+    fastf_t a; /* chordwise extent of constant loading */
+    char *camber = "0"; /* Camber line (2-digit or 3-digit;
+		 = '0' no camber
+		 = '2' 2-digit mean line
+		 = '3' 3-digit mean line
+		 = '3R' 3-digit reflex mean line
+		 = '6' 6-series mean line
+		 = '6M' 6-series (modified) mean line */
+    fastf_t chord = 1.0; /* model chord length used for listing ordinates */
+    fastf_t cl; /* design lift coefficient of the camber line
+		   applies to 3-digit, 3-digit-reflex and
+		   6-series camber lines */
+    fastf_t cmax = 0.04; /* maximum camber ordinate-to-chord ratio */
+    int denCode = 1; /* =0 if specified by the user
+			=1 for coarse output
+			=2 for fine output
+			=3 for very fine output */
+    int errCode;
+    fastf_t leIndex = 6.0; /* leading-edge index (4-digit modified) */
+    char *name; /* title desired on output */
+    int nTable = 1; /* size of xTable (only used if denCode = 0) */
+    const fastf_t PRESET = -1e20;
+    const char *profile  = "4"; /* NACA airfoil family
+			 = '4' four digit profile
+			 = '4M' modified-four-digit profile
+			 = '63' 63 series profile
+			 = '64' 64 series profile
+			 = '65' 65 series profile
+			 = '66' 66 series profile
+			 = '67' 67 series profile
+			 = '63A' 63A series profile
+			 = '64A' 64A series profile
+			 = '65A' 65A series profile */
+    fastf_t toc = 0.1; /* thickness-chord ratio of airfoil. */
+    fastf_t xmaxc = 0.4; /* location of maximum camber position
+			    used for 2-,3- and 3-digit-reflex mean lines */
+    fastf_t xmaxt = 0.3; /* location of maximum camber position
+			    used for 2-,3- and 3-digit-reflex mean lines */
+    fastf_t xOrigin = 0.0, yOrigin = 0.0; /* leading edge point */
+    double C_xTable[1000];
+    struct fortran_array *xTable;
+
+    struct fortran_array *x, *ymean, *ymeanp, *yt, *ytp;
+    fastf_t yMeanMax = -INFINITY;
+    struct fortran_array *xUpper, *xLower, *yUpper, *yLower;
+    struct fortran_array *yu, *yl, *yup, *ylp;
+
+    const char *TITLE1 = "COORDINATES OF NACA AIRFOILS";
+    const char *TITLE2 = "SYMMETRICAL AIRFOIL DEFINITION";
+    const char *TITLE3 = "x         y        dy/dx";
+    const char *TITLE4 = "THICKNESS          MEAN LINE";
+    const char *TITLE5 = "x         y      dy/dx         y      dy/dx";
+    const char *TITLE6 = "COMBINED THICKNESS AND CAMBER";
+    const char *TITLE7 = "xupper    yupper    xlower    ylower";
+    const char *TITLE8 = "INTERPOLATED COORDINATES";
+    const char *TITLE9 = "x      yupper   ylower";
+    const char *TITLE10 = "SCALED AND TRANSLATED AIRFOIL";
+    const char *FMT1 = "Scaled chord length=%12.5f\n";
+    const char *FMT2 = "   leading edge at x=%12.5f   y=%12.5f\n";
+
+    NL_ENTRY_DECLARE7(a, camber, chord, cl, cmax, denCode, leIndex);
+    NL_ENTRY_DECLARE7(name, profile, toc, xmaxc, xmaxt, xOrigin, yOrigin);
+    NL_ARRAY_DECLARE(C_xTable);
+    NAMELIST(nl, 15);
+
+    NL_ENTRY(nl, 0, a, scan_fastf_t, "%lf");
+    NL_ENTRY(nl, 1, camber, scan_string, NULL);
+    NL_ENTRY(nl, 2, chord, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 3, cl, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 4, cmax, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 5, denCode, scan_single_value, "%d");
+    NL_ENTRY(nl, 6, leIndex, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 7, name, scan_string, NULL);
+    NL_ENTRY(nl, 8, profile, scan_string, NULL);
+    NL_ENTRY(nl, 9, toc, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 10, xmaxc, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 11, xmaxt, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 12, xOrigin, scan_fastf_t, NULL);
+    NL_ENTRY(nl, 13, yOrigin, scan_fastf_t, NULL);
+
+    NL_ARRAY_ENTRY(nl, 14, C_xTable, 1000, sizeof(double), scan_fastf_t, NULL);
+
+    for (i = 0; i < 1000; i++) {
+	C_xTable[i] = PRESET;
+    }
+    fseek(IN, 0L, SEEK_END);
+    len = ftell(IN);
+    fseek(IN, 0L, SEEK_SET);
+    in = (char *)bu_malloc(len, "ReadDataAndMakeAirfoils");
+    fread(in, sizeof(char), len, IN);
+
+    errCode = read_namelist(in, "NACA", &nl);
+    if (errCode < 1) {
+	printf("End of file reading input\n");
+	fprintf(DBG, "End of file reading input\n");
+	fprintf(OUT, "End of file reading input\n");
+	exit(1);
+    }
+    fprintf(DBG, " Namelist read successfully\n");
+    fprintf(DBG, " %s\n", name);
+
+    if (denCode == 0) {
+	C2F(xTable, C_xTable, 1000);
+	nTable = CountInputArray(PRESET, xTable);
+    } else {
+	ALLOCATE(xTable, 1000);
+	LoadX(denCode, &nTable, xTable);
+    }
+
+    fprintf(DBG, " Allocating x,ymean,... with denCode=%11s%d\n", "", denCode);
+    ALLOCATE(x, nTable);
+    ALLOCATE(ymean, nTable);
+    ALLOCATE(ymeanp, nTable);
+    ALLOCATE(yt, nTable);
+    ALLOCATE(ytp, nTable);
+    ALLOCATE(xUpper, nTable);
+    ALLOCATE(yUpper, nTable);
+    ALLOCATE(xLower, nTable);
+    ALLOCATE(yLower, nTable);
+
+    SLICE(x, xTable, 1, nTable);
+    fprintf(DBG, " nTable is now%11s%d\n", "", nTable);
+
+    fprintf(DBG, " THICKNESS DEFINITION\n");
+    if (!bu_strcasecmp(profile, "4")) {
+	fprintf(DBG, " Four-digit profile\n");
+	Thickness4(toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "4M")) {
+	fprintf(DBG, " Four-digit modified profile %f %f\n", leIndex, xmaxt);
+	Thickness4M(toc, leIndex, xmaxt, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "63")) {
+	fprintf(DBG, " 63-series profile\n");
+	Thickness6(1, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "64")) {
+	fprintf(DBG, " 64-series profile\n");
+	Thickness6(2, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "65")) {
+	fprintf(DBG, " 65-series profile\n");
+	Thickness6(3, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "66")) {
+	fprintf(DBG, " 66-series profile\n");
+	Thickness6(4, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "67")) {
+	fprintf(DBG, " 67-series profile\n");
+	Thickness6(5, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "63A")) {
+	fprintf(DBG, " 63A-series profile\n");
+	Thickness6(6, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "64A")) {
+	fprintf(DBG, " 64A-series profile\n");
+	Thickness6(7, toc, x, yt, ytp, NULL);
+    } else if (!bu_strcasecmp(profile, "65A")) {
+	fprintf(DBG, " 65A-series profile\n");
+	Thickness6(8, toc, x, yt, ytp, NULL);
+    } else {
+	printf("Not a valid profile: %s", profile);
+	fprintf(DBG, " Not a valid profile: %s", profile);
+	exit(1);
+    }
+
+    fprintf(DBG, "           x         y        dy/dx\n");
+    PrintArraysNumbered(DBG, x, yt, ytp, NULL, NULL, NULL);
+    if (!bu_strcasecmp(camber, "0")) {
+	fprintf(DBG, " No camber\n");
+	for (i = 1; i <= nTable; i++) {
+	    INDEX(ymean, i) = 0.0;
+	    INDEX(ymeanp, i) = 0.0;
+	}
+    } else if (!bu_strcasecmp(camber, "2")) {
+	fprintf(DBG, " Two digit mean line %f %f\n", xmaxc, cmax);
+	MeanLine2(cmax, xmaxc, x, ymean, ymeanp);
+    } else if (!bu_strcasecmp(camber, "3")) {
+	fprintf(DBG, " Three digit camber line\n");
+	MeanLine3(cl, xmaxc, x, ymean, ymeanp);
+    } else if (!bu_strcasecmp(camber, "3R")) {
+	fprintf(DBG, " Three digit (reflex) camber line\n");
+	MeanLine3Reflex(cl, xmaxc, x, ymean, ymeanp);
+    } else if (!bu_strcasecmp(camber, "6")) {
+	fprintf(DBG, " 6-series camber line\n");
+	MeanLine6(a, cl, x, ymean, ymeanp);
+    } else if (!bu_strcasecmp(camber, "6A") || !bu_strcasecmp(camber, "6M")) {
+	fprintf(DBG, " 6A-series camber line\n");
+	MeanLine6M(cl, x, ymean, ymeanp);
+    } else {
+	printf("Not a valid mean line: %s\n", camber);
+	fprintf(DBG, " Not a valid mean line: %s\n", camber);
+    }
+
+    for (i = 1; i <= nTable; i++) {
+	V_MAX(yMeanMax, fabs(INDEX(ymean, i)));
+    }
+    if (ZERO(yMeanMax)) {
+	struct fortran_array *minus_yt;
+	ALLOCATE(minus_yt, nTable);
+	VSCALEN(F2C(minus_yt), F2C(yt), -1, nTable);
+	fprintf(OUT, "%s\n", name);
+	DescribeProfile(OUT, profile, toc, leIndex, xmaxt);
+	DescribeMeanLine(OUT, camber, cmax, xmaxc, a, cl);
+	fprintf(OUT, " %s\n", TITLE2);
+	fprintf(OUT, "        %s\n", TITLE3);
+	PrintArraysNumbered(OUT, x, yt, ytp, NULL, NULL, NULL);
+	ScaleAirfoil(chord, xOrigin, yOrigin, x, yt, x, minus_yt);
+	fprintf(OUT, " End of output for symmetrical airfoil\n");
+	return;
+    }
+
+    fprintf(DBG, "MEAN LINE DEFINITION\n");
+    fprintf(DBG, "         x          y        dy/dx\n");
+    PrintArraysNumbered(DBG, x, ymean, ymeanp, NULL, NULL, NULL);
+    fprintf(OUT, " \n");
+    fprintf(OUT, " %s\n", name);
+    DescribeProfile(OUT, profile, toc, leIndex, xmaxt);
+    DescribeMeanLine(OUT, camber, cmax, xmaxc, a, cl);
+    fprintf(OUT, " \n");
+
+    fprintf(OUT, "                       %s\n", TITLE4);
+    fprintf(OUT, "            %s\n", TITLE5);
+    PrintArraysNumbered(OUT, x, yt, ytp, ymean, ymeanp, NULL);
+    CombineThicknessAndCamber(x, yt, ymean, ymeanp, xUpper, yUpper, xLower, yLower);
+    fprintf(DBG, "%s\n", TITLE6);
+    fprintf(DBG, "        %s\n", TITLE7);
+    PrintArraysNumbered(DBG, xUpper, yUpper, xLower, yLower, NULL, NULL);
+    fprintf(OUT, "\f\n");
+    /* dateTimeStr should start in the 40th column, so there need to
+     * be 39 chars printed; TITLE1 contains 28, so there should be 11
+     * left, which is why the length modifier for the empty string is
+     * 11.
+     */
+    fprintf(OUT, "%s%11s%s\n", TITLE1, "", dateTimeStr);
+    fprintf(OUT, "%s\n", name);
+    fprintf(OUT, "%s\n", TITLE6);
+    fprintf(OUT, "            %s\n", TITLE7);
+
+    PrintArraysNumbered(OUT, xUpper, yUpper, xLower, yLower, NULL, NULL);
+    ALLOCATE(yu, nTable);
+    ALLOCATE(yl, nTable);
+    ALLOCATE(yup, nTable);
+    ALLOCATE(ylp, nTable);
+    InterpolateUpperAndLower(xUpper, yUpper, xLower, yLower, x, yu, yl, yup, ylp);
+
+    fprintf(OUT, "\f\n");
+    /* See the comment above for an explanation of the 11. */
+    fprintf(OUT, "%s%11s%s\n", TITLE1, "", dateTimeStr);
+    fprintf(OUT, "%s\n", name);
+    fprintf(OUT, "%s\n", TITLE8);
+    fprintf(OUT, "            %s\n", TITLE9);
+
+    PrintArraysNumbered(DBG, x, yu, yup, yl, ylp, NULL);
+    PrintArraysNumbered(OUT, x, yu, yl, NULL, NULL, NULL);
+
+    if (!ZERO(xOrigin) || !ZERO(yOrigin) || fabs(chord - 1.0) > 1e-6) {
+	fprintf(OUT, "\f\n");
+	/* See the comment above for an explanation of the 11. */
+	fprintf(OUT, "%s%11s%s\n", TITLE1, "", dateTimeStr);
+	fprintf(OUT, "%s\n", name);
+	fprintf(OUT, FMT1, chord);
+	fprintf(OUT, FMT2, xOrigin, yOrigin);
+	fprintf(OUT, "%s\n", TITLE10);
+	fprintf(OUT, "         %s\n", TITLE7);
+    }
+    ScaleAirfoil(chord, xOrigin, yOrigin, x, yu, x, yl);
+
+    DEALLOCATE(ylp);
+    DEALLOCATE(yup);
+    DEALLOCATE(yl);
+    DEALLOCATE(yu);
+    DEALLOCATE(yLower);
+    DEALLOCATE(xLower);
+    DEALLOCATE(yUpper);
+    DEALLOCATE(xUpper);
+    DEALLOCATE(ytp);
+    DEALLOCATE(yt);
+    DEALLOCATE(ymeanp);
+    DEALLOCATE(ymean);
+    DEALLOCATE(xTable);
+
+    fprintf(OUT, "End of output for cambered airfoil\n");
+}
+
+static char *
+Trim(char *s)
+{
+    int j;
+    char c;
+
+    /* Move input past any leading spaces */
+    while (isspace(*s++)) {}
+    s--;
+
+    /* Add a terminating null after the last non-space non-null byte */
+    for (j = strlen(s); isspace(c = s[j]) || c == '\0'; j--) {}
+    s[j+1] = '\0';
+
+    return s;
+}
+
+/**
+ * Print arrays, neatly formatted.  X and Y are always printed.  The
+ * next 4 optional variables are printed when present.
+ */
+static void
+PrintArrays(FILE *efu, struct fortran_array *x, struct fortran_array *y,
+	    struct fortran_array *a, struct fortran_array *b, struct fortran_array *c, struct fortran_array *d)
+{
+    char *buffer = (char *)bu_malloc(80, "PrintArrays");
+    int k, j;
+    char ch;
+    VSETALLN(buffer, 0, 80);
+    for (k = 1; k <= SIZE(x); k++) {
+	snprintf(buffer, 21, "%10.6f%10.6f", INDEX(x, k), INDEX(y, k));
+	if (a) {
+	    /* Recreate the behavior of printing stars for numbers
+	     * that are too large.
+	     */
+	    if (INDEX(a, k) > 999) {
+		snprintf(buffer + 20, 11, "**********");
+	    } else {
+		snprintf(buffer + 20, 11, "%10.6f", INDEX(a, k));
+	    }
+	}
+	if (b) { snprintf(buffer + 30, 11, "%10.6f", INDEX(b, k)); }
+	if (c) { snprintf(buffer + 40, 11, "%10.6f", INDEX(c, k)); }
+	if (d) { snprintf(buffer + 50, 11, "%10.6f", INDEX(d, k)); }
+	for (j = 79; isspace(ch = buffer[j]) || ch == '\0'; j--) {}
+	buffer[j + 1] = '\0';
+	fprintf(efu, " %s\n", buffer);
+    }
+}
+
+/**
+ * Print arrays, neatly formatted.  X and Y are always printed.  The
+ * next 4 optional variables are printed when present.
+ */
+static void
+PrintArraysNumbered(FILE *efu, struct fortran_array *x, struct fortran_array *y,
+		    struct fortran_array *a, struct fortran_array *b, struct fortran_array *c, struct fortran_array *d)
+{
+    char buffer[80];
+    int k, j;
+    char ch;
+    VSETALLN(buffer, 0, 80);
+    for (k = 1; k <= SIZE(x); k++) {
+	snprintf(buffer, 6, "%5d", k);
+	snprintf(buffer + 5, 21, "%10.6f%10.6f", INDEX(x, k), INDEX(y, k));
+	if (a) {
+	    /* Recreate the behavior of printing stars for numbers
+	     * that are too large.
+	     */
+	    if (INDEX(a, k) > 999) {
+		snprintf(buffer + 25, 11, "**********");
+	    } else {
+		snprintf(buffer + 25, 11, "%10.6f", INDEX(a, k));
+	    }
+	}
+	if (b) { snprintf(buffer + 35, 11, "%10.6f", INDEX(b, k)); }
+	if (c) { snprintf(buffer + 45, 11, "%10.6f", INDEX(c, k)); }
+	if (d) { snprintf(buffer + 55, 11, "%10.6f", INDEX(d, k)); }
+	for (j = 79; isspace(ch = buffer[j]) || ch == '\0'; j--) {}
+	fprintf(efu, " %s\n", buffer);
+    }
+}
+
+/**
+ * Translate and scale the airfoil.  If no scaling or translation is
+ * done, just return.
+ */
+static void
+ScaleAirfoil(fastf_t scale, fastf_t xOrigin, fastf_t yOrigin,
+	     struct fortran_array *xupper, struct fortran_array *yupper, struct fortran_array *xlower, struct fortran_array *ylower)
+{
+    struct fortran_array *xu, *yu, *xl, *yl;
+    int i;
+    ALLOCATE(xu, SIZE(xupper));
+    ALLOCATE(yu, SIZE(yupper));
+    ALLOCATE(xl, SIZE(xlower));
+    ALLOCATE(yl, SIZE(ylower));
+
+    for (i = 1; i <= SIZE(xupper); i++) {
+	INDEX(xu, i) = xOrigin + scale * INDEX(xupper, i);
+    }
+    for (i = 1; i <= SIZE(yupper); i++) {
+	INDEX(yu, i) = yOrigin + scale * INDEX(yupper, i);
+    }
+    for (i = 1; i <= SIZE(xlower); i++) {
+	INDEX(xl, i) = xOrigin + scale * INDEX(xlower, i);
+    }
+    for (i = 1; i <= SIZE(ylower); i++) {
+	INDEX(yl, i) = yOrigin + scale * INDEX(ylower, i);
+    }
+
+    if (!ZERO(xOrigin) || !ZERO(yOrigin) || fabs(scale - 1.0) > 1e-6) {
+	PrintArrays(OUT, xu, yu, xl, yl, NULL, NULL);
+    }
+
+    PrintArrays(GNU, xu, yu, NULL, NULL, NULL, NULL); /* Plot upper surface */
+    fprintf(GNU, "  \n"); /* Invisible move to start of lower surface */
+    PrintArrays(GNU, xl, yl, NULL, NULL, NULL, NULL); /* Plot lower surface */
+    fclose(GNU); /* Plot is complete */
+
+    return;
+}
+
+static void
+Welcome(void)
+{
+    const char *AUTHOR = "Ralph L. Carmichael, Public Domain Aeronautical Software";
+    char *fileName = (char *)bu_malloc(132, "naca456");
+    const char *GREETING = "COORDINATES OF NACA AIRFOILS";
+
+    dateTimeStr = GetDateTimeStr();
+
+    printf("%s\n", GREETING);
+    printf("Program naca456, version %s\n", VERSION);
+    printf("%s\n", AUTHOR);
+    while (1) {
+	char *fileNameWithExtension;
+	int len;
+	printf("Enter the name of the input file: ");
+	fgets(fileName, 132, stdin);
+	fileName = Trim(fileName);
+	len = strlen(fileName);
+	if (len == 0) {
+	    /* User gives up */
+	    exit(1);
+	}
+	IN = fopen(fileName, "r");
+	if (IN) { break; }
+	/* 5 for the .ext and the terminating null. */
+	fileNameWithExtension = (char *)bu_malloc(len + 5, "naca456");
+	bu_strlcpy(fileNameWithExtension, fileName, len + 1);
+	bu_strlcat(fileNameWithExtension, ".nml", len + 5);
+	IN = fopen(fileName, "r");
+	if (IN) { break; }
+	fileNameWithExtension[len + 1] = '\0';
+	bu_strlcat(fileNameWithExtension, ".inp", len + 5);
+	IN = fopen(fileName, "r");
+	if (IN) { break; }
+	printf("Unable to open %s.  Try again.\n", fileName);
+    }
+    printf("Reading from %s\n", fileName);
+    DBG = fopen("naca.dbg", "w");
+    fprintf(DBG, " %s\n", GREETING);
+    fprintf(DBG, " Created by naca456, version %s on %s\n", VERSION, dateTimeStr);
+    fprintf(DBG, " %s\n", AUTHOR);
+
+    OUT = fopen("naca.out", "w");
+    fprintf(OUT, " %s\n", GREETING);
+    fprintf(OUT, " Created by naca456, version %s on %s\n", VERSION, dateTimeStr);
+    fprintf(OUT, " %s\n", AUTHOR);
+
+    GNU = fopen("naca.gnu", "w");
+    return;
+}
+
 /*
  * Local Variables:
  * tab-width: 8
Index: nacax.c
===================================================================
--- nacax.c	(revision 63769)
+++ nacax.c	(working copy)
@@ -374,6 +374,7 @@
     struct fortran_array *xLocal, *yLocal, *sLocal, *xpLocal, *ypLocal;
     struct fortran_array *xLocal_start, *yLocal_start, *sLocal_start, *xpLocal_start, *ypLocal_start;
     struct fortran_array *xLocal_end, *yLocal_end, *sLocal_end, *xpLocal_end, *ypLocal_end;
+
     nupper = SIZE(xupper);
     nlower = SIZE(xlower);
     ALLOCATE(xupperCopy, nupper + 1);
@@ -523,7 +524,7 @@
 }
 
 void
-LoadX(int denCode, int nx, struct fortran_array *x)
+LoadX(int denCode, int *nx, struct fortran_array *x)
 {
     const fastf_t COARSE[26] = {0.0,0.005,0.0075,0.0125,
 				0.025,0.05,0.075,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,
@@ -545,16 +546,16 @@
 			      0.96,0.97,0.975,0.98,0.985,0.99,0.995,0.999,1.0};
     switch (denCode) {
     case 2:
-	nx = 26;
-	VMOVEN(F2C(x), MEDIUM, nx);
+	*nx = 64;
+	VMOVEN(F2C(x), MEDIUM, *nx);
 	break;
     case 3:
-	nx = 64;
-	VMOVEN(F2C(x), FINE, nx);
+	*nx = 98;
+	VMOVEN(F2C(x), FINE, *nx);
 	break;
     default: /* denCode = 1 and anything else (probably an accident) */
-	nx = 98;
-	VMOVEN(F2C(x), COARSE, nx);
+	*nx = 26;
+	VMOVEN(F2C(x), COARSE, *nx);
 	break;
     }
 }
@@ -838,7 +839,7 @@
     int j, n;
     n = SIZE(c);
     ff = INDEX(c, n);
-    for (j = n - 1; j <= 1; j--) {
+    for (j = n - 1; j >= 1; j--) {
 	ff = ff * x + INDEX(c, j);
     }
 
@@ -924,9 +925,9 @@
      * zfinal.  Return the real and imaginary parts as xt and yt.
      */
     for (i = 0; i < NP; i++) {
-	bn_cx_cons(&z[i], psi[0] * cos(phi[i]), exp(psi[0]) * sin(phi[i]));
+	bn_cx_cons(&z[i], exp(psi[0]) * cos(phi[i]), exp(psi[0]) * sin(phi[i]));
 	bn_cx_scal(&z[i], A);
-	bn_cx_cons(&zprime[i], exp(psi[i] - psi[0]) * cos(-eps[i]), exp(psi[i] - psi[i]) * sin(-eps[i]));
+	bn_cx_cons(&zprime[i], exp(psi[i] - psi[0]) * cos(-eps[i]), exp(psi[i] - psi[0]) * sin(-eps[i]));
 	bn_cx_mul(&zprime[i], &z[i]);
 	bn_cx_cons(&zeta[i], A * A, 0);
 	bn_cx_div(&zeta[i], &zprime[i]);
@@ -951,7 +952,7 @@
     const fastf_t A22 = A2 + A2;
     const fastf_t A3 = 0.2843;
     const fastf_t A33 = A3 + A3 + A3;
-    const fastf_t A4 = -0.1014;
+    const fastf_t A4 = -0.1015;
     const fastf_t A42 = A4 + A4, A44 = A42 + A42;
     int k, n;
     fastf_t srx, xx;
@@ -960,11 +961,11 @@
     if (yp) { INDEX(yp, 1) = 1e22; }
     if (ypp) { INDEX(ypp, 1) = -1e22; }
     for (k = 1; k <= n; k++) { /* based on t/c = 0.2 */
-	xx += INDEX(x, k);
+	xx = INDEX(x, k);
 	if (ZERO(xx)) {
 	    INDEX(y, k) = 0.0;
 	    if (yp) { INDEX(yp, k) = 1e22; }
-	    if (ypp) { INDEX(ypp, 1) = 1e22; }
+	    if (ypp) { INDEX(ypp, 1) = -1e22; }
 	} else {
 	    srx = sqrt(xx);
 	    INDEX(y, k) = A0 * srx + xx * (A1 + xx * (A2 + xx * (A3 + xx * A4)));
@@ -1001,7 +1002,7 @@
     A2 = CalA2(A0, A3, xmaxt);
     A1 = CalA1(A0, A2, A3, xmaxt);
     A22 = A2 + A2;
-    A33 = A3 + A3;
+    A33 = A3 + A3 + A3;
 
     omxmt = 1.0 - xmaxt; /* calculate the "d" constants" */
     omxmsq = omxmt * omxmt;
@@ -1056,7 +1057,7 @@
     if (yp) { INDEX(yp, 1) = 1e22; }
     if (ypp) { INDEX(ypp, 1) = 1e22; }
     for (k = 1; k <= n; k++) { /* based on t/c = 0.2 */
-	xx += INDEX(x, k);
+	xx = INDEX(x, k);
 	if (ZERO(xx)) {
 	    INDEX(y, k) = 0.0;
 	    if (yp) { INDEX(yp, k) = 1e22; }
Index: namelist.c
===================================================================
--- namelist.c	(revision 0)
+++ namelist.c	(working copy)
@@ -0,0 +1,314 @@
+/*                      N A M E L I S T . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2014 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @file namelist.c
+ *
+ * Brief description
+ *
+ */
+
+#include "common.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "bu/str.h"
+#include "bu/malloc.h"
+#include "bu/log.h"
+
+#include "naca.h"
+
+static const char *
+fill_entry(const char *input, struct namelist_entry *entry)
+{
+    return entry->scan_func(input, entry);
+}
+
+static const char *
+skip_spaces(const char *input)
+{
+    while (isspace(*input++)) {};
+    return input - 1;
+}
+
+const char *
+scan_single_value(const char *input, struct namelist_entry *entry)
+{
+    char *type_spec = (char *)entry->scan_func_data;
+    /* + 3 for the '%', the 'n', and the '\0' */
+    int format_spec_len = strlen(type_spec) + 3;
+    char *format_spec = (char *)bu_malloc(format_spec_len, "read_namelist");
+    int num_chars = 0;
+
+    bu_strlcpy(format_spec, type_spec, format_spec_len);
+    bu_strlcat(format_spec, "%n", format_spec_len);
+    sscanf(input, format_spec, entry->value, &num_chars);
+    bu_free(format_spec, "read_namelist");
+    return input + num_chars;
+}
+
+const char *
+scan_fastf_t(const char *input, struct namelist_entry *entry)
+{
+    double scanned_value;
+    int num_chars = 0;
+
+    sscanf(input, "%lf%n", &scanned_value, &num_chars);
+    *((fastf_t *)entry->value) = scanned_value;
+    return input + num_chars;
+}
+
+static int
+char_ends_str(const char c, int quoted, const char quote_char, int escaped)
+{
+    if(escaped) {
+	return 0;
+    }
+    if (quoted) {
+	return (c == quote_char || c == '\0');
+    } else {
+	return (c == '=' || c == ',' || c == '/' || c == '\0');
+    }
+    return 0;
+}
+
+const char *
+scan_string(const char *input, struct namelist_entry *entry)
+{
+    int quoted = (*input == '\'' || *input == '"');
+    char quote_char;
+    int escaped = 0;
+    /* Most of the variables that naca456 reads in are 3 or 4 chars
+     * long.
+     */
+    int value_size = 4;
+    char *value = (char *)bu_malloc(value_size, "read_namelist");
+    int i = 0;
+    char c;
+
+    if (quoted) { quote_char = *input++; }
+
+    c = *input;
+
+    while (!char_ends_str((c = *input++), quoted, quote_char, escaped)) {
+	if (i >= value_size) {
+	    value_size *= 2;
+	    value = (char *)bu_realloc(value, value_size, "read_namelist");
+	}
+	value[i++] = c;
+	/* Is the next char escaped? */
+	escaped = (c == '\\');
+    }
+
+    value[i] = '\0';
+
+    if (i) {
+	*(char **)(entry->value) = value;
+    } else {
+	bu_free(value, "read_namelist");
+    }
+    return input;
+}
+
+const char *
+scan_array(const char *input, struct namelist_entry *entry)
+{
+    int i;
+    /* This is used to keep track of multiple commas in a row (which
+     * represent null elements).  Initialized to 1 because '= ,'
+     * counts as a null element.
+     */
+    int seen_comma = 1;
+    struct scan_array_info *info = (struct scan_array_info *)entry->scan_func_data;
+    struct namelist_entry element;
+    element.value = entry->value;
+    element.scan_func = info->scan_func;
+    element.scan_func_data = info->scan_func_data;
+
+    for (i = 0; *input != '/' && *input != '\0' && i < info->max_num_elements; i++) {
+	const char *prev_input = input;
+	/* Check for the r* form */
+	int r, c;
+	int n = sscanf(input, "%d%n", &r, &c);
+	if (n) {
+	    input += c;
+	    input = skip_spaces(input);
+	    if (*input == '*') {
+		/* This is an r* form; is there a constant? */
+		input++;
+		input = skip_spaces(input);
+		prev_input = input;
+		input = fill_entry(input, &element);
+		if (prev_input != input) {
+		    /* There is a constant to set them all to */
+		    int j;
+		    for (j = 0; j < r; j++) {
+			memcpy((void*)((char*)element.value + info->size * j),
+			       element.value, info->size);
+		    }
+		}
+		/* The increment done at the end of the loop iteration
+		 * requires adds one more, making i = i + r.
+		 */
+		i += r - 1;
+		element.value = (void*)((char*)element.value + info->size * r);
+		info->num_scanned += r;
+		if ((seen_comma = *input) == ',') {
+		    input++;
+		    input = skip_spaces(input);
+		}
+		continue;
+	    } else {
+		input = prev_input;
+	    }
+	}
+
+	/* Two consective commas represent a null element; move on to
+	 * the next element in the array, and skip to the beginning of
+	 * the next element in the input stream
+	 */
+	if (seen_comma && *input == ',') {
+	    element.value = (void*)((char*)element.value + info->size);
+	    input++;
+	    input = skip_spaces(input);
+	    info->num_scanned++;
+	    continue;
+	}
+	input = fill_entry(input, &element);
+	info->num_scanned++;
+	element.value = (void*)((char*)element.value + info->size);
+	if (prev_input == input) {
+	    if (*input == '=') { info->num_scanned--; }
+	    while (*--input != ',') { }
+	    info->num_scanned--;
+	    return input;
+	}
+	input = skip_spaces(input);
+	if ((seen_comma = *input) == ',') {
+	    input++;
+	    input = skip_spaces(input);
+	}
+    }
+    if (*input == '=') {
+	while (*--input != ',') {}
+	info->num_scanned--;
+    }
+    return input;
+}
+
+static const char *
+get_entry(const char *input, struct namelist_entry **entry, const struct namelist *namelist)
+{
+    /* Should be large enough for most variable names while not
+     * wasting too much memory.
+     */
+    int name_size = 8;
+    char *name = (char *)bu_malloc(name_size, "read_namelist");
+    int i = 0, j;
+    char c = *input;
+
+    do {
+	if (i >= name_size) {
+	    name_size *= 2;
+	    name = (char *)bu_realloc(name, name_size, "read_namelist");
+	}
+	name[i++] = c;
+    } while (!isspace(c = *++input) && !(c == '='));
+
+    name[i] = '\0';
+
+    /* Iterate through the namelist to find the correct entry */
+    for (j = 0; j < namelist->num_entries; j++) {
+	if (bu_strncasecmp(name, namelist->entries[j]->name, i) == 0) {
+	    /* Found the entry */
+	    *entry = namelist->entries[j];
+	    break;
+	}
+    }
+    bu_free(name, "read_namelist");
+    return input;
+}
+
+int
+read_namelist(const char *input, char *group_name, const struct namelist *namelist)
+{
+    /* ignore everything up to the & */
+    while (*input++ != '&') {
+	/* If the file never contained a start of namelist. */
+	if (*input == '\0') { return 0; }
+    }
+
+    /* Ensure that the group_name is correct. */
+    if (bu_strncasecmp(input, group_name, strlen(group_name))) {
+	return 0;
+    }
+    input += strlen(group_name);
+
+    input = skip_spaces(input);
+
+    while (*input != '/' && *input != '\0') {
+	struct namelist_entry *entry = NULL;
+	/* Skip to the next varname */
+	input = skip_spaces(input);
+	input = get_entry(input, &entry, namelist);
+	/* If it doesn't exist, return failure */
+	if (entry == NULL) { return 0; }
+	/* Check the '=' */
+	input = skip_spaces(input);
+	if (*input++ != '=') { return 0; }
+	input = skip_spaces(input);
+	input = fill_entry(input, entry);
+	/* Skip past any other whitespace; if there is a comma, skip
+	 * it and then skip past any more whitespace --- if there is
+	 * another record, this moves to the beginning of the next
+	 * line, otherwise to the '/'
+	 */
+	input = skip_spaces(input);
+	if (*input == ',') {
+	    input++;
+	    input = skip_spaces(input);
+	}
+    }
+    return (*input == '/');
+}
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
Index: namelist.h
===================================================================
--- namelist.h	(revision 0)
+++ namelist.h	(working copy)
@@ -0,0 +1,192 @@
+/*                          N A M E L I S T . H
+ * BRL-CAD
+ *
+ * Copyright (c) 2014 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @file namelist.h
+ *
+ * This file contains a number of functions and structures related to
+ * reading in data in the format of Fortran namelists.
+ * Unfortunately, the namelist format seems to have been implemented
+ * differently in different compilers as a language extension prior to
+ * being standardized; emulating the exact quirks of any given
+ * implementation (or even the standard!) would be quite difficult.
+ * Instead, this set of functions just tries to be 'close enough' that
+ * it can read all of the example inputs for naca456 from
+ * http://www.pdas.com/naca456samples.html.
+ *
+ */
+
+#ifndef NAMELIST_H
+#define NAMELIST_H
+
+/* Convenience macros for setting up namelists */
+/*
+#define NL_ENTRY(var, func, data) \
+  struct namelist_entry _nle ## var = { #var, (void *)var, func, (void *)data };
+*/
+#define NL_ENTRY(nl, n, var, func, data)                \
+  _nle ## var.name = #var;                              \
+  _nle ## var.value = (void *)&var;                     \
+  _nle ## var.scan_func = (name_scan_func *)func;       \
+  _nle ## var.scan_func_data = (void *) data;           \
+  nl.entries[n] = &_nle ## var
+
+#define NL_ARRAY_ENTRY(nl, n, var, num_elements, _size, func, data)  \
+  _nle ## var ## info.max_num_elements = num_elements;               \
+  _nle ## var ## info.size = _size;                                  \
+  _nle ## var ## info.scan_func = (name_scan_func *)func;            \
+  _nle ## var ## info.scan_func_data = data;                         \
+  NL_ENTRY(nl, n, var, scan_array, &_nle ## var ## info)
+
+#define NL_ENTRY_DECLARE(var) \
+  struct namelist_entry _nle ## var
+#define NL_ENTRY_DECLARE7(var1, var2, var3, var4, var5, var6, var7)  \
+  NL_ENTRY_DECLARE(var1);                                            \
+  NL_ENTRY_DECLARE(var2);                                            \
+  NL_ENTRY_DECLARE(var3);                                            \
+  NL_ENTRY_DECLARE(var4);                                            \
+  NL_ENTRY_DECLARE(var5);                                            \
+  NL_ENTRY_DECLARE(var6);                                            \
+  NL_ENTRY_DECLARE(var7)
+
+#define NL_ARRAY_DECLARE(var)                   \
+  struct namelist_entry _nle ## var;            \
+  struct scan_array_info _nle ## var ## info
+
+#define NAMELIST(nl, num) \
+  struct namelist nl;     \
+  nl.num_entries = num;   \
+  nl.entries = (struct namelist_entry **)bu_calloc(sizeof(struct namelist_entry *), num, "namelist")
+
+/* Forward-declaration of struct namelist_entry to avoid circular
+ * dependencies with the type name_scan_func.
+ */
+struct namelist_entry;
+
+/**
+ * General type for functions that are used by read_namelist() to scan
+ * a given kind of value.
+ *
+ * Scanning functions should stop scanning if they encounter an
+ * un-escaped '='; this is especially important because it allows
+ * scan_array() to detect this case easily.
+ *
+ * @param[in] input The input string that contains the variable to be
+ *                  scanned; the terminating \0 is at the end of
+ *                  input.
+ * @param[in] entry A pointer to the struct namelist_entry for the
+ *                  value being scanned; the function should set the
+ *                  'value' member of entry to the scanned value.
+ *
+ * @returns A string starting at the end of the scanned value and
+ *          continuing to the end of input; should be a pointer into
+ *          'input'.
+ */
+typedef char *name_scan_func(const char *input, struct namelist_entry *entry);
+
+/**
+ * This struct represents a variable fed into the FORTRAN namelist
+ * statement.
+ */
+struct namelist_entry {
+  char *name;                /* The name for the variable given in the output */
+  void *value;               /* Pointer to the variable that should hold the value */
+  name_scan_func *scan_func; /* Function used to scan in the value */
+  void *scan_func_data;      /* Any other data necessary for the function */
+};
+
+/**
+ * A whole namelist, which consists of a collection of namelist
+ * entries along with a count of them.
+ */
+struct namelist {
+    int num_entries;
+    struct namelist_entry **entries;
+};
+
+/**
+ * A function for scanning in `single values' from the input stream.
+ * A `single value' is essentially a value that can be scanned by a
+ * single call to sscanf() with one format specifier into one
+ * variable, such as int, double, etc.  This expects the
+ * scan_func_data component of the entry to contain the
+ * correct format specifier.
+ */
+const char *scan_single_value(const char *input, struct namelist_entry *entry);
+
+/**
+ * A function to scan in a fastf_t value from the input stream;
+ * necessary because scanning to fastf_t requires first scanning into
+ * a double and then converting to a fastf_t.
+ */
+const char *scan_fastf_t(const char *input, struct namelist_entry *entry);
+
+/**
+ * A function for scanning in strings from the namelist input; this
+ * does not use the value in the scan_func_data member of the entry.
+ */
+const char *scan_string(const char *input, struct namelist_entry *entry);
+
+/**
+ * This is intended to be used as the scan_func_data argument of
+ * namelist_entries that use scan_array() to scan in the input data.
+ */
+struct scan_array_info
+{
+  int max_num_elements;
+  size_t size;               /* The size of a single element */
+  name_scan_func *scan_func; /* The function used to scan each element */
+  void *scan_func_data;
+  int num_scanned;           /* The number of elements actually scanned */
+};
+
+/**
+ * A function for scanning in arrays of data from the namelist input.
+ * Unfortunately, determining the end of an array appears to be
+ * somewhat difficult; this continues reading elements until either
+ * the scanning function doesn't consume any input (indicating an
+ * error), a '/', or a '=' sign is found.  If an '=' sign is found, it
+   removes
+ * the previous word from the array, since it is the name of the next
+ * variable.  scan_array() expects the scan_func_data element of
+ * namelist_entry to be a struct scan_array.
+ */
+const char *scan_array(const char *input, struct namelist_entry *entry);
+
+/**
+ * The main entry point for reading a namelist.  This scans the data
+ * from input into namelist, after checking that the group is correct.
+ */
+int read_namelist(const char *input, char *group_name, const struct namelist *namelist);
+
+#endif /* NAMELIST_H */
Index: splprocs.c
===================================================================
--- splprocs.c	(revision 63769)
+++ splprocs.c	(working copy)
@@ -117,9 +117,9 @@
     ALLOCATE(dx, n - 1);
     ALLOCATE(dy, n - 1);
     ALLOCATE(delta, n - 1);
-    VSUB2N(F2C(dx), F2CI(dx, 2), F2C(x), n - 1);
-    VSUB2N(F2C(dy), F2CI(dy, 2), F2C(y), n - 1);
-    for (i = 1; i <= n; i++) {
+    VSUB2N(F2C(dx), F2CI(x, 2), F2C(x), n - 1);
+    VSUB2N(F2C(dy), F2CI(y, 2), F2C(y), n - 1);
+    for (i = 1; i < n; i++) {
 	INDEX(delta, i) = INDEX(dy, i) / INDEX(dx, i);
     }
     if (n == 2) {
@@ -202,7 +202,7 @@
 {
     int n = SIZE(x);
     struct fortran_array *du;
-    fastf_t sum;
+    fastf_t sum = 0.0;
     int i, j;
     ALLOCATE(du, n);
     VSETALLN(F2C(du), u, n);
@@ -341,7 +341,7 @@
     j = Lookup(x, u);
     j = j - (m / 2 - 1);
     V_MIN(j, 1 + SIZE(x) - m); /* j + m - 1 must not exceed SIZE(x) */
-    V_MIN(j, 1); /* j must be positive */
+    V_MAX(j, 1); /* j must be positive */
     /* Use points j through j + m - 1 for interpolation (m points) */
     SLICE(xp, x, j, j + m - 1);
     SLICE(yp, y, j, j + m - 1);
