http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/6adc7977/tests/charmonizer.c
----------------------------------------------------------------------
diff --git a/tests/charmonizer.c b/tests/charmonizer.c
new file mode 100644
index 0000000..12bb2d9
--- /dev/null
+++ b/tests/charmonizer.c
@@ -0,0 +1,7910 @@
+/* This is an auto-generated file -- do not edit directly. */
+
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/Defines.h"
+/* Charmonizer/Core/Defines.h -- Universal definitions.
+ */
+#ifndef H_CHAZ_DEFINES
+#define H_CHAZ_DEFINES 1
+
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
+#define CHAZ_QUOTE(x) #x "\n"
+
+#endif /* H_CHAZ_DEFINES */
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/Library.h"
+/* Charmonizer/Core/Library.h
+ */
+
+#ifndef H_CHAZ_LIB
+#define H_CHAZ_LIB
+
+typedef struct chaz_Lib chaz_Lib;
+
+typedef enum {
+    chaz_Lib_SHARED = 1,
+    chaz_Lib_STATIC = 2
+} chaz_LibType;
+
+chaz_Lib*
+chaz_Lib_new(const char *name, chaz_LibType type, const char *version,
+             const char *major_version);
+
+void
+chaz_Lib_destroy(chaz_Lib *flags);
+
+const char*
+chaz_Lib_get_name(chaz_Lib *lib);
+
+const char*
+chaz_Lib_get_version(chaz_Lib *lib);
+
+const char*
+chaz_Lib_get_major_version(chaz_Lib *lib);
+
+int
+chaz_Lib_is_shared(chaz_Lib *lib);
+
+int
+chaz_Lib_is_static(chaz_Lib *lib);
+
+char*
+chaz_Lib_filename(chaz_Lib *lib);
+
+char*
+chaz_Lib_major_version_filename(chaz_Lib *lib);
+
+char*
+chaz_Lib_no_version_filename(chaz_Lib *lib);
+
+char*
+chaz_Lib_implib_filename(chaz_Lib *lib);
+
+char*
+chaz_Lib_export_filename(chaz_Lib *lib);
+
+#endif /* H_CHAZ_LIB */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/CFlags.h"
+/* Charmonizer/Core/CFlags.h
+ */
+
+#ifndef H_CHAZ_CFLAGS
+#define H_CHAZ_CFLAGS
+
+/* #include "Charmonizer/Core/Library.h" */
+
+#define CHAZ_CFLAGS_STYLE_POSIX  1
+#define CHAZ_CFLAGS_STYLE_GNU    2
+#define CHAZ_CFLAGS_STYLE_MSVC   3
+#define CHAZ_CFLAGS_STYLE_SUN_C  4
+
+typedef struct chaz_CFlags chaz_CFlags;
+
+chaz_CFlags*
+chaz_CFlags_new(int style);
+
+void
+chaz_CFlags_destroy(chaz_CFlags *flags);
+
+const char*
+chaz_CFlags_get_string(chaz_CFlags *flags);
+
+void
+chaz_CFlags_append(chaz_CFlags *flags, const char *string);
+
+void
+chaz_CFlags_clear(chaz_CFlags *flags);
+
+void
+chaz_CFlags_set_output_obj(chaz_CFlags *flags, const char *filename);
+
+void
+chaz_CFlags_set_output_exe(chaz_CFlags *flags, const char *filename);
+
+void
+chaz_CFlags_add_define(chaz_CFlags *flags, const char *name,
+                       const char *value);
+
+void
+chaz_CFlags_add_include_dir(chaz_CFlags *flags, const char *dir);
+
+void
+chaz_CFlags_enable_optimization(chaz_CFlags *flags);
+
+void
+chaz_CFlags_disable_strict_aliasing(chaz_CFlags *flags);
+
+void
+chaz_CFlags_set_warnings_as_errors(chaz_CFlags *flags);
+
+void
+chaz_CFlags_compile_shared_library(chaz_CFlags *flags);
+
+void
+chaz_CFlags_hide_symbols(chaz_CFlags *flags);
+
+void
+chaz_CFlags_link_shared_library(chaz_CFlags *flags);
+
+void
+chaz_CFlags_set_shared_library_version(chaz_CFlags *flags, chaz_Lib *lib);
+
+void
+chaz_CFlags_set_link_output(chaz_CFlags *flags, const char *filename);
+
+void
+chaz_CFlags_add_library_path(chaz_CFlags *flags, const char *directory);
+
+void
+chaz_CFlags_add_library(chaz_CFlags *flags, chaz_Lib *lib);
+
+void
+chaz_CFlags_add_external_library(chaz_CFlags *flags, const char *library);
+
+void
+chaz_CFlags_enable_code_coverage(chaz_CFlags *flags);
+
+#endif /* H_CHAZ_CFLAGS */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/CLI.h"
+#ifndef H_CHAZ_CLI
+#define H_CHAZ_CLI 1
+
+#define CHAZ_CLI_NO_ARG       0
+#define CHAZ_CLI_ARG_REQUIRED (1 << 0)
+#define CHAZ_CLI_ARG_OPTIONAL (1 << 1)
+
+/* The CLI module provides argument parsing for a command line interface.
+ */
+
+typedef struct chaz_CLI chaz_CLI;
+
+/* Constructor.
+ *
+ * @param name The name of the application.
+ * @param description A description of the application.
+ */
+chaz_CLI*
+chaz_CLI_new(const char *name, const char *description);
+
+/* Destructor.
+ */
+void
+chaz_CLI_destroy(chaz_CLI *self);
+
+/* Return a string combining usage header with documentation of options.
+ */
+const char*
+chaz_CLI_help(chaz_CLI *self);
+
+/* Override the generated usage header.
+ */
+void
+chaz_CLI_set_usage(chaz_CLI *self, const char *usage);
+
+/* Register an option.  Updates the "help" string, invalidating previous
+ * values.  Returns true on success, or reports an error and returns false if
+ * the option was already registered.
+ */
+int
+chaz_CLI_register(chaz_CLI *self, const char *name, const char *help,
+                  int flags);
+
+/* Set an option.  The specified option must have been registered previously.
+ * The supplied `value` is optional and will be copied.
+ *
+ * Returns true on success.  Reports an error and returns false on failure.
+ */
+int
+chaz_CLI_set(chaz_CLI *self, const char *name, const char *value);
+
+/* Returns true if the option has been set, false otherwise.
+ */
+int
+chaz_CLI_defined(chaz_CLI *self, const char *name);
+
+/* Return the value of a given option converted to a long int.  Defaults to 0.
+ * Reports an error if the named option has not been registered.
+ */
+long
+chaz_CLI_longval(chaz_CLI *self, const char *name);
+
+/* Return the value of an option as a C string.  Defaults to NULL.  Reports an
+ * error if the named option has not been registered.
+ */
+const char*
+chaz_CLI_strval(chaz_CLI *self, const char *name);
+
+/* Unset an option, making subsequent calls to `get` return false and making
+ * it possible to call `set` again.
+ *
+ * Returns true if the option exists and was able to be unset.
+ */
+int
+chaz_CLI_unset(chaz_CLI *self, const char *name);
+
+/* Parse `argc` and `argv`, setting options as appropriate.  Returns true on
+ * success.  Reports an error and returns false if either an unexpected option
+ * was encountered or an option which requires an argument was supplied
+ * without one.
+ */
+int
+chaz_CLI_parse(chaz_CLI *self, int argc, const char *argv[]);
+
+#endif /* H_CHAZ_CLI */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/Compiler.h"
+/* Charmonizer/Core/Compiler.h
+ */
+
+#ifndef H_CHAZ_COMPILER
+#define H_CHAZ_COMPILER
+
+#include <stddef.h>
+/* #include "Charmonizer/Core/Defines.h" */
+/* #include "Charmonizer/Core/CFlags.h" */
+
+/* Attempt to compile and link an executable.  Return true if the executable
+ * file exists after the attempt.
+ */
+int
+chaz_CC_compile_exe(const char *source_path, const char *exe_path,
+                    const char *code);
+
+/* Attempt to compile an object file.  Return true if the object file
+ * exists after the attempt.
+ */
+int
+chaz_CC_compile_obj(const char *source_path, const char *obj_path,
+                    const char *code);
+
+/* Attempt to compile the supplied source code and return true if the
+ * effort succeeds.
+ */
+int
+chaz_CC_test_compile(const char *source);
+
+/* Attempt to compile the supplied source code.  If successful, capture the
+ * output of the program and return a pointer to a newly allocated buffer.
+ * If the compilation fails, return NULL.  The length of the captured
+ * output will be placed into the integer pointed to by [output_len].
+ */
+char*
+chaz_CC_capture_output(const char *source, size_t *output_len);
+
+/** Initialize the compiler environment.
+ */
+void
+chaz_CC_init(const char *cc_command, const char *cflags);
+
+/* Clean up the environment.
+ */
+void
+chaz_CC_clean_up(void);
+
+/* Accessor for the compiler executable's string representation.
+ */
+const char*
+chaz_CC_get_cc(void);
+
+/* Accessor for `cflags`.
+ */
+const char*
+chaz_CC_get_cflags(void);
+
+/* Accessor for `extra_cflags`.
+ */
+chaz_CFlags*
+chaz_CC_get_extra_cflags(void);
+
+/* Accessor for `temp_cflags`.
+ */
+chaz_CFlags*
+chaz_CC_get_temp_cflags(void);
+
+/* Return a new CFlags object.
+ */
+chaz_CFlags*
+chaz_CC_new_cflags(void);
+
+/* Return the extension for a compiled object.
+ */
+const char*
+chaz_CC_obj_ext(void);
+
+int
+chaz_CC_gcc_version_num(void);
+
+const char*
+chaz_CC_gcc_version(void);
+
+int
+chaz_CC_msvc_version_num(void);
+
+int
+chaz_CC_sun_c_version_num(void);
+
+const char*
+chaz_CC_link_command(void);
+
+/* Create a command for building a static library.
+ *
+ * @param target The target library filename.
+ * @param objects The list of object files to be archived in the library.
+ */
+char*
+chaz_CC_format_archiver_command(const char *target, const char *objects);
+
+/* Returns a "ranlib" command if valid.
+ *
+ * @param target The library filename.
+ */
+char*
+chaz_CC_format_ranlib_command(const char *target);
+
+#endif /* H_CHAZ_COMPILER */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/ConfWriter.h"
+/* Charmonizer/Core/ConfWriter.h -- Write to a config file.
+ */
+
+#ifndef H_CHAZ_CONFWRITER
+#define H_CHAZ_CONFWRITER 1
+
+#include <stddef.h>
+#include <stdarg.h>
+/* #include "Charmonizer/Core/Defines.h" */
+
+struct chaz_ConfWriter;
+
+/* Initialize elements needed by ConfWriter.  Must be called before anything
+ * else, but after os and compiler are initialized.
+ */
+void
+chaz_ConfWriter_init(void);
+
+/* Close the include guard on charmony.h, then close the file.  Delete temp
+ * files and perform any other needed cleanup.
+ */
+void
+chaz_ConfWriter_clean_up(void);
+
+/* Print output to charmony.h.
+ */
+void
+chaz_ConfWriter_append_conf(const char *fmt, ...);
+
+/* Add a pound-define.
+ */
+void
+chaz_ConfWriter_add_def(const char *sym, const char *value);
+
+/* Add a globally scoped pound-define.
+ */
+void
+chaz_ConfWriter_add_global_def(const char *sym, const char *value);
+
+/* Add a typedef.
+ */
+void
+chaz_ConfWriter_add_typedef(const char *type, const char *alias);
+
+/* Add a globally scoped typedef.
+ */
+void
+chaz_ConfWriter_add_global_typedef(const char *type, const char *alias);
+
+/* Pound-include a system header (within angle brackets).
+ */
+void
+chaz_ConfWriter_add_sys_include(const char *header);
+
+/* Pound-include a locally created header (within quotes).
+ */
+void
+chaz_ConfWriter_add_local_include(const char *header);
+
+/* Print a "chapter heading" comment in the conf file when starting a module.
+ */
+void
+chaz_ConfWriter_start_module(const char *module_name);
+
+/* Leave a little whitespace at the end of each module.
+ */
+void
+chaz_ConfWriter_end_module(void);
+
+void
+chaz_ConfWriter_add_writer(struct chaz_ConfWriter *writer);
+
+typedef void
+(*chaz_ConfWriter_clean_up_t)(void);
+typedef void
+(*chaz_ConfWriter_vappend_conf_t)(const char *fmt, va_list args); 
+typedef void
+(*chaz_ConfWriter_add_def_t)(const char *sym, const char *value);
+typedef void
+(*chaz_ConfWriter_add_global_def_t)(const char *sym, const char *value);
+typedef void
+(*chaz_ConfWriter_add_typedef_t)(const char *type, const char *alias);
+typedef void
+(*chaz_ConfWriter_add_global_typedef_t)(const char *type, const char *alias);
+typedef void
+(*chaz_ConfWriter_add_sys_include_t)(const char *header);
+typedef void
+(*chaz_ConfWriter_add_local_include_t)(const char *header);
+typedef void
+(*chaz_ConfWriter_start_module_t)(const char *module_name);
+typedef void
+(*chaz_ConfWriter_end_module_t)(void);
+typedef struct chaz_ConfWriter {
+    chaz_ConfWriter_clean_up_t           clean_up;
+    chaz_ConfWriter_vappend_conf_t       vappend_conf;
+    chaz_ConfWriter_add_def_t            add_def;
+    chaz_ConfWriter_add_global_def_t     add_global_def;
+    chaz_ConfWriter_add_typedef_t        add_typedef;
+    chaz_ConfWriter_add_global_typedef_t add_global_typedef;
+    chaz_ConfWriter_add_sys_include_t    add_sys_include;
+    chaz_ConfWriter_add_local_include_t  add_local_include;
+    chaz_ConfWriter_start_module_t       start_module;
+    chaz_ConfWriter_end_module_t         end_module;
+} chaz_ConfWriter;
+
+#endif /* H_CHAZ_CONFWRITER */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/ConfWriterC.h"
+/* Charmonizer/Core/ConfWriterC.h -- Write to a C header file.
+ */
+
+#ifndef H_CHAZ_CONFWRITERC
+#define H_CHAZ_CONFWRITERC 1
+
+/* Enable writing config to a C header file.
+ */
+void
+chaz_ConfWriterC_enable(void);
+
+#endif /* H_CHAZ_CONFWRITERC */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/ConfWriterPerl.h"
+/* Charmonizer/Core/ConfWriterPerl.h -- Write to a Perl module file.
+ */
+
+#ifndef H_CHAZ_CONFWRITERPERL
+#define H_CHAZ_CONFWRITERPERL 1
+
+/* Enable writing config to a Perl module file.
+ */
+void
+chaz_ConfWriterPerl_enable(void);
+
+#endif /* H_CHAZ_CONFWRITERPERL */
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/ConfWriterPython.h"
+/* Charmonizer/Core/ConfWriterPython.h -- Write to a Python module file.
+ */
+
+#ifndef H_CHAZ_CONFWRITERPYTHON
+#define H_CHAZ_CONFWRITERPYTHON 1
+
+/* Enable writing config to a Python module file.
+ */
+void
+chaz_ConfWriterPython_enable(void);
+
+#endif /* H_CHAZ_CONFWRITERPYTHON */
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/ConfWriterRuby.h"
+/* Charmonizer/Core/ConfWriterRuby.h -- Write to a Ruby module file.
+ */
+
+#ifndef H_CHAZ_CONFWRITERRUBY
+#define H_CHAZ_CONFWRITERRUBY 1
+
+/* Enable writing config to a Ruby module file.
+ */
+void
+chaz_ConfWriterRuby_enable(void);
+
+#endif /* H_CHAZ_CONFWRITERRUBY */
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/HeaderChecker.h"
+/* Charmonizer/Probe/HeaderChecker.h
+ */
+
+#ifndef H_CHAZ_HEAD_CHECK
+#define H_CHAZ_HEAD_CHECK
+
+/* #include "Charmonizer/Core/Defines.h" */
+
+/* Bootstrap the HeadCheck.  Call this before anything else.
+ */
+void
+chaz_HeadCheck_init(void);
+
+/* Check for a particular header and return true if it's available.  The
+ * test-compile is only run the first time a given request is made.
+ */
+int
+chaz_HeadCheck_check_header(const char *header_name);
+
+/* Attempt to compile a file which pulls in all the headers specified by name
+ * in a null-terminated array.  If the compile succeeds, add them all to the
+ * internal register and return true.
+ */
+int
+chaz_HeadCheck_check_many_headers(const char **header_names);
+
+/* Return true if the member is present in the struct. */
+int
+chaz_HeadCheck_contains_member(const char *struct_name, const char *member,
+                               const char *includes);
+
+#endif /* H_CHAZ_HEAD_CHECK */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/Make.h"
+/* Charmonizer/Core/Make.h
+ */
+
+#ifndef H_CHAZ_MAKE
+#define H_CHAZ_MAKE
+
+/* #include "Charmonizer/Core/CFlags.h" */
+/* #include "Charmonizer/Core/Library.h" */
+
+typedef struct chaz_MakeFile chaz_MakeFile;
+typedef struct chaz_MakeVar chaz_MakeVar;
+typedef struct chaz_MakeRule chaz_MakeRule;
+
+typedef void (*chaz_Make_list_files_callback_t)(const char *dir, char *file,
+                                                void *context);
+
+/** Initialize the environment.
+ */
+void
+chaz_Make_init(void);
+
+/** Clean up the environment.
+ */
+void
+chaz_Make_clean_up(void);
+
+/** Return the name of the detected 'make' executable.
+ */
+const char*
+chaz_Make_get_make(void);
+
+/** Return the type of shell used by the detected 'make' executable.
+ */
+int
+chaz_Make_shell_type(void);
+
+/** Recursively list files in a directory. For every file a callback is called
+ * with the filename and a context variable.
+ *
+ * @param dir Directory to search in.
+ * @param ext File extension to search for.
+ * @param callback Callback to call for every matching file.
+ * @param context Context variable to pass to callback.
+ */
+void
+chaz_Make_list_files(const char *dir, const char *ext,
+                     chaz_Make_list_files_callback_t callback, void *context);
+
+/** MakeFile constructor.
+ */
+chaz_MakeFile*
+chaz_MakeFile_new();
+
+/** MakeFile destructor.
+ */
+void
+chaz_MakeFile_destroy(chaz_MakeFile *makefile);
+
+/** Add a variable to a makefile.
+ *
+ * @param makefile The makefile.
+ * @param name Name of the variable.
+ * @param value Value of the variable. Can be NULL if you want add content
+ * later.
+ * @return a MakeVar.
+ */
+chaz_MakeVar*
+chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
+                      const char *value);
+
+/** Add a rule to a makefile.
+ *
+ * @param makefile The makefile.
+ * @param target The first target of the rule. Can be NULL if you want to add
+ * targets later.
+ * @param prereq The first prerequisite of the rule. Can be NULL if you want to
+ * add prerequisites later.
+ * @return a MakeRule.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
+                       const char *prereq);
+
+/** Return the rule for the 'clean' target.
+ *
+ * @param makefile The makefile.
+ */
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile);
+
+/** Return the rule for the 'distclean' target.
+ *
+ * @param makefile The makefile.
+ */
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile);
+
+/** Add a rule to link an executable. The executable will also be added to the
+ * list of files to clean.
+ *
+ * @param makefile The makefile.
+ * @param exe The name of the executable.
+ * @param sources The list of source files.
+ * @param link_flags Additional link flags.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
+                      const char *sources, chaz_CFlags *link_flags);
+
+/** Add a rule to compile and link an executable. The executable will also be
+ * added to the list of files to clean.
+ *
+ * @param makefile The makefile.
+ * @param exe The name of the executable.
+ * @param sources The list of source files.
+ * @param cflags Additional compiler flags.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
+                               const char *sources, chaz_CFlags *cflags);
+
+/** Add a rule to link a shared library. The shared library will also be added
+ * to the list of files to clean.
+ *
+ * @param makefile The makefile.
+ * @param lib The shared library.
+ * @param sources The list of source files.
+ * @param link_flags Additional link flags.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, chaz_Lib *lib,
+                             const char *sources, chaz_CFlags *link_flags);
+
+/** Add a rule to create a static library. The static library will also be 
added
+ * to the list of files to clean.
+ *
+ * @param makefile The makefile.
+ * @param lib The static library.
+ * @param objects The list of object files to be archived.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_static_lib(chaz_MakeFile *makefile, chaz_Lib *lib,
+                             const char *objects);
+
+/** Add a rule to build the lemon parser generator.
+ *
+ * @param makefile The makefile.
+ * @param dir The lemon directory.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_lemon_exe(chaz_MakeFile *makefile, const char *dir);
+
+/** Add a rule for a lemon grammar.
+ *
+ * @param makefile The makefile.
+ * @param base_name The filename of the grammar without extension.
+ */
+chaz_MakeRule*
+chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *makefile,
+                                const char *base_name);
+
+/** Write the makefile to a file named 'Makefile' in the current directory.
+ *
+ * @param makefile The makefile.
+ */
+void
+chaz_MakeFile_write(chaz_MakeFile *makefile);
+
+/** Append content to a makefile variable. The new content will be separated
+ * from the existing content with whitespace.
+ *
+ * @param var The variable.
+ * @param element The additional content.
+ */
+void
+chaz_MakeVar_append(chaz_MakeVar *var, const char *element);
+
+/** Add another target to a makefile rule.
+ *
+ * @param rule The rule.
+ * @param target The additional rule.
+ */
+void
+chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target);
+
+/** Add another prerequisite to a makefile rule.
+ *
+ * @param rule The rule.
+ * @param prereq The additional prerequisite.
+ */
+void
+chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq);
+
+/** Add a command to a rule.
+ *
+ * @param rule The rule.
+ * @param command The additional command.
+ */
+void
+chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
+
+/** Add a command to remove one or more files.
+ *
+ * @param rule The rule.
+ * @param files The list of files.
+ */
+void
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files);
+
+/** Add a command to remove one or more directories.
+ *
+ * @param rule The rule.
+ * @param dirs The list of directories.
+ */
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs);
+
+/** Add one or more commands to call another makefile recursively.
+ *
+ * @param rule The rule.
+ * @param dir The directory in which to call the makefile.
+ * @param target The target to call. Pass NULL for the default target.
+ */
+void
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
+                               const char *target);
+
+#endif /* H_CHAZ_MAKE */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/OperatingSystem.h"
+/* Charmonizer/Core/OperatingSystem.h - abstract an operating system down to a 
few
+ * variables.
+ */
+
+#ifndef H_CHAZ_OPER_SYS
+#define H_CHAZ_OPER_SYS
+
+#define CHAZ_OS_POSIX    1
+#define CHAZ_OS_CMD_EXE  2
+
+/* Safely remove a file named [name]. Needed because of Windows quirks.
+ * Returns true on success, false on failure.
+ */
+int
+chaz_OS_remove(const char *name);
+
+/* Invoke a command and attempt to suppress output from both stdout and stderr
+ * (as if they had been sent to /dev/null).  If it's not possible to run the
+ * command quietly, run it anyway.
+ */
+int
+chaz_OS_run_quietly(const char *command);
+
+/* Capture both stdout and stderr for a command to the supplied filepath.
+ */
+int
+chaz_OS_run_redirected(const char *command, const char *path);
+
+/* Run a command beginning with the name of an executable in the current
+ * working directory and capture both stdout and stderr to the supplied
+ * filepath.
+ */
+int
+chaz_OS_run_local_redirected(const char *command, const char *path);
+
+/* Run a command and return the output from stdout.
+ */
+char*
+chaz_OS_run_and_capture(const char *command, size_t *output_len);
+
+/* Attempt to create a directory.
+ */
+void
+chaz_OS_mkdir(const char *filepath);
+
+/* Attempt to remove a directory, which must be empty.
+ */
+void
+chaz_OS_rmdir(const char *filepath);
+
+/* Return the operating system name.
+ */
+const char*
+chaz_OS_name(void);
+
+int
+chaz_OS_is_darwin(void);
+
+int
+chaz_OS_is_cygwin(void);
+
+/* Return the extension for an executable on this system.
+ */
+const char*
+chaz_OS_exe_ext(void);
+
+/* Return the extension for a shared object on this system.
+ */
+const char*
+chaz_OS_shared_lib_ext(void);
+
+/* Return the extension for a static library on this system.
+ */
+const char*
+chaz_OS_static_lib_ext(void);
+
+/* Return the equivalent of /dev/null on this system.
+ */
+const char*
+chaz_OS_dev_null(void);
+
+/* Return the directory separator on this system.
+ */
+const char*
+chaz_OS_dir_sep(void);
+
+/* Return the shell type of this system.
+ */
+int
+chaz_OS_shell_type(void);
+
+/* Initialize the Charmonizer/Core/OperatingSystem module.
+ */
+void
+chaz_OS_init(void);
+
+#endif /* H_CHAZ_COMPILER */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Core/Util.h"
+/* Chaz/Core/Util.h -- miscellaneous utilities.
+ */
+
+#ifndef H_CHAZ_UTIL
+#define H_CHAZ_UTIL 1
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+extern int chaz_Util_verbosity;
+
+/* Open a file (truncating if necessary) and write [content] to it.  
Util_die() if
+ * an error occurs.
+ */
+void
+chaz_Util_write_file(const char *filename, const char *content);
+
+/* Read an entire file into memory.
+ */
+char*
+chaz_Util_slurp_file(const char *file_path, size_t *len_ptr);
+
+/* Return a newly allocated copy of a NULL-terminated string.
+ */
+char*
+chaz_Util_strdup(const char *string);
+
+/* Join a NULL-terminated list of strings using a separator.
+ */
+char*
+chaz_Util_join(const char *sep, ...);
+
+/* Get the length of a file (may overshoot on text files under DOS).
+ */
+long
+chaz_Util_flength(void *file);
+
+/* Print an error message to stderr and exit.
+ */
+void
+chaz_Util_die(const char *format, ...);
+
+/* Print an error message to stderr.
+ */
+void
+chaz_Util_warn(const char *format, ...);
+
+/* Attept to delete a file.  Return true if the file is gone, whether or not
+ * it was there to begin with.  Issue a warning and return false if the file
+ * still exists.
+ */
+int
+chaz_Util_remove_and_verify(const char *file_path);
+
+/* Attempt to open a file for reading, then close it immediately.
+ */
+int
+chaz_Util_can_open_file(const char *file_path);
+
+#endif /* H_CHAZ_UTIL */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe.h"
+#ifndef H_CHAZ
+#define H_CHAZ 1
+
+#include <stddef.h>
+#include <stdio.h>
+
+struct chaz_CLI;
+
+/* Parse command line arguments, initializing and filling in the supplied
+ * `args` struct.
+ *
+ *     APP_NAME --cc=CC_COMMAND
+ *              [--enable-c]
+ *              [--enable-perl]
+ *              [--enable-python]
+ *              [--enable-ruby]
+ *              [-- [CFLAGS]]
+ *
+ * @return true if argument parsing proceeds without incident, false if
+ * unexpected arguments are encountered or values are missing or invalid.
+ */
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLI *cli);
+
+/* Exit after printing usage instructions to stderr.
+ */
+void
+chaz_Probe_die_usage(void);
+
+/* Set up the Charmonizer environment.
+ *
+ * If the environment variable CHARM_VERBOSITY has been set, it will be
+ * processed at this time:
+ *
+ *      0 - silent
+ *      1 - normal
+ *      2 - debugging
+ */
+void
+chaz_Probe_init(struct chaz_CLI *cli);
+
+/* Clean up the Charmonizer environment -- deleting tempfiles, etc.  This
+ * should be called only after everything else finishes.
+ */
+void
+chaz_Probe_clean_up(void);
+
+/* Return an integer version of the GCC version number which is
+ * (10000 * __GNU_C__ + 100 * __GNUC_MINOR__ + __GNUC_PATCHLEVEL__).
+ */
+int
+chaz_Probe_gcc_version_num(void);
+
+/* If the compiler is GCC (or claims compatibility), return an X.Y.Z string
+ * version of the GCC version; otherwise, return NULL.
+ */
+const char*
+chaz_Probe_gcc_version(void);
+
+/* Return the integer version of MSVC defined by _MSC_VER
+ */
+int
+chaz_Probe_msvc_version_num(void);
+
+#endif /* Include guard. */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/AtomicOps.h"
+/* Charmonizer/Probe/AtomicOps.h
+ */
+
+#ifndef H_CHAZ_ATOMICOPS
+#define H_CHAZ_ATOMICOPS
+
+#include <stdio.h>
+
+/* Run the AtomicOps module.
+ *
+ * These following symbols will be defined if the associated headers are
+ * available:
+ *
+ * HAS_LIBKERN_OSATOMIC_H  <libkern/OSAtomic.h> (Mac OS X)
+ * HAS_SYS_ATOMIC_H        <sys/atomic.h>       (Solaris)
+ * HAS_INTRIN_H            <intrin.h>           (Windows)
+ *
+ * This symbol is defined if OSAtomicCompareAndSwapPtr is available:
+ *
+ * HAS_OSATOMIC_CAS_PTR
+ */
+void chaz_AtomicOps_run(void);
+
+#endif /* H_CHAZ_ATOMICOPS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/Booleans.h"
+/* Charmonizer/Probe/Booleans.h -- bool type.
+ *
+ * If stdbool.h is is available, it will be pound-included in the configuration
+ * header.  If it is not, the following typedef will be defined:
+ *
+ * bool
+ *
+ * These symbols will be defined if they are not already:
+ *
+ * true
+ * false
+ */
+
+#ifndef H_CHAZ_BOOLEANS
+#define H_CHAZ_BOOLEANS
+
+#include <stdio.h>
+
+/* Run the Booleans module.
+ */
+void chaz_Booleans_run(void);
+
+#endif /* H_CHAZ_BOOLEANS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/BuildEnv.h"
+/* Charmonizer/Probe/BuildEnv.h -- Build environment.
+ *
+ * Capture various information about the build environment, including the C
+ * compiler's interface, the shell, the operating system, etc.
+ *
+ * The following symbols will be defined:
+ *
+ * CC - String representation of the C compiler executable.
+ * CFLAGS - C compiler flags.
+ * EXTRA_CFLAGS - Extra C compiler flags.
+ */
+
+#ifndef H_CHAZ_BUILDENV
+#define H_CHAZ_BUILDENV
+
+#include <stdio.h>
+
+/* Run the BuildEnv module.
+ */
+void chaz_BuildEnv_run(void);
+
+#endif /* H_CHAZ_BUILDENV */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/DirManip.h"
+/* Charmonizer/Probe/DirManip.h
+ */
+
+#ifndef H_CHAZ_DIRMANIP
+#define H_CHAZ_DIRMANIP
+
+/* The DirManip module exports or aliases symbols related to directory and file
+ * manipulation.
+ *
+ * Defined if the header files dirent.h and direct.h are available, 
respectively:
+ *
+ * HAS_DIRENT_H
+ * HAS_DIRECT_H
+ *
+ * Defined if struct dirent has these members.
+ *
+ * HAS_DIRENT_D_NAMLEN
+ * HAS_DIRENT_D_TYPE
+ *
+ * The "makedir" macro will be aliased to the POSIX-specified two-argument
+ * "mkdir" interface:
+ *
+ * makedir
+ *
+ * On some systems, the second argument to makedir will be ignored, in which
+ * case this symbol will be true; otherwise, it will be false: (TODO: This
+ * isn't verified and may sometimes be incorrect.)
+ *
+ * MAKEDIR_MODE_IGNORED
+ *
+ * String representing the system's directory separator:
+ *
+ * DIR_SEP
+ *
+ * True if the remove() function removes directories, false otherwise:
+ *
+ * REMOVE_ZAPS_DIRS
+ */
+void chaz_DirManip_run(void);
+
+#endif /* H_CHAZ_DIR_SEP */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/Floats.h"
+/* Charmonizer/Probe/Floats.h -- floating point types.
+ *
+ * The following symbols will be created if the platform supports IEEE 754
+ * floating point types:
+ *
+ * F32_NAN
+ * F32_INF
+ * F32_NEGINF
+ * F64_NAN
+ * F64_INF
+ * F64_NEGINF
+ *
+ * TODO: Actually test to see whether IEEE 754 is supported, rather than just
+ * lying about it.
+ */
+
+#ifndef H_CHAZ_FLOATS
+#define H_CHAZ_FLOATS
+
+/* Run the Floats module.
+ */
+void
+chaz_Floats_run(void);
+
+/* Return the name of the math library to link against or NULL.
+ */
+const char*
+chaz_Floats_math_library(void);
+
+#endif /* H_CHAZ_FLOATS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/FuncMacro.h"
+/* Charmonizer/Probe/FuncMacro.h
+ */
+
+#ifndef H_CHAZ_FUNC_MACRO
+#define H_CHAZ_FUNC_MACRO
+
+#include <stdio.h>
+
+/* Run the FuncMacro module.
+ *
+ * If __func__ successfully resolves, this will be defined:
+ *
+ * HAS_ISO_FUNC_MACRO
+ *
+ * If __FUNCTION__ successfully resolves, this will be defined:
+ *
+ * HAS_GNUC_FUNC_MACRO
+ *
+ * If one or the other succeeds, these will be defined:
+ *
+ * HAS_FUNC_MACRO
+ * FUNC_MACRO
+ *
+ * The "inline" keyword will also be probed for.  If it is available, the
+ * following macro will be defined to "inline", otherwise it will be defined
+ * to nothing.
+ *
+ * INLINE
+ */
+void chaz_FuncMacro_run(void);
+
+#endif /* H_CHAZ_FUNC_MACRO */
+
+
+
+
+/***************************************************************************/
+
+#line 20 "src/Charmonizer/Probe/Headers.h"
+/* Charmonizer/Probe/Headers.h
+ */
+
+#ifndef H_CHAZ_HEADERS
+#define H_CHAZ_HEADERS
+
+#include <stdio.h>
+/* #include "Charmonizer/Core/Defines.h" */
+
+/* Check whether a particular header file is available.  The test-compile is
+ * only run the first time a given request is made.
+ */
+int
+chaz_Headers_check(const char *header_name);
+
+/* Run the Headers module.
+ *
+ * Exported symbols:
+ *
+ * If HAS_C89 is declared, this system has all the header files described in
+ * Ansi C 1989.  HAS_C90 is a synonym.  (It would be surprising if they are
+ * not defined, because Charmonizer itself assumes C89.)
+ *
+ * HAS_C89
+ * HAS_C90
+ *
+ * One symbol is exported for each C89 header file:
+ *
+ * HAS_ASSERT_H
+ * HAS_CTYPE_H
+ * HAS_ERRNO_H
+ * HAS_FLOAT_H
+ * HAS_LIMITS_H
+ * HAS_LOCALE_H
+ * HAS_MATH_H
+ * HAS_SETJMP_H
+ * HAS_SIGNAL_H
+ * HAS_STDARG_H
+ * HAS_STDDEF_H
+ * HAS_STDIO_H
+ * HAS_STDLIB_H
+ * HAS_STRING_H
+ * HAS_TIME_H
+ *
+ * One symbol is exported for every POSIX header present, and HAS_POSIX is
+ * exported if they're all there.
+ *
+ * HAS_POSIX
+ *
+ * HAS_CPIO_H
+ * HAS_DIRENT_H
+ * HAS_FCNTL_H
+ * HAS_GRP_H
+ * HAS_PWD_H
+ * HAS_SYS_STAT_H
+ * HAS_SYS_TIMES_H
+ * HAS_SYS_TYPES_H
+ * HAS_SYS_UTSNAME_H
+ * HAS_WAIT_H
+ * HAS_TAR_H
+ * HAS_TERMIOS_H
+ * HAS_UNISTD_H
+ * HAS_UTIME_H
+ *
+ * If pthread.h is available, this will be exported:
+ *
+ * HAS_PTHREAD_H
+ */
+void
+chaz_Headers_run(void);
+
+#endif /* H_CHAZ_HEADERS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/Integers.h"
+/* Charmonizer/Probe/Integers.h -- info about integer types and sizes.
+ *
+ * One or the other of these will be defined, depending on whether the
+ * processor is big-endian or little-endian.
+ *
+ * BIG_END
+ * LITTLE_END
+ *
+ * These will always be defined:
+ *
+ * SIZEOF_CHAR
+ * SIZEOF_SHORT
+ * SIZEOF_INT
+ * SIZEOF_LONG
+ * SIZEOF_PTR
+ *
+ * If long longs are available these symbols will be defined:
+ *
+ * HAS_LONG_LONG
+ * SIZEOF_LONG_LONG
+ *
+ * Similarly, with the __int64 type (the sizeof is included for completeness):
+ *
+ * HAS___INT64
+ * SIZEOF___INT64
+ *
+ * If the inttypes.h or stdint.h header files are available, these may be
+ * defined:
+ *
+ * HAS_INTTYPES_H
+ * HAS_STDINT_H
+ *
+ * If stdint.h is is available, it will be pound-included in the configuration
+ * header.  If it is not, the following typedefs and macros will be defined if
+ * possible:
+ *
+ * int8_t
+ * int16_t
+ * int32_t
+ * int64_t
+ * uint8_t
+ * uint16_t
+ * uint32_t
+ * uint64_t
+ * INT8_MAX
+ * INT16_MAX
+ * INT32_MAX
+ * INT64_MAX
+ * INT8_MIN
+ * INT16_MIN
+ * INT32_MIN
+ * INT64_MIN
+ * UINT8_MAX
+ * UINT16_MAX
+ * UINT32_MAX
+ * UINT64_MAX
+ * SIZE_MAX
+ * INT32_C
+ * INT64_C
+ * UINT32_C
+ * UINT64_C
+ *
+ * If inttypes.h is is available, it will be pound-included in the
+ * configuration header.  If it is not, the following macros will be defined if
+ * possible:
+ *
+ * PRId64
+ * PRIu64
+ *
+ * Availability of integer types is indicated by which of these are defined:
+ *
+ * HAS_INT8_T
+ * HAS_INT16_T
+ * HAS_INT32_T
+ * HAS_INT64_T
+ *
+ * If 64-bit integers are available, this macro will promote pointers to i64_t
+ * safely.
+ *
+ * PTR_TO_I64(ptr)
+ */
+
+#ifndef H_CHAZ_INTEGERS
+#define H_CHAZ_INTEGERS
+
+#include <stdio.h>
+
+/* Run the Integers module.
+ */
+void chaz_Integers_run(void);
+
+#endif /* H_CHAZ_INTEGERS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/LargeFiles.h"
+/* Charmonizer/Probe/LargeFiles.h
+ */
+
+#ifndef H_CHAZ_LARGE_FILES
+#define H_CHAZ_LARGE_FILES
+
+#include <stdio.h>
+
+/* The LargeFiles module attempts to detect these symbols or alias them to
+ * synonyms:
+ *
+ * off64_t
+ * fopen64
+ * ftello64
+ * fseeko64
+ * lseek64
+ * pread64
+ *
+ * If off64_t or its equivalent is available, this will be defined:
+ *
+ * HAS_64BIT_OFFSET_TYPE
+ *
+ * If 64-bit variants of fopen, ftell, and fseek are available, this will be
+ * defined:
+ *
+ * HAS_64BIT_STDIO
+ *
+ * If 64-bit variants of pread and lseek are available, then corresponding
+ * symbols will be defined:
+ *
+ * HAS_64BIT_PREAD
+ * HAS_64BIT_LSEEK
+ *
+ * Use of the off64_t symbol may require sys/types.h.
+ */
+void chaz_LargeFiles_run(void);
+
+#endif /* H_CHAZ_LARGE_FILES */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/Memory.h"
+/* Charmonizer/Probe/Memory.h
+ */
+
+#ifndef H_CHAZ_MEMORY
+#define H_CHAZ_MEMORY
+
+/* The Memory module attempts to detect these symbols or alias them to
+ * synonyms:
+ *
+ * alloca
+ *
+ * These following symbols will be defined if the associated headers are
+ * available:
+ *
+ * HAS_SYS_MMAN_H          <sys/mman.h>
+ * HAS_ALLOCA_H            <alloca.h>
+ * HAS_MALLOC_H            <malloc.h>
+ *
+ * Defined if alloca() is available via stdlib.h:
+ *
+ * ALLOCA_IN_STDLIB_H
+ */
+void chaz_Memory_run(void);
+
+#endif /* H_CHAZ_MEMORY */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/RegularExpressions.h"
+/* Charmonizer/Probe/RegularExpressions.h -- regular expressions.
+ */
+
+#ifndef H_CHAZ_REGULAREXPRESSIONS
+#define H_CHAZ_REGULAREXPRESSIONS
+
+/* Run the RegularExpressions module.
+ */
+void chaz_RegularExpressions_run(void);
+
+#endif /* H_CHAZ_REGULAREXPRESSIONS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/Strings.h"
+/* Charmonizer/Probe/Strings.h
+ */
+
+#ifndef H_CHAZ_STRINGS
+#define H_CHAZ_STRINGS
+
+/* The Strings module attempts to detect whether snprintf works as specified
+ * by the C99 standard. It also looks for system-specific functions which can
+ * be used to emulate snprintf.
+ */
+void chaz_Strings_run(void);
+
+#endif /* H_CHAZ_STRINGS */
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/SymbolVisibility.h"
+/* Charmonizer/Probe/SymbolVisibility.h
+ */
+
+#ifndef H_CHAZ_SYMBOLVISIBILITY
+#define H_CHAZ_SYMBOLVISIBILITY
+
+void chaz_SymbolVisibility_run(void);
+
+#endif /* H_CHAZ_SYMBOLVISIBILITY */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/UnusedVars.h"
+/* Charmonizer/Probe/UnusedVars.h
+ */
+
+#ifndef H_CHAZ_UNUSED_VARS
+#define H_CHAZ_UNUSED_VARS
+
+#include <stdio.h>
+
+/* Run the UnusedVars module.
+ *
+ * These symbols are exported:
+ *
+ * UNUSED_VAR(var)
+ * UNREACHABLE_RETURN(type)
+ *
+ */
+void chaz_UnusedVars_run(void);
+
+#endif /* H_CHAZ_UNUSED_VARS */
+
+
+
+
+/***************************************************************************/
+
+#line 21 "src/Charmonizer/Probe/VariadicMacros.h"
+/* Charmonizer/Probe/VariadicMacros.h
+ */
+
+#ifndef H_CHAZ_VARIADIC_MACROS
+#define H_CHAZ_VARIADIC_MACROS
+
+#include <stdio.h>
+
+/* Run the VariadicMacros module.
+ *
+ * If your compiler supports ISO-style variadic macros, this will be defined:
+ *
+ * HAS_ISO_VARIADIC_MACROS
+ *
+ * If your compiler supports GNU-style variadic macros, this will be defined:
+ *
+ * HAS_GNUC_VARIADIC_MACROS
+ *
+ * If you have at least one of the above, this will be defined:
+ *
+ * HAS_VARIADIC_MACROS
+ */
+void chaz_VariadicMacros_run(void);
+
+#endif /* H_CHAZ_VARIADIC_MACROS */
+
+
+
+
+/***************************************************************************/
+
+#line 17 "src/Charmonizer/Core/Library.c"
+#include <string.h>
+#include <stdlib.h>
+/* #include "Charmonizer/Core/Library.h" */
+/* #include "Charmonizer/Core/Compiler.h" */
+/* #include "Charmonizer/Core/Util.h" */
+/* #include "Charmonizer/Core/OperatingSystem.h" */
+
+struct chaz_Lib {
+    char *name;
+    char *version;
+    char *major_version;
+    int   is_static;
+    int   is_shared;
+    chaz_LibType lib_type;
+};
+
+static char*
+S_build_filename(chaz_Lib *lib, const char *version, const char *ext);
+
+static const char*
+S_get_prefix(void);
+
+chaz_Lib*
+chaz_Lib_new(const char *name, chaz_LibType lib_type, const char *version,
+             const char *major_version) {
+    chaz_Lib *lib = (chaz_Lib*)malloc(sizeof(chaz_Lib));
+    lib->name          = chaz_Util_strdup(name);
+    lib->version       = chaz_Util_strdup(version);
+    lib->major_version = chaz_Util_strdup(major_version);
+    lib->lib_type      = lib_type;
+    if (lib_type == chaz_Lib_SHARED) {
+        lib->is_shared = 1;
+        lib->is_static = 0;
+    }
+    else if (lib_type == chaz_Lib_STATIC) {
+        lib->is_shared = 0;
+        lib->is_static = 1;
+    }
+    else {
+        chaz_Util_die("Invalid value for lib_type: %d", lib_type);
+    }
+    return lib;
+}
+
+void
+chaz_Lib_destroy(chaz_Lib *lib) {
+    free(lib->name);
+    free(lib->version);
+    free(lib->major_version);
+    free(lib);
+}
+
+const char*
+chaz_Lib_get_name(chaz_Lib *lib) {
+    return lib->name;
+}
+
+const char*
+chaz_Lib_get_version(chaz_Lib *lib) {
+    return lib->version;
+}
+
+const char*
+chaz_Lib_get_major_version(chaz_Lib *lib) {
+    return lib->major_version;
+}
+
+int
+chaz_Lib_is_shared (chaz_Lib *lib) {
+    return lib->is_shared;
+}
+
+int
+chaz_Lib_is_static (chaz_Lib *lib) {
+    return lib->is_static;
+}
+
+char*
+chaz_Lib_filename(chaz_Lib *lib) {
+    const char *ext = lib->is_shared
+                      ? chaz_OS_shared_lib_ext()
+                      : chaz_OS_static_lib_ext();
+
+    if ((strcmp(ext, ".dll") == 0) || strcmp(ext, ".lib") == 0) {
+        return S_build_filename(lib, lib->major_version, ext);
+    }
+    else {
+        return S_build_filename(lib, lib->version, ext);
+    }
+}
+
+char*
+chaz_Lib_major_version_filename(chaz_Lib *lib) {
+    const char *ext = lib->is_shared
+                      ? chaz_OS_shared_lib_ext()
+                      : chaz_OS_static_lib_ext();
+    return S_build_filename(lib, lib->major_version, ext);
+}
+
+char*
+chaz_Lib_no_version_filename(chaz_Lib *lib) {
+    const char *prefix = S_get_prefix();
+    const char *ext = lib->is_shared
+                      ? chaz_OS_shared_lib_ext()
+                      : chaz_OS_static_lib_ext();
+    return chaz_Util_join("", prefix, lib->name, ext, NULL);
+}
+
+char*
+chaz_Lib_implib_filename(chaz_Lib *lib) {
+    return S_build_filename(lib, lib->major_version, ".lib");
+}
+
+char*
+chaz_Lib_export_filename(chaz_Lib *lib) {
+    return S_build_filename(lib, lib->major_version, ".exp");
+}
+
+static char*
+S_build_filename(chaz_Lib *lib, const char *version, const char *ext) {
+    const char *prefix    = S_get_prefix();
+    const char *shlib_ext = chaz_OS_shared_lib_ext();
+
+    /* Use `shlib_ext` as a proxy for OS to determine behavior, but append
+     * the supplied `ext`. */
+    if (strcmp(shlib_ext, ".dll") == 0) {
+        return chaz_Util_join("", prefix, lib->name, "-", version, ext, NULL);
+    }
+    else if (strcmp(shlib_ext, ".dylib") == 0) {
+        return chaz_Util_join("", prefix, lib->name, ".", version, ext, NULL);
+    }
+    else {
+        return chaz_Util_join("", prefix, lib->name, ext, ".", version, NULL);
+    }
+}
+
+static const char*
+S_get_prefix() {
+    if (chaz_CC_msvc_version_num()) {
+        return "";
+    }
+    else if (chaz_OS_is_cygwin()) {
+        return "cyg";
+    }
+    else {
+        return "lib";
+    }
+}
+
+
+
+/***************************************************************************/
+
+#line 17 "src/Charmonizer/Core/CFlags.c"
+#include <string.h>
+#include <stdlib.h>
+/* #include "Charmonizer/Core/CFlags.h" */
+/* #include "Charmonizer/Core/Compiler.h" */
+/* #include "Charmonizer/Core/Util.h" */
+/* #include "Charmonizer/Core/OperatingSystem.h" */
+/* #include "Charmonizer/Core/Library.h" */
+
+struct chaz_CFlags {
+    int   style;
+    char *string;
+};
+
+chaz_CFlags*
+chaz_CFlags_new(int style) {
+    chaz_CFlags *flags = (chaz_CFlags*)malloc(sizeof(chaz_CFlags));
+    flags->style  = style;
+    flags->string = chaz_Util_strdup("");
+    return flags;
+}
+
+void
+chaz_CFlags_destroy(chaz_CFlags *flags) {
+    free(flags->string);
+    free(flags);
+}
+
+const char*
+chaz_CFlags_get_string(chaz_CFlags *flags) {
+    return flags->string;
+}
+
+void
+chaz_CFlags_append(chaz_CFlags *flags, const char *string) {
+    char *new_string;
+    if (flags->string[0] == '\0') {
+        new_string = chaz_Util_strdup(string);
+    }
+    else {
+        new_string = chaz_Util_join(" ", flags->string, string, NULL);
+    }
+    free(flags->string);
+    flags->string = new_string;
+}
+
+void
+chaz_CFlags_clear(chaz_CFlags *flags) {
+    if (flags->string[0] != '\0') {
+        free(flags->string);
+        flags->string = chaz_Util_strdup("");
+    }
+}
+
+void
+chaz_CFlags_set_output_obj(chaz_CFlags *flags, const char *filename) {
+    const char *output;
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        output = "/c /Fo";
+    }
+    else {
+        /* POSIX */
+        output = "-c -o ";
+    }
+    string = chaz_Util_join("", output, filename, NULL);
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_set_output_exe(chaz_CFlags *flags, const char *filename) {
+    const char *output;
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        output = "/Fe";
+    }
+    else {
+        /* POSIX */
+        output = "-o ";
+    }
+    string = chaz_Util_join("", output, filename, NULL);
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_add_define(chaz_CFlags *flags, const char *name,
+                       const char *value) {
+    const char *define;
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        define = "/D";
+    }
+    else {
+        /* POSIX */
+        define = "-D ";
+    }
+    if (value) {
+        string = chaz_Util_join("", define, name, "=", value, NULL);
+    }
+    else {
+        string = chaz_Util_join("", define, name, NULL);
+    }
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_add_include_dir(chaz_CFlags *flags, const char *dir) {
+    const char *include;
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC)  {
+        include = "/I ";
+    }
+    else {
+        /* POSIX */
+        include = "-I ";
+    }
+    string = chaz_Util_join("", include, dir, NULL);
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_enable_optimization(chaz_CFlags *flags) {
+    const char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        string = "/O2";
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        string = "-O2";
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        string = "-xO4";
+    }
+    else {
+        /* POSIX */
+        string = "-O 1";
+    }
+    chaz_CFlags_append(flags, string);
+}
+
+void
+chaz_CFlags_enable_debugging(chaz_CFlags *flags) {
+    if (flags->style == CHAZ_CFLAGS_STYLE_GNU
+        || flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        chaz_CFlags_append(flags, "-g");
+    }
+}
+
+void
+chaz_CFlags_disable_strict_aliasing(chaz_CFlags *flags) {
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        return;
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        chaz_CFlags_append(flags, "-fno-strict-aliasing");
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        chaz_CFlags_append(flags, "-xalias_level=any");
+    }
+    else {
+        chaz_Util_die("Don't know how to disable strict aliasing with '%s'",
+                      chaz_CC_get_cc());
+    }
+}
+
+void
+chaz_CFlags_set_warnings_as_errors(chaz_CFlags *flags) {
+    const char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        string = "/WX";
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        string = "-Werror";
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        string = "-errwarn=%all";
+    }
+    else {
+        chaz_Util_die("Don't know how to set warnings as errors with '%s'",
+                      chaz_CC_get_cc());
+    }
+    chaz_CFlags_append(flags, string);
+}
+
+void
+chaz_CFlags_compile_shared_library(chaz_CFlags *flags) {
+    const char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        string = "/MD";
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        const char *shlib_ext = chaz_OS_shared_lib_ext();
+        if (strcmp(shlib_ext, ".dylib") == 0) {
+            string = "-fno-common";
+        }
+        else if (strcmp(shlib_ext, ".so") == 0) {
+            string = "-fPIC";
+        }
+        else if (strcmp(shlib_ext, ".dll") == 0) {
+            /* MinGW */
+            return;
+        }
+        else {
+            /* unknown */
+            return;
+        }
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        string = "-KPIC";
+    }
+    else {
+        return;
+    }
+    chaz_CFlags_append(flags, string);
+}
+
+void
+chaz_CFlags_hide_symbols(chaz_CFlags *flags) {
+    if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        if (strcmp(chaz_OS_shared_lib_ext(), ".dll") != 0) {
+            chaz_CFlags_append(flags, "-fvisibility=hidden");
+        }
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        if (chaz_CC_sun_c_version_num() >= 0x550) {
+            /* Sun Studio 8. */
+            chaz_CFlags_append(flags, "-xldscope=hidden");
+        }
+    }
+}
+
+void
+chaz_CFlags_link_shared_library(chaz_CFlags *flags) {
+    const char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        string = "/DLL";
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        if (strcmp(chaz_OS_shared_lib_ext(), ".dylib") == 0) {
+            string = "-dynamiclib";
+        }
+        else {
+            string = "-shared";
+        }
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        string = "-G";
+    }
+    else {
+        chaz_Util_die("Don't know how to link a shared library with '%s'",
+                      chaz_CC_get_cc());
+    }
+    chaz_CFlags_append(flags, string);
+}
+
+void
+chaz_CFlags_set_shared_library_version(chaz_CFlags *flags, chaz_Lib *lib) {
+    if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        const char *shlib_ext = chaz_OS_shared_lib_ext();
+
+        if (strcmp(shlib_ext, ".dylib") == 0) {
+            const char *version = chaz_Lib_get_version(lib);
+            char *string
+                = chaz_Util_join(" ", "-current_version", version, NULL);
+            chaz_CFlags_append(flags, string);
+            free(string);
+        }
+        else if (strcmp(shlib_ext, ".so") == 0) {
+            char *soname = chaz_Lib_major_version_filename(lib);
+            char *string = chaz_Util_join("", "-Wl,-soname,", soname, NULL);
+            chaz_CFlags_append(flags, string);
+            free(string);
+            free(soname);
+        }
+    }
+    else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) {
+        char *soname = chaz_Lib_major_version_filename(lib);
+        char *string = chaz_Util_join(" ", "-h", soname, NULL);
+        chaz_CFlags_append(flags, string);
+        free(string);
+        free(soname);
+    }
+}
+
+void
+chaz_CFlags_set_link_output(chaz_CFlags *flags, const char *filename) {
+    const char *output;
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        output = "/OUT:";
+    }
+    else {
+        output = "-o ";
+    }
+    string = chaz_Util_join("", output, filename, NULL);
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_add_library_path(chaz_CFlags *flags, const char *directory) {
+    const char *lib_path;
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        if (strcmp(directory, ".") == 0) {
+            /* The MS linker searches the current directory by default. */
+            return;
+        }
+        else {
+            lib_path = "/LIBPATH:";
+        }
+    }
+    else {
+        lib_path = "-L ";
+    }
+    string = chaz_Util_join("", lib_path, directory, NULL);
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_add_library(chaz_CFlags *flags, chaz_Lib *lib) {
+    char *filename;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        filename = chaz_Lib_implib_filename(lib);
+    }
+    else {
+        filename = chaz_Lib_filename(lib);
+    }
+    chaz_CFlags_append(flags, filename);
+    free(filename);
+}
+
+void
+chaz_CFlags_add_external_library(chaz_CFlags *flags, const char *library) {
+    char *string;
+    if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) {
+        string = chaz_Util_join("", library, ".lib", NULL);
+    }
+    else {
+        string = chaz_Util_join(" ", "-l", library, NULL);
+    }
+    chaz_CFlags_append(flags, string);
+    free(string);
+}
+
+void
+chaz_CFlags_enable_code_coverage(chaz_CFlags *flags) {
+    if (flags->style == CHAZ_CFLAGS_STYLE_GNU) {
+        chaz_CFlags_append(flags, "--coverage");
+    }
+    else {
+        chaz_Util_die("Don't know how to enable code coverage with '%s'",
+                      chaz_CC_get_cc());
+    }
+}
+
+
+
+/***************************************************************************/
+
+#line 17 "src/Charmonizer/Core/CLI.c"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+/* #include "Charmonizer/Core/CLI.h" */
+/* #include "Charmonizer/Core/Util.h" */
+
+typedef struct chaz_CLIOption {
+    char *name;
+    char *help;
+    char *value;
+    int   defined;
+    int   flags;
+} chaz_CLIOption;
+
+struct chaz_CLI {
+    char *name;
+    char *desc;
+    char *usage;
+    char *help;
+    chaz_CLIOption *opts;
+    int   num_opts;
+};
+
+static void
+S_chaz_CLI_error(chaz_CLI *self, const char *pattern, ...) {
+    va_list ap;
+    if (chaz_Util_verbosity > 0) {
+        va_start(ap, pattern);
+        vfprintf(stderr, pattern, ap);
+        va_end(ap);
+        fprintf(stderr, "\n");
+    }
+}
+
+static void
+S_chaz_CLI_rebuild_help(chaz_CLI *self) {
+    int i;
+    size_t amount = 200; /* Length of section headers. */
+
+    /* Allocate space. */
+    if (self->usage) {
+        amount += strlen(self->usage);
+    }
+    else {
+        amount += strlen(self->name);
+    }
+    if (self->desc) {
+        amount += strlen(self->desc);
+    }
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        amount += 24 + 2 * strlen(opt->name);
+        if (opt->flags) {
+            amount += strlen(opt->name);
+        }
+        if (opt->help) {
+            amount += strlen(opt->help);
+        }
+    }
+    free(self->help);
+    self->help = (char*)malloc(amount);
+    self->help[0] = '\0';
+
+    /* Accumulate "help" string. */
+    if (self->usage) {
+        strcat(self->help, self->usage);
+    }
+    else {
+        strcat(self->help, "Usage: ");
+        strcat(self->help, self->name);
+        if (self->num_opts) {
+            strcat(self->help, " [OPTIONS]");
+        }
+    }
+    if (self->desc) {
+        strcat(self->help, "\n\n");
+        strcat(self->help, self->desc);
+    }
+    strcat(self->help, "\n");
+    if (self->num_opts) {
+        strcat(self->help, "\nOptional arguments:\n");
+        for (i = 0; i < self->num_opts; i++) {
+            chaz_CLIOption *opt = &self->opts[i];
+            size_t line_start = strlen(self->help);
+            size_t current_len;
+
+            strcat(self->help, "  --");
+            strcat(self->help, opt->name);
+            current_len = strlen(self->help);
+            if (opt->flags) {
+                int j;
+                if (opt->flags & CHAZ_CLI_ARG_OPTIONAL) {
+                    self->help[current_len++] = '[';
+                }
+                self->help[current_len++] = '=';
+                for (j = 0; opt->name[j]; j++) {
+                    self->help[current_len++] = toupper(opt->name[j]);
+                }
+                if (opt->flags & CHAZ_CLI_ARG_OPTIONAL) {
+                    strcat(self->help, "]");
+                }
+                self->help[current_len] = '\0';
+            }
+            if (opt->help) {
+                self->help[current_len++] = ' ';
+                while (current_len - line_start < 25) {
+                    self->help[current_len++] = ' ';
+                }
+                self->help[current_len] = '\0';
+                strcpy(self->help + current_len, opt->help);
+            }
+            strcat(self->help, "\n");
+        }
+    }
+    strcat(self->help, "\n");
+}
+
+chaz_CLI*
+chaz_CLI_new(const char *name, const char *description) {
+    chaz_CLI *self  = calloc(1, sizeof(chaz_CLI));
+    self->name      = chaz_Util_strdup(name ? name : "PROGRAM");
+    self->desc      = description ? chaz_Util_strdup(description) : NULL;
+    self->help      = NULL;
+    self->opts      = NULL;
+    self->num_opts  = 0;
+    S_chaz_CLI_rebuild_help(self);
+    return self;
+}
+
+void
+chaz_CLI_destroy(chaz_CLI *self) {
+    int i;
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        free(opt->name);
+        free(opt->help);
+        free(opt->value);
+    }
+    free(self->name);
+    free(self->desc);
+    free(self->opts);
+    free(self->usage);
+    free(self->help);
+    free(self);
+}
+
+void
+chaz_CLI_set_usage(chaz_CLI *self, const char *usage) {
+    free(self->usage);
+    self->usage = chaz_Util_strdup(usage);
+}
+
+const char*
+chaz_CLI_help(chaz_CLI *self) {
+    return self->help;
+}
+
+int
+chaz_CLI_register(chaz_CLI *self, const char *name, const char *help,
+                  int flags) {
+    int rank;
+    int i;
+    int arg_required = !!(flags & CHAZ_CLI_ARG_REQUIRED);
+    int arg_optional = !!(flags & CHAZ_CLI_ARG_OPTIONAL);
+
+    /* Validate flags */
+    if (arg_required && arg_optional) {
+        S_chaz_CLI_error(self, "Conflicting flags: value both optional "
+                         "and required");
+        return 0;
+    }
+
+    /* Insert new option.  Keep options sorted by name. */
+    for (rank = self->num_opts; rank > 0; rank--) {
+        int comparison = strcmp(name, self->opts[rank - 1].name);
+        if (comparison == 0) {
+            S_chaz_CLI_error(self, "Option '%s' already registered", name);
+            return 0;
+        }
+        else if (comparison > 0) {
+            break;
+        }
+    }
+    self->num_opts += 1;
+    self->opts = realloc(self->opts, self->num_opts * sizeof(chaz_CLIOption));
+    for (i = self->num_opts - 1; i > rank; i--) {
+        self->opts[i] = self->opts[i - 1];
+    }
+    self->opts[rank].name    = chaz_Util_strdup(name);
+    self->opts[rank].help    = help ? chaz_Util_strdup(help) : NULL;
+    self->opts[rank].flags   = flags;
+    self->opts[rank].defined = 0;
+    self->opts[rank].value   = NULL;
+
+    /* Update `help` with new option. */
+    S_chaz_CLI_rebuild_help(self);
+
+    return 1;
+}
+
+int
+chaz_CLI_set(chaz_CLI *self, const char *name, const char *value) {
+    int i;
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        if (strcmp(opt->name, name) == 0) {
+            if (opt->defined) {
+                S_chaz_CLI_error(self, "'%s' specified multiple times", name);
+                return 0;
+            }
+            opt->defined = 1;
+            if (value != NULL) {
+                opt->value = chaz_Util_strdup(value);
+            }
+            return 1;
+        }
+    }
+    S_chaz_CLI_error(self, "Attempt to set unknown option: '%s'", name);
+    return 0;
+}
+
+int
+chaz_CLI_unset(chaz_CLI *self, const char *name) {
+    int i;
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        if (strcmp(opt->name, name) == 0) {
+            free(opt->value);
+            opt->value = NULL;
+            opt->defined = 0;
+            return 1;
+        }
+    }
+    S_chaz_CLI_error(self, "Attempt to unset unknown option: '%s'", name);
+    return 0;
+}
+
+int
+chaz_CLI_defined(chaz_CLI *self, const char *name) {
+    int i;
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        if (strcmp(opt->name, name) == 0) {
+            return opt->defined;
+        }
+    }
+    S_chaz_CLI_error(self, "Inquiry for unknown option: '%s'", name);
+    return 0;
+}
+
+long
+chaz_CLI_longval(chaz_CLI *self, const char *name) {
+    int i;
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        if (strcmp(opt->name, name) == 0) {
+            if (!opt->defined || !opt->value) {
+                return 0;
+            }
+            return strtol(opt->value, NULL, 10);
+        }
+    }
+    S_chaz_CLI_error(self, "Longval request for unknown option: '%s'", name);
+    return 0;
+}
+
+const char*
+chaz_CLI_strval(chaz_CLI *self, const char *name) {
+    int i;
+    for (i = 0; i < self->num_opts; i++) {
+        chaz_CLIOption *opt = &self->opts[i];
+        if (strcmp(opt->name, name) == 0) {
+            return opt->value;
+        }
+    }
+    S_chaz_CLI_error(self, "Strval request for unknown option: '%s'", name);
+    return 0;
+}
+
+int
+chaz_CLI_parse(chaz_CLI *self, int argc, const char *argv[]) {
+    int i;
+    char *name = NULL;
+    size_t name_cap = 0;
+
+    /* Parse most args. */
+    for (i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        size_t name_len = 0;
+        int has_equals = 0;
+        const char *value = NULL;
+
+        /* Stop processing if we see `-` or `--`. */
+        if (strcmp(arg, "--") == 0 || strcmp(arg, "-") == 0) {
+            break;
+        }
+
+        if (strncmp(arg, "--", 2) != 0) {
+            S_chaz_CLI_error(self, "Unexpected argument: '%s'", arg);
+            free(name);
+            return 0;
+        }
+
+        /* Extract the name of the argument, look for a potential value. */
+        while (1) {
+            char c = arg[name_len + 2];
+            if (isalnum(c) || c == '-' || c == '_') {
+                name_len++;
+            }
+            else if (c == '\0') {
+                break;
+            }
+            else if (c == '=') {
+                /* The rest of the arg is the value. */
+                value = arg + 2 + name_len + 1;
+                break;
+            }
+            else {
+                free(name);
+                S_chaz_CLI_error(self, "Malformed argument: '%s'", arg);
+                return 0;
+            }
+        }
+        if (name_len + 1 > name_cap) {
+            name_cap = name_len + 1;
+            name = (char*)realloc(name, name_cap);
+        }
+        memcpy(name, arg + 2, name_len);
+        name[name_len] = '\0';
+
+        /* Attempt to set the option. */
+        if (!chaz_CLI_set(self, name, value)) {
+            free(name);
+            return 0;
+        }
+    }
+
+    free(name);
+    return 1;
+}
+
+
+/***************************************************************************/
+
+#line 17 "src/Charmonizer/Core/Compiler.c"
+#include <string.h>
+#include <stdlib.h>
+/* #include "Charmonizer/Core/Util.h" */
+/* #include "Charmonizer/Core/Compiler.h" */
+/* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Core/OperatingSystem.h" */
+
+/* Detect macros which may help to identify some compilers.
+ */
+static void
+chaz_CC_detect_known_compilers(void);
+
+/* Temporary files. */
+#define CHAZ_CC_TRY_SOURCE_PATH  "_charmonizer_try.c"
+#define CHAZ_CC_TRY_BASENAME     "_charmonizer_try"
+#define CHAZ_CC_TARGET_PATH      "_charmonizer_target"
+
+/* Static vars. */
+static struct {
+    char     *cc_command;
+    char     *cflags;
+    char     *try_exe_name;
+    char      obj_ext[10];
+    char      gcc_version_str[30];
+    int       cflags_style;
+    int       intval___GNUC__;
+    int       intval___GNUC_MINOR__;
+    int       intval___GNUC_PATCHLEVEL__;
+    int       intval__MSC_VER;
+    int       intval___clang__;
+    int       intval___SUNPRO_C;
+    chaz_CFlags *extra_cflags;
+    chaz_CFlags *temp_cflags;
+} chaz_CC = {
+    NULL, NULL, NULL,
+    "", "",
+    0, 0, 0, 0, 0, 0, 0,
+    NULL, NULL
+};
+
+void
+chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
+    const char *code = "int main() { return 0; }\n";
+    int compile_succeeded = 0;
+
+    if (chaz_Util_verbosity) { printf("Creating compiler object...\n"); }
+
+    /* Assign, init. */
+    chaz_CC.cc_command   = chaz_Util_strdup(compiler_command);
+    chaz_CC.cflags       = chaz_Util_strdup(compiler_flags);
+    chaz_CC.extra_cflags = NULL;
+    chaz_CC.temp_cflags  = NULL;
+
+    /* Set names for the targets which we "try" to compile. */
+    chaz_CC.try_exe_name
+        = chaz_Util_join("", CHAZ_CC_TRY_BASENAME, chaz_OS_exe_ext(), NULL);
+
+    /* If we can't compile anything, game over. */
+    if (chaz_Util_verbosity) {
+        printf("Trying to compile a small test file...\n");
+    }
+    /* Try MSVC argument style. */
+    strcpy(chaz_CC.obj_ext, ".obj");
+    chaz_CC.cflags_style = CHAZ_CFLAGS_STYLE_MSVC;
+    compile_succeeded = chaz_CC_test_compile(code);
+    if (!compile_succeeded) {
+        /* Try POSIX argument style. */
+        strcpy(chaz_CC.obj_ext, ".o");
+        chaz_CC.cflags_style = CHAZ_CFLAGS_STYLE_POSIX;
+        compile_succeeded = chaz_CC_test_compile(code);
+    }
+    if (!compile_succeeded) {
+        chaz_Util_die("Failed to compile a small test file");
+    }
+
+    chaz_CC_detect_known_compilers();
+
+    if (chaz_CC.intval___GNUC__) {
+        chaz_CC.cflags_style = CHAZ_CFLAGS_STYLE_GNU;
+    }
+    else if (chaz_CC.intval__MSC_VER) {
+        chaz_CC.cflags_style = CHAZ_CFLAGS_STYLE_MSVC;
+    }
+    else if (chaz_CC.intval___SUNPRO_C) {
+        chaz_CC.cflags_style = CHAZ_CFLAGS_STYLE_SUN_C;
+    }
+    else {
+        chaz_CC.cflags_style = CHAZ_CFLAGS_STYLE_POSIX;
+    }
+    chaz_CC.extra_cflags = chaz_CFlags_new(chaz_CC.cflags_style);
+    chaz_CC.temp_cflags  = chaz_CFlags_new(chaz_CC.cflags_style);
+}
+
+static const char chaz_CC_detect_macro_code[] =
+    CHAZ_QUOTE(  #include <stdio.h>             )
+    CHAZ_QUOTE(  int main() {                   )
+    CHAZ_QUOTE(  #ifndef %s                     )
+    CHAZ_QUOTE(  #error "nope"                  )
+    CHAZ_QUOTE(  #endif                         )
+    CHAZ_QUOTE(      printf("%%d", %s);         )
+    CHAZ_QUOTE(      return 0;                  )
+    CHAZ_QUOTE(  }                              );
+
+static int
+chaz_CC_detect_macro(const char *macro) {
+    size_t size = sizeof(chaz_CC_detect_macro_code)
+                  + (strlen(macro) * 2)
+                  + 20;
+    char *code = (char*)malloc(size);
+    int retval = 0;
+    char *output;
+    size_t len;
+    sprintf(code, chaz_CC_detect_macro_code, macro, macro);
+    output = chaz_CC_capture_output(code, &len);
+    if (output) {
+        retval = atoi(output);
+        free(output);
+    }
+    free(code);
+    return retval;
+}
+
+static void
+chaz_CC_detect_known_compilers(void) {
+    chaz_CC.intval___GNUC__  = chaz_CC_detect_macro("__GNUC__");
+    if (chaz_CC.intval___GNUC__) {
+        chaz_CC.intval___GNUC_MINOR__
+            = chaz_CC_detect_macro("__GNUC_MINOR__");
+        chaz_CC.intval___GNUC_PATCHLEVEL__
+            = chaz_CC_detect_macro("__GNUC_PATCHLEVEL__");
+        sprintf(chaz_CC.gcc_version_str, "%d.%d.%d", chaz_CC.intval___GNUC__,
+                chaz_CC.intval___GNUC_MINOR__,
+                chaz_CC.intval___GNUC_PATCHLEVEL__);
+    }
+    chaz_CC.intval__MSC_VER   = chaz_CC_detect_macro("_MSC_VER");
+    chaz_CC.intval___clang__  = chaz_CC_detect_macro("__clang__");
+    chaz_CC.intval___SUNPRO_C = chaz_CC_detect_macro("__SUNPRO_C");
+}
+
+void
+chaz_CC_clean_up(void) {
+    free(chaz_CC.cc_command);
+    free(chaz_CC.cflags);
+    free(chaz_CC.try_exe_name);
+    chaz_CFlags_destroy(chaz_CC.extra_cflags);
+    chaz_CFlags_destroy(chaz_CC.temp_cflags);
+}
+
+int
+chaz_CC_compile_exe(const char *source_path, const char *exe_name,
+                    const char *code) {
+    chaz_CFlags *local_cflags = chaz_CFlags_new(chaz_CC.cflags_style);
+    const char *extra_cflags_string = "";
+    const char *temp_cflags_string  = "";
+    const char *local_cflags_string;
+    char *exe_file = chaz_Util_join("", exe_name, chaz_OS_exe_ext(), NULL);
+    char *command;
+    int result;
+
+    /* Write the source file. */
+    chaz_Util_write_file(source_path, code);
+
+    /* Prepare and run the compiler command. */
+    if (chaz_CC.extra_cflags) {
+        extra_cflags_string = chaz_CFlags_get_string(chaz_CC.extra_cflags);
+    }
+    if (chaz_CC.temp_cflags) {
+        temp_cflags_string = chaz_CFlags_get_string(chaz_CC.temp_cflags);
+    }
+    chaz_CFlags_set_output_exe(local_cflags, exe_file);
+    local_cflags_string = chaz_CFlags_get_string(local_cflags);
+    command = chaz_Util_join(" ", chaz_CC.cc_command, chaz_CC.cflags,
+                             source_path, extra_cflags_string,
+                             temp_cflags_string, local_cflags_string, NULL);
+    if (chaz_Util_verbosity < 2) {
+        chaz_OS_run_quietly(command);
+    }
+    else {
+        system(command);
+    }
+
+    if (chaz_CC.intval__MSC_VER) {
+        /* Zap MSVC junk. */
+        size_t  junk_buf_size = strlen(exe_file) + 4;
+        char   *junk          = (char*)malloc(junk_buf_size);
+        sprintf(junk, "%s.obj", exe_name);
+        chaz_Util_remove_and_verify(junk);
+        sprintf(junk, "%s.ilk", exe_name);
+        chaz_Util_remove_and_verify(junk);
+        sprintf(junk, "%s.pdb", exe_name);
+        chaz_Util_remove_and_verify(junk);
+        free(junk);
+    }
+
+    /* See if compilation was successful.  Remove the source file. */
+    result = chaz_Util_can_open_file(exe_file);
+    if (!chaz_Util_remove_and_verify(source_path)) {
+        chaz_Util_die("Failed to remove '%s'", source_path);
+    }
+
+    chaz_CFlags_destroy(local_cflags);
+    free(command);
+    free(exe_file);
+    return result;
+}
+
+int
+chaz_CC_compile_obj(const char *source_path, const char *obj_name,
+                    const char *code) {
+    chaz_CFlags *local_cflags = chaz_CFlags_new(chaz_CC.cflags_style);
+    const char *extra_cflags_string = "";
+    const char *temp_cflags_string  = "";
+    const char *local_cflags_string;
+    char *obj_file = chaz_Util_join("", obj_name, chaz_CC.obj_ext, NULL);
+    char *command;
+    int result;
+
+    /* Write the source file. */
+    chaz_Util_write_file(source_path, code);
+
+    /* Prepare and run the compiler command. */
+    if (chaz_CC.extra_cflags) {
+        extra_cflags_string = chaz_CFlags_get_string(chaz_CC.extra_cflags);
+    }
+    if (chaz_CC.temp_cflags) {
+        temp_cflags_string = chaz_CFlags_get_string(chaz_CC.temp_cflags);
+    }
+    chaz_CFlags_set_output_obj(local_cflags, obj_file);
+    local_cflags_string = chaz_CFlags_get_string(local_cflags);
+    command = chaz_Util_join(" ", chaz_CC.cc_command, chaz_CC.cflags,
+                             source_path, extra_cflags_string,
+                             temp_cflags_string, local_cflags_string, NULL);
+    if (chaz_Util_verbosity < 2) {
+        chaz_OS_run_quietly(command);
+    }
+    else {
+        system(command);
+    }
+
+    /* See if compilation was successful.  Remove the source file. */
+    result = chaz_Util_can_open_file(obj_file);
+    if (!chaz_Util_remove_and_verify(source_path)) {
+        chaz_Util_die("Failed to remove '%s'", source_path);
+    }
+
+    chaz_CFlags_destroy(local_cflags);
+    free(command);
+    free(obj_file);
+    return result;
+}
+
+int
+chaz_CC_test_compile(const char *source) {
+    int compile_succeeded;
+    char *try_obj_name
+        = chaz_Util_join("", CHAZ_CC_TRY_BASENAME, chaz_CC.obj_ext, NULL);
+    if (!chaz_Util_remove_and_verify(try_obj_name)) {
+        chaz_Util_die("Failed to delete file '%s'", try_obj_name);
+    }
+    compile_succeeded = chaz_CC_compile_obj(CHAZ_CC_TRY_SOURCE_PATH,
+                                            CHAZ_CC_TRY_BASENAME, source);
+    chaz_Util_remove_and_verify(try_obj_name);
+    free(try_obj_name);
+    return compile_succeeded;
+}
+
+char*
+chaz_CC_capture_output(const char *source, size_t *output_len) {
+    char *captured_output = NULL;
+    int compile_succeeded;
+
+    /* Clear out previous versions and test to make sure removal worked. */
+    if (!chaz_Util_remove_and_verify(chaz_CC.try_exe_name)) {
+        chaz_Util_die("Failed to delete file '%s'", chaz_CC.try_exe_name);
+    }
+    if (!chaz_Util_remove_and_verify(CHAZ_CC_TARGET_PATH)) {
+        chaz_Util_die("Failed to delete file '%s'", CHAZ_CC_TARGET_PATH);
+    }
+
+    /* Attempt compilation; if successful, run app and slurp output. */
+    compile_succeeded = chaz_CC_compile_exe(CHAZ_CC_TRY_SOURCE_PATH,
+                                            CHAZ_CC_TRY_BASENAME, source);
+    if (compile_succeeded) {
+        chaz_OS_run_local_redirected(chaz_CC.try_exe_name,
+                                     CHAZ_CC_TARGET_PATH);
+        captured_output = chaz_Util_slurp_file(CHAZ_CC_TARGET_PATH,
+                                               output_len);
+    }
+    else {
+        *output_len = 0;
+    }
+
+    /* Remove all the files we just created. */
+    chaz_Util_remove_and_verify(CHAZ_CC_TRY_SOURCE_PATH);
+    chaz_Util_remove_and_verify(chaz_CC.try_exe_name);
+    chaz_Util_remove_and_verify(CHAZ_CC_TARGET_PATH);
+
+    return captured_output;
+}
+
+const char*
+chaz_CC_get_cc(void) {
+    return chaz_CC.cc_command;
+}
+
+const char*
+chaz_CC_get_cflags(void) {
+    return chaz_CC.cflags;
+}
+
+chaz_CFlags*
+chaz_CC_get_extra_cflags(void) {
+    return chaz_CC.extra_cflags;
+}
+
+chaz_CFlags*
+chaz_CC_get_temp_cflags(void) {
+    return chaz_CC.temp_cflags;
+}
+
+chaz_CFlags*
+chaz_CC_new_cflags(void) {
+    return chaz_CFlags_new(chaz_CC.cflags_style);
+}
+
+const char*
+chaz_CC_obj_ext(void) {
+    return chaz_CC.obj_ext;
+}
+
+int
+chaz_CC_gcc_version_num(void) {
+    return 10000 * chaz_CC.intval___GNUC__
+           + 100 * chaz_CC.intval___GNUC_MINOR__
+           + chaz_CC.intval___GNUC_PATCHLEVEL__;
+}
+
+const char*
+chaz_CC_gcc_version(void) {
+    return chaz_CC.intval___GNUC__ ? chaz_CC.gcc_version_str : NULL;
+}
+
+int
+chaz_CC_msvc_version_num(void) {
+    return chaz_CC.intval__MSC_VER;
+}
+
+int
+chaz_CC_sun_c_version_num(void) {
+    return chaz_CC.intval___SUNPRO_C;
+}
+
+const char*
+chaz_CC_link_command() {
+    if (chaz_CC.intval__MSC_VER) {
+        return "link";
+    }
+    else {
+        return chaz_CC.cc_command;
+    }
+}
+
+char*
+chaz_CC_format_archiver_command(const char *target, const char *objects) {
+    if (chaz_CC.intval__MSC_VER) {
+        /* TODO: Write `objects` to a temporary file in order to avoid
+         * exceeding line length limits. */
+        char *out = chaz_Util_join("", "/OUT:", target, NULL);
+        char *command = chaz_Util_join(" ", "lib", "/NOLOGO", out, NULL);
+        free(out);
+        return command;
+    }
+    else {
+        return chaz_Util_join(" ", "ar", "rcs", target, objects, NULL);
+    }
+}
+
+char*
+chaz_CC_format_ranlib_command(const char *target) {
+    if (chaz_CC.intval__MSC_VER) {
+        return NULL;
+    }
+    return chaz_Util_join(" ", "ranlib", target, NULL);
+}
+
+
+/***************************************************************************/
+
+#line 17 "src/Charmonizer/Core/ConfWriter.c"
+/* #include "Charmonizer/Core/Util.h" */
+/* #include "Charmonizer/Core/ConfWriter.h" */
+#include <stdarg.h>
+#include <stdio.h>
+
+#define CW_MAX_WRITERS 10
+static struct {
+    chaz_ConfWriter *writers[CW_MAX_WRITERS];
+    size_t num_writers;
+} chaz_CW;
+
+void
+chaz_ConfWriter_init(void) {
+    chaz_CW.num_writers = 0;
+    return;
+}
+
+void
+chaz_ConfWriter_clean_up(void) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->clean_up();
+    }
+}
+
+void
+chaz_ConfWriter_append_conf(const char *fmt, ...) {
+    va_list args;
+    size_t i;
+    
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        va_start(args, fmt);
+        chaz_CW.writers[i]->vappend_conf(fmt, args);
+        va_end(args);
+    }
+}
+
+void
+chaz_ConfWriter_add_def(const char *sym, const char *value) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->add_def(sym, value);
+    }
+}
+
+void
+chaz_ConfWriter_add_global_def(const char *sym, const char *value) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->add_global_def(sym, value);
+    }
+}
+
+void
+chaz_ConfWriter_add_typedef(const char *type, const char *alias) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->add_typedef(type, alias);
+    }
+}
+
+void
+chaz_ConfWriter_add_global_typedef(const char *type, const char *alias) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->add_global_typedef(type, alias);
+    }
+}
+
+void
+chaz_ConfWriter_add_sys_include(const char *header) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->add_sys_include(header);
+    }
+}
+
+void
+chaz_ConfWriter_add_local_include(const char *header) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->add_local_include(header);
+    }
+}
+
+void
+chaz_ConfWriter_start_module(const char *module_name) {
+    size_t i;
+    if (chaz_Util_verbosity > 0) {
+        printf("Running %s module...\n", module_name);
+    }
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->start_module(module_name);
+    }
+}
+
+void
+chaz_ConfWriter_end_module(void) {
+    size_t i;
+    for (i = 0; i < chaz_CW.num_writers; i++) {
+        chaz_CW.writers[i]->end_module();
+    }
+}
+
+void
+chaz_ConfWriter_add_writer(chaz_ConfWriter *writer) {
+    chaz_CW.writers[chaz_CW.num_writers] = writer;
+    chaz_CW.num_writers++;
+}
+
+
+/***************************************************************************/
+
+#line 17 "src/Charmonizer/Core/ConfWriterC.c"
+/* #include "Charmonizer/Core/Util.h" */
+/* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Core/ConfWriterC.h" */
+/* #include "Charmonizer/Core/OperatingSystem.h" */
+/* #include "Charmonizer/Core/Compiler.h" */
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef enum chaz_ConfElemType {
+    CHAZ_CONFELEM_DEF,
+    CHAZ_CONFELEM_GLOBAL_DEF,
+    CHAZ_CONFELEM_TYPEDEF,
+    CHAZ_CONFELEM_GLOBAL_TYPEDEF,
+    CHAZ_CONFELEM_SYS_INCLUDE,
+    CHAZ_CONFELEM_LOCAL_INCLUDE
+} chaz_ConfElemType;
+
+typedef struct chaz_ConfElem {
+    char *str1;
+    char *str2;
+    chaz_ConfElemType type;
+} chaz_ConfElem;
+
+/* Static vars. */
+static struct {
+    FILE          *fh;
+    char          *MODULE_NAME;
+    chaz_ConfElem *defs;
+    size_t         def_cap;
+    size_t         def_count;
+} chaz_ConfWriterC = { NULL, NULL, 0, 0 };
+static chaz_ConfWriter CWC_conf_writer;
+
+/* Open the charmony.h file handle.  Print supplied text to it, if non-null.
+ * Print an explanatory comment and open the include guard.
+ */
+static void
+chaz_ConfWriterC_open_charmony_h(const char *charmony_start);
+
+/* Push a new elem onto the def list. */
+static void
+chaz_ConfWriterC_push_def_list_item(const char *str1, const char *str2,
+                     chaz_ConfElemType type);
+
+/* Free the def list. */
+static void
+chaz_ConfWriterC_clear_def_list(void);
+
+static void
+chaz_ConfWriterC_clean_up(void);
+static void
+chaz_ConfWriterC_vappend_conf(const char *fmt, va_list args);
+static void
+chaz_ConfWriterC_add_def(const char *sym, const char *value);
+static void
+chaz_ConfWriterC_add_global_def(const char *sym, const char *value);
+static void
+chaz_ConfWriterC_add_typedef(const char *type, const char *alias);
+static void
+chaz_ConfWriterC_add_global_typedef(const char *type, const char *alias);
+static void
+chaz_ConfWriterC_add_sys_include(const char *header);
+static void
+chaz_ConfWriterC_add_local_include(const char *header);
+static void
+chaz_ConfWriterC_start_module(const char *module_name);
+static void
+chaz_ConfWriterC_end_module(void);
+
+void
+chaz_ConfWriterC_enable(void) {
+    CWC_conf_writer.clean_up           = chaz_ConfWriterC_clean_up;
+    CWC_conf_writer.vappend_conf       = chaz_ConfWriterC_vappend_conf;
+    CWC_conf_writer.add_def            = chaz_ConfWriterC_add_def;
+    CWC_conf_writer.add_global_def     = chaz_ConfWriterC_add_global_def;
+    CWC_conf_writer.add_typedef        = chaz_ConfWriterC_add_typedef;
+    CWC_conf_writer.add_global_typedef = chaz_ConfWriterC_add_global_typedef;
+    CWC_conf_writer.add_sys_include    = chaz_ConfWriterC_add_sys_include;
+    CWC_conf_writer.add_local_include  = chaz_ConfWriterC_add_local_include;
+    CWC_conf_writer.start_module       = chaz_ConfWriterC_start_module;
+    CWC_conf_writer.end_module         = chaz_ConfWriterC_end_module;
+    chaz_ConfWriterC_open_charmony_h(NULL);
+    chaz_ConfWriter_add_writer(&CWC_conf_writer);
+    return;
+}
+
+static void
+chaz_ConfWriterC_open_charmony_h(const char *charmony_start) {
+    /* Open the filehandle. */
+    chaz_ConfWriterC.fh = fopen("charmony.h", "w+");
+    if (chaz_ConfWriterC.fh == NULL) {
+        chaz_Util_die("Can't open 'charmony.h': %s", strerror(errno));
+    }
+
+    /* Print supplied text (if any) along with warning, open include guard. */
+    if (charmony_start != NULL) {
+        fwrite(charmony_start, sizeof(char), strlen(charmony_start),
+               chaz_ConfWriterC.fh);
+    }
+    fprintf(chaz_ConfWriterC.fh,
+            "/* Header file auto-generated by Charmonizer. \n"
+            " * DO NOT EDIT THIS FILE!!\n"
+            " */\n\n"
+            "#ifndef H_CHARMONY\n"
+            "#define H_CHARMONY 1\n\n"
+           );
+}
+
+static void
+chaz_ConfWriterC_clean_up(void) {
+    /* Write the last bit of charmony.h and close. */
+    fprintf(chaz_ConfWriterC.fh, "#endif /* H_CHARMONY */\n\n");
+    if (fclose(chaz_ConfWriterC.fh)) {
+        chaz_Util_die("Couldn't close 'charmony.h': %s", strerror(errno));
+    }
+}
+
+static void
+chaz_ConfWriterC_vappend_conf(const char *fmt, va_list args) {
+    vfprintf(chaz_ConfWriterC.fh, fmt, args);
+}
+
+static int
+chaz_ConfWriterC_sym_is_uppercase(const char *sym) {
+    return isupper(sym[0]);
+}
+
+static char*
+chaz_ConfWriterC_uppercase_string(const char *src) {
+    char *retval = chaz_Util_strdup(src);
+    size_t i;
+    for (i = 0; retval[i]; ++i) {
+        retval[i] = toupper(retval[i]);
+    }
+    return retval;
+}
+
+static void
+chaz_ConfWriterC_add_def(const char *sym, const char *value) {
+    chaz_ConfWriterC_push_def_list_item(sym, value, CHAZ_CONFELEM_DEF);
+}
+
+static void
+chaz_ConfWriterC_append_def_to_conf(const char *sym, const char *value) {
+    if (value) {
+        if (chaz_ConfWriterC_sym_is_uppercase(sym)) {
+            fprintf(chaz_ConfWriterC.fh, "#define CHY_%s %s\n", sym, value);
+        }
+        else {
+            fprintf(chaz_ConfWriterC.fh, "#define chy_%s %s\n", sym, value);
+        }
+    }
+    else {
+        if (chaz_ConfWriterC_sym_is_uppercase(sym)) {
+            fprintf(chaz_ConfWriterC.fh, "#define CHY_%s\n", sym);
+        }
+        else {
+            fprintf(chaz_ConfWriterC.fh, "#define chy_%s\n", sym);
+        }
+    }
+}
+
+static void
+chaz_ConfWriterC_add_global_def(const char *sym, const char *value) {
+    chaz_ConfWriterC_push_def_list_item(sym, value, CHAZ_CONFELEM_GLOBAL_DEF);
+}
+
+static void
+chaz_ConfWriterC_append_global_def_to_conf(const char *sym,
+                                           const char *value) {
+    char *name_end = strchr(sym, '(');
+    if (name_end == NULL) {
+        if (strcmp(sym, value) == 0) { return; }
+        fprintf(chaz_ConfWriterC.fh, "#ifndef %s\n", sym);
+    }
+    else {
+        size_t  name_len = (size_t)(name_end - sym);
+        char   *name     = chaz_Util_strdup(sym);
+        name[name_len] = '\0';
+        fprintf(chaz_ConfWriterC.fh, "#ifndef %s\n", name);
+        free(name);
+    }
+    if (value) {
+        fprintf(chaz_ConfWriterC.fh, "  #define %s %s\n", sym, value);
+    }
+    else {
+        fprintf(chaz_ConfWriterC.fh, "  #define %s\n", sym);
+    }
+    fprintf(chaz_ConfWriterC.fh, "#endif\n");
+}
+
+static void
+chaz_ConfWriterC_add_typedef(const char *type, const char *alias) {
+    chaz_ConfWriterC_push_def_list_item(alias, type, CHAZ_CONFELEM_TYPEDEF);
+}
+
+static void
+chaz_ConfWriterC_append_typedef_to_conf(const char *type, const char *alias) {
+    if (chaz_ConfWriterC_sym_is_uppercase(alias)) {
+        fprintf(chaz_ConfWriterC.fh, "typedef %s CHY_%s;\n", type, alias);
+    }
+    else {
+        fprintf(chaz_ConfWriterC.fh, "typedef %s chy_%s;\n", type, alias);
+    }
+}
+
+static void
+chaz_ConfWriterC_add_global_typedef(const char *type, const char *alias) {
+    chaz_ConfWriterC_push_def_list_item(alias, type,
+            CHAZ_CONFELEM_GLOBAL_TYPEDEF);
+}
+
+static void
+chaz_ConfWriterC_append_global_typedef_to_conf(const char *type,
+                                               const char *alias) {
+    if (strcmp(type, alias) == 0) { return; }
+    fprintf(chaz_ConfWriterC.fh, "typedef %s %s;\n", type, alias);
+}
+
+static void
+chaz_ConfWriterC_add_sys_include(const char *header) {
+    chaz_ConfWriterC_push_def_list_item(header, NULL,
+                                        CHAZ_CONFELEM_SYS_INCLUDE);
+}
+
+static void
+chaz_ConfWriterC_append_sys_include_to_conf(const char *header) {
+    fprintf(chaz_ConfWriterC.fh, "#include <%s>\n", header);
+}
+
+static void
+chaz_ConfWriterC_add_local_include(const char *header) {
+    chaz_ConfWriterC_push_def_list_item(header, NULL,
+                                        CHAZ_CONFELEM_LOCAL_INCLUDE);
+}
+
+static void
+chaz_ConfWriterC_append_local_include_to_conf(const char *header) {
+    fprintf(chaz_ConfWriterC.fh, "#include \"%s\"\n", header);
+}
+
+static void
+chaz_ConfWriterC_start_module(const char *module_name) {
+    fprintf(chaz_ConfWriterC.fh, "\n/* %s */\n", module_name);
+    chaz_ConfWriterC.MODULE_NAME
+        = chaz_ConfWriterC_uppercase_string(module_name);
+}
+
+static void
+chaz_ConfWriterC_end_module(void) {
+    size_t num_globals = 0;
+    size_t i;
+    chaz_ConfElem *defs = chaz_ConfWriterC.defs;
+    for (i = 0; i < chaz_ConfWriterC.def_count; i++) {
+        switch (defs[i].type) {
+            case CHAZ_CONFELEM_GLOBAL_DEF:
+                ++num_globals;
+            /* fall through */
+            case CHAZ_CONFELEM_DEF:
+                chaz_ConfWriterC_append_def_to_conf(defs[i].str1,
+                                                    defs[i].str2);
+                break;
+            case CHAZ_CONFELEM_GLOBAL_TYPEDEF: {
+                char *sym = chaz_ConfWriterC_uppercase_string(defs[i].str1);
+                chaz_ConfWriterC_append_def_to_conf(sym, defs[i].str2);
+                free(sym);
+                ++num_globals;
+            }
+            /* fall through */
+            case CHAZ_CONFELEM_TYPEDEF:
+                chaz_ConfWriterC_append_typedef_to_conf(defs[i].str2,
+                                                        defs[i].str1);
+                break;
+            case CHAZ_CONFELEM_SYS_INCLUDE:
+                ++num_globals;
+                break;
+            case CHAZ_CONFELEM_LOCAL_INCLUDE:
+                chaz_ConfWriterC_append_local_include_to_conf(defs[i].str1);
+                break;
+            default:
+                chaz_Util_die("Internal error: bad element type %d",
+                              (int)defs[i].type);
+        }
+    }
+
+    /* Write out short names. */
+    fprintf(chaz_ConfWriterC.fh,

<TRUNCATED>

Reply via email to