Ken Yourek / ucmd

Dependents:   nucleo_ucmd_helloworld

Files at this revision

API Documentation at this revision

Comitter:
kyourek
Date:
Mon Oct 12 21:09:07 2015 +0000
Commit message:
Initial commit of the ucmd library for mbed.; https://github.com/kyourek/ucmd

Changed in this revision

ucArgOpt.c Show annotated file Show diff for this revision Revisions of this file
ucArgOptOwner.c Show annotated file Show diff for this revision Revisions of this file
ucArgTok.c Show annotated file Show diff for this revision Revisions of this file
ucArgTokOwner.c Show annotated file Show diff for this revision Revisions of this file
ucCmdLine.c Show annotated file Show diff for this revision Revisions of this file
ucCmdLineApp.c Show annotated file Show diff for this revision Revisions of this file
ucCmdLineOpt.c Show annotated file Show diff for this revision Revisions of this file
ucCmdLineToks.c Show annotated file Show diff for this revision Revisions of this file
ucCmdParser.c Show annotated file Show diff for this revision Revisions of this file
ucCmdTok.c Show annotated file Show diff for this revision Revisions of this file
ucOpt.c Show annotated file Show diff for this revision Revisions of this file
ucSwitchOpt.c Show annotated file Show diff for this revision Revisions of this file
ucSwitchTok.c Show annotated file Show diff for this revision Revisions of this file
ucTok.c Show annotated file Show diff for this revision Revisions of this file
ucmd.h Show annotated file Show diff for this revision Revisions of this file
ucmd_internal.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucArgOpt.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,252 @@
+#include <stdlib.h>
+#include "ucmd_internal.h"
+
+static const char *boolean_arg_name = "<boolean>";
+static const char *numeric_arg_name = "<numeric>";
+
+ucMemoryManager_INIT(ucArgOpt, ucArgOpt_COUNT);
+
+static ucArgOpt *create(const char *name, const char *desc, ucBool is_required, int min_tok_count, int max_tok_count, ucBool is_boolean, ucBool is_numeric, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next) {
+    return ucArgOpt_init(ucMemoryManager_create(), name, desc, is_required, min_tok_count, max_tok_count, is_boolean, is_numeric, numeric_min, numeric_max, next);
+}
+
+static const char *format_is_required_validation_err(ucArgOpt *p, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name, const char *prefix) {
+
+    /* check if this argument is required */
+    if (ucOpt_is_required((ucOpt*)p)) {
+
+        /* the argument is required, so check that the argument
+           token exists */
+        if (NULL == arg_tok) {
+
+            /* the argument is required, but the token does NOT exist,
+               so there's an error here. Return the appropriate error
+               message */
+            return NULL == switch_name
+                ? ucCmdLine_format_response(cmd, "%sthe argument \"%s\" is required.", prefix, ucOpt_get_name((ucOpt*)p))
+                : ucCmdLine_format_response(cmd, "%sthe argument \"%s\" is required for switch \"%s\".", prefix, ucOpt_get_name((ucOpt*)p), switch_name);
+        }
+    }
+
+    /* return no error */
+    return NULL;
+}
+
+static const char *format_is_boolean_validation_err(ucArgOpt *p, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name, const char *prefix) {
+    ucBool is_bool;
+    if (ucArgOpt_is_boolean(p)) {
+        if (arg_tok) {
+            is_bool = ucTok_is_boolean((ucTok*)arg_tok);
+            if (!is_bool) {
+                return NULL == switch_name
+                    ? ucCmdLine_format_response(cmd, "%sthe argument \"%s\" is not boolean.", prefix, ucTok_get_value(arg_tok))
+                    : ucCmdLine_format_response(cmd, "%sthe \"%s\" argument \"%s\" is not boolean.", prefix, switch_name, ucTok_get_value(arg_tok));
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static const char *format_is_numeric_validation_err(ucArgOpt *p, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name, const char *prefix) {
+    ucBool is_num;
+    double arg_num;
+
+    /* Check if this argument option must be numeric. */
+    if (ucArgOpt_is_numeric(p)) {
+
+        /* Check if the argument token was provided. */
+        if (arg_tok) {
+            
+            /* Parse the argument token into a number. */
+            is_num = ucTok_try_parse_numeric((ucTok*)arg_tok, &arg_num);
+            if (!is_num) {
+
+                /* The argument option requires a number, but the
+                   provided token is not numeric, so return the
+                   appropriate error message. */
+                return NULL == switch_name
+                    ? ucCmdLine_format_response(cmd, "%sthe argument \"%s\" is not numeric.", prefix, ucTok_get_value(arg_tok))
+                    : ucCmdLine_format_response(cmd, "%sthe \"%s\" argument \"%s\" is not numeric.", prefix, switch_name, ucTok_get_value(arg_tok));
+            }
+
+            /* Check that that number is above the lower bound. */
+            if (ucArgOpt_get_numeric_min(p) > arg_num) {
+
+                /* The number is below the lower bound, so return the
+                   appropriate error message. */
+                return NULL == switch_name
+                    ? ucCmdLine_format_response(cmd, "%sthe argument \"%f\" is above the minimum value of \"%f\".", prefix, arg_num, ucArgOpt_get_numeric_min(p))
+                    : ucCmdLine_format_response(cmd, "%sthe \"%s\" argument \"%f\" is above the minimum value of \"%f\".", prefix, switch_name, arg_num, ucArgOpt_get_numeric_min(p));
+            }
+
+            /* Check that the number is below the upper bound. */
+            if (ucArgOpt_get_numeric_max(p) < arg_num) {
+
+                /* The number is above the upper bound, so return the
+                   appropriate error message. */
+                return NULL == switch_name
+                    ? ucCmdLine_format_response(cmd, "%sthe argument \"%f\" is below the maximum value of \"%f\".", prefix, arg_num, ucArgOpt_get_numeric_max(p))
+                    : ucCmdLine_format_response(cmd, "%sthe \"%s\" argument \"%f\" is below the maximum value of \"%f\".", prefix, switch_name, arg_num, ucArgOpt_get_numeric_max(p));
+            }
+        }
+    }
+
+    /* Return no error. */
+    return NULL;
+}
+
+static const char *format_arg_tok_validation_err(ucArgOpt *p, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name, const char *prefix) {
+    const char *err;
+
+    err = format_is_required_validation_err(p, cmd, arg_tok, switch_name, prefix);
+    if (err) return err;
+
+    err = format_is_boolean_validation_err(p, cmd, arg_tok, switch_name, prefix);
+    if (err) return err;
+
+    err = format_is_numeric_validation_err(p, cmd, arg_tok, switch_name, prefix);
+    if (err) return err;
+
+    return NULL;
+}
+
+int ucArgOpt_get_min_tok_count(ucArgOpt *p) {
+    if (NULL == p) return 0;
+    return p->min_tok_count;
+}
+
+int ucArgOpt_get_max_tok_count(ucArgOpt *p) {
+    if (NULL == p) return 0;
+    return p->max_tok_count;
+}
+
+ucBool ucArgOpt_is_boolean(ucArgOpt *p) {
+    if (NULL == p) return ucBool_FALSE;
+    return p->is_boolean;
+}
+
+ucBool ucArgOpt_is_numeric(ucArgOpt *p) {
+    if (NULL == p) return ucBool_FALSE;
+    return p->is_numeric;
+}
+
+ucArgOpt_NUMERIC_TYPE ucArgOpt_get_numeric_min(ucArgOpt *p) {
+    if (NULL == p) return 0;
+    return p->numeric_min;
+}
+
+ucArgOpt_NUMERIC_TYPE ucArgOpt_get_numeric_max(ucArgOpt* p) {
+    if (NULL == p) return 0;
+    return p->numeric_max;
+}
+
+ucArgOpt *ucArgOpt_get_next(ucArgOpt* p) {
+    if (NULL == p) return NULL;
+    return p->next;
+}
+
+ucArgOpt *ucArgOpt_init(ucArgOpt *p, const char *name, const char *desc, ucBool is_required, int min_tok_count, int max_tok_count, ucBool is_boolean, ucBool is_numeric, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next) {
+
+    if (NULL == p) return NULL;
+    if (NULL == ucOpt_init((ucOpt*)p, name, desc, is_required)) return NULL;
+
+    p->min_tok_count = min_tok_count;
+    p->max_tok_count = max_tok_count;
+    p->is_boolean = is_boolean;
+    p->is_numeric = is_numeric;
+    p->numeric_min = numeric_min;
+    p->numeric_max = numeric_max;
+    p->next = next;
+
+    return p;
+}
+
+ucArgOpt *ucArgOpt_create(const char *name, const char *desc, ucArgOpt *next) {
+    return create(name, desc, ucBool_FALSE, 0, 1, ucBool_FALSE, ucBool_FALSE, 0, 0, next);
+}
+
+ucArgOpt *ucArgOpt_create_multiple(const char *name, const char *desc, int min_tok_count, int max_tok_count) {
+    return create(name, desc, min_tok_count > 0 ? ucBool_TRUE : ucBool_FALSE, min_tok_count, max_tok_count, ucBool_FALSE, ucBool_FALSE, 0, 0, NULL);
+}
+
+ucArgOpt *ucArgOpt_create_required(const char *name, const char *desc, ucArgOpt *next) {
+    return create(name, desc, ucBool_TRUE, 1, 1, ucBool_FALSE, ucBool_FALSE, 0, 0, next);
+}
+
+ucArgOpt *ucArgOpt_create_boolean(const char *desc, ucArgOpt *next) {
+    return create(boolean_arg_name, desc, ucBool_FALSE, 0, 1, ucBool_TRUE, ucBool_FALSE, 0, 0, next);
+}
+
+ucArgOpt *ucArgOpt_create_required_boolean(const char *desc, ucArgOpt *next) {
+    return create(boolean_arg_name, desc, ucBool_TRUE, 0, 1, ucBool_TRUE, ucBool_FALSE, 0, 0, next);
+}
+
+ucArgOpt *ucArgOpt_create_numeric(const char *desc, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next) {
+    return create(numeric_arg_name, desc, ucBool_FALSE, 0, 1, ucBool_FALSE, ucBool_TRUE, numeric_min, numeric_max, next);
+}
+
+ucArgOpt *ucArgOpt_create_multiple_numeric(const char *desc, int min_tok_count, int max_tok_count, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max) {
+    return create(numeric_arg_name, desc, min_tok_count > 0 ? ucBool_TRUE : ucBool_FALSE, min_tok_count, max_tok_count, ucBool_FALSE, ucBool_TRUE, numeric_min, numeric_max, NULL);
+}
+
+ucArgOpt *ucArgOpt_create_required_numeric(const char *desc, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next) {
+    return create(numeric_arg_name, desc, ucBool_TRUE, 1, 1, ucBool_FALSE, ucBool_TRUE, numeric_min, numeric_max, next);
+}
+
+const char *ucArgOpt_format_validation_err(ucArgOpt *p, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name) {
+    int tok_count, max_tok_count;
+
+    /* if a switch name was given, then this argument belongs
+       to a switch. Otherwise, it's a command argument. */
+    const char *prefix = switch_name == NULL ? ucOpt_validation_err_invalid_argument_prefix : ucOpt_validation_err_invalid_switch_argument_prefix;
+
+    /* validate the current argument token */
+    const char *err = format_arg_tok_validation_err(p, cmd, arg_tok, switch_name, prefix);
+    if (err) return err;
+
+    /* check if this argument option allows multiple tokens */
+    max_tok_count = ucArgOpt_get_max_tok_count(p);
+    if (1 < max_tok_count) {
+
+        /* loop through the argument tokens */
+        tok_count = arg_tok ? 1 : 0;
+        while (arg_tok) {
+
+            /* get the next argument token in the list */
+            arg_tok = ucArgTok_get_next(arg_tok);
+
+            /* check if this token exists */
+            if (arg_tok) {
+
+                /* increment the number of tokens and make sure it is valid */
+                tok_count++;
+                if (tok_count > max_tok_count) return ucCmdLine_format_response(cmd, "%stoo many arguments for %s.", prefix, ucOpt_get_name((ucOpt*)p));
+
+                /* validate this token */
+                err = format_arg_tok_validation_err(p, cmd, arg_tok, switch_name, prefix);
+                if (err) return err;
+            }
+        }
+
+        /* make sure we have enough tokens */
+        if (tok_count < ucArgOpt_get_min_tok_count(p)) return ucCmdLine_format_response(cmd, "%snot enough arguments for %s.", prefix, ucOpt_get_name((ucOpt*)p));
+    }
+
+    /* if we got here, then no error was found */
+    return NULL;
+}
+
+void ucArgOpt_destroy(ucArgOpt *p) {
+    ucMemoryManager_destroy(p);
+}
+
+void ucArgOpt_destroy_chain(ucArgOpt *p) {
+    ucArgOpt *next = p;
+    while (NULL != next) {
+        p = next;
+        next = ucArgOpt_get_next(p);
+        ucArgOpt_destroy(p);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucArgOptOwner.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,72 @@
+#include "ucmd_internal.h"
+
+ucArgOpt *ucArgOptOwner_get_arg_opt(ucArgOptOwner *p) {
+    if (NULL == p) return NULL;
+    return p->arg_opt;
+}
+
+ucArgOptOwner *ucArgOptOwner_init(ucArgOptOwner *p, const char *name, const char *desc, ucBool is_required, ucArgOpt *arg_opt) {
+    if (NULL == p) return NULL;
+    if (NULL == ucOpt_init((ucOpt*)p, name, desc, is_required)) return NULL;
+    p->arg_opt = arg_opt;
+    return p;
+}
+
+const char *ucArgOptOwner_format_validation_err(ucArgOptOwner *p, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name) {
+    int max_arg_tok_count;
+
+    /* set the prefix for error messages */
+    const char *validation, *prefix = switch_name == NULL ? ucOpt_validation_err_invalid_argument_prefix : ucOpt_validation_err_invalid_switch_argument_prefix;
+
+    /* get the first argument option */
+    ucArgOpt *arg_opt = ucArgOptOwner_get_arg_opt(p);
+
+    /* check if an argument option does NOT exist */
+    if (NULL == arg_opt) {
+
+        /* check if the argumen token DOES exist */
+        if (NULL != arg_tok) {
+
+            /* the option does NOT exist, but the token DOES, so there's an error */
+            return NULL == switch_name
+                ? ucCmdLine_format_response(cmd, "%sno argument options exist for command \"%s\".", prefix, ucTok_get_value(ucCmdLine_get_cmd_tok(cmd)))
+                : ucCmdLine_format_response(cmd, "%sno argument options exist for switch \"%s\".", prefix, switch_name);
+        }
+
+        /* neither the option nor the token exist, so no error here */
+        return NULL;
+    }
+
+    /* loop through all the argument options */
+    max_arg_tok_count = 0;
+    while (NULL != arg_opt) {
+
+        /* validate this argument option agains the current token */
+        validation = ucArgOpt_format_validation_err(arg_opt, cmd, arg_tok, switch_name);
+        if (NULL != validation) return validation;
+
+        /* get the number of tokens that this option allows */
+        max_arg_tok_count = ucArgOpt_get_max_tok_count(arg_opt);
+
+        /* move to the next option and the next token */
+        arg_opt = ucArgOpt_get_next(arg_opt);
+        arg_tok = ucArgTok_get_next(arg_tok);
+    }
+
+    /* check if we have any remaining tokens */
+    if (NULL != arg_tok) {
+
+        /* check if the last argument option does NOT allow multiple tokens */
+        if (2 > max_arg_tok_count) {
+
+            /* we have remaining tokens but no arguments for them, so there's an error */
+            return NULL == switch_name
+                ? ucCmdLine_format_response(cmd, "%sno option exists for argument \"%s\".", prefix, ucTok_get_value(arg_tok))
+                : ucCmdLine_format_response(cmd, "%sno option exists for \"%s\" argument \"%s\".", prefix, switch_name, ucTok_get_value(arg_tok));
+        }
+    }
+
+    /* return no error */
+    return NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucArgTok.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,34 @@
+#include "ucmd_internal.h"
+
+ucArgTok *ucArgTok_get_next(ucArgTok* p) {
+    ucTok *tok;
+    if (NULL == p) return NULL;
+    tok = ucTok_get_next((ucTok*)p);
+    if (NULL == tok) return NULL;
+    if (ucTok_is_switch(tok)) return NULL;
+    return (ucArgTok*)tok;
+}
+
+int ucArgTok_count(ucArgTok* p) {
+    int count = 0;
+    while (NULL != p) {
+        count++;
+        p = ucArgTok_get_next(p);
+    }
+    return count;
+}
+
+ucArgTok *ucArgTok_find(ucArgTok *p, const char *arg_value) {
+    while (NULL != p) {
+        if (ucTok_equals((ucTok*)p, arg_value)) {
+            return p;
+        }
+        p = ucArgTok_get_next(p);
+    }
+    return NULL;
+}
+
+ucBool ucArgTok_contains(ucArgTok* p, const char *arg_value) {
+    return NULL == ucArgTok_find(p, arg_value) ? ucBool_FALSE : ucBool_TRUE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucArgTokOwner.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,12 @@
+#include "ucmd_internal.h"
+
+ucArgTok *ucArgTokOwner_get_arg(ucArgTokOwner *p) {
+    ucTok* tok;
+    if (NULL == p) return NULL;
+
+    tok = ucTok_get_next((ucTok*)p);
+    if (ucTok_is_switch(tok)) return NULL;
+
+    return (ucArgTok*)tok;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucCmdLine.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,199 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "ucmd_internal.h"
+
+ucCmdLine *ucCmdLine_init(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    p->cmd_tok = NULL;
+    p->command_acknowledgment = NULL;
+    p->transmit = NULL;
+    p->transmit_state = NULL;
+    p->is_quiet = ucBool_FALSE;
+    p->is_canceled = NULL;
+    p->is_canceled_state = NULL;
+    p->handle_invalid_command = NULL;
+    p->handle_invalid_command_state = NULL;
+    p->response_terminator = NULL;
+    return p;
+}
+
+ucCmdLine *ucCmdLine_get_instance(void) {
+    static ucCmdLine instance = { 0 };
+    static ucCmdLine *pointer = NULL;
+    if (pointer == NULL) {
+        pointer = ucCmdLine_init(&instance);
+    }
+    return pointer;
+}
+
+ucCmdTok *ucCmdLine_get_cmd_tok(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->cmd_tok;
+}
+
+void ucCmdLine_set_cmd_tok(ucCmdLine *p, ucCmdTok *value) {
+    if (NULL == p) return;
+    p->cmd_tok = value;
+}
+
+ucCmdLineToks *ucCmdLine_get_cmd_toks(ucCmdLine *p, ucCmdLineToks *buffer) {
+    if (NULL == p) return NULL;
+    if (NULL == buffer) return NULL;
+
+    buffer->cmd_tok = ucCmdLine_get_cmd_tok(p);
+    buffer->arg_tok = ucCmdTok_get_arg(buffer->cmd_tok);
+    buffer->switch_tok = ucCmdTok_get_switch(buffer->cmd_tok);
+
+    return buffer;
+}
+
+const char *ucCmdLine_format_response_va(ucCmdLine *p, const char *format, va_list arg_list) {
+    if (NULL == p) return NULL;
+
+	/* TODO: Buffer and copy were added because "usage" uses the command's response in the arg list.
+	   TODO: There's probably a better-performing way to handle that, though. */
+	vsnprintf(p->response_buffer, sizeof(p->response_buffer) - 1, format, arg_list);
+	strcpy(p->response, p->response_buffer);
+    return p->response;
+}
+
+const char *ucCmdLine_format_response(ucCmdLine *p, const char *format, ...) {
+    va_list arg_list;
+    const char *response;
+
+    va_start(arg_list, format);
+    response = ucCmdLine_format_response_va(p, format, arg_list);
+    va_end(arg_list);
+
+    return response;
+}
+
+void ucCmdLine_respond(ucCmdLine *p, const char *response) {
+    if (NULL == p) return;
+    if (NULL == p->transmit) return;
+    if (p->is_quiet) return;
+    p->transmit(response, p->transmit_state);
+}
+
+void ucCmdLine_set_transmit(ucCmdLine *p, ucCmdLine_TransmitFunc *value) {
+    if (NULL == p) return;
+    p->transmit = value;
+}
+
+ucCmdLine_TransmitFunc *ucCmdLine_get_transmit(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->transmit;
+}
+
+ucBool ucCmdLine_is_canceled(ucCmdLine *p) {
+    if (NULL == p) return ucBool_FALSE;
+    if (NULL == p->is_canceled) return ucBool_FALSE;
+    return p->is_canceled(p->is_canceled_state);
+}
+
+void ucCmdLine_set_is_canceled(ucCmdLine *p, ucCmdLine_IsCanceledFunc *value) {
+    if (NULL == p) return;
+    p->is_canceled = value;
+}
+
+ucCmdLine_IsCanceledFunc *ucCmdLine_get_is_canceled(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->is_canceled;
+}
+
+void *ucCmdLine_get_transmit_state(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->transmit_state;
+}
+
+uc_EXPORTED void ucCmdLine_set_transmit_state(ucCmdLine *p, void *value) {
+    if (NULL == p) return;
+    p->transmit_state = value;
+}
+
+void *ucCmdLine_get_is_canceled_state(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->is_canceled_state;
+}
+
+void ucCmdLine_set_is_canceled_state(ucCmdLine *p, void *value) {
+    if (NULL == p) return;
+    p->is_canceled_state = value;
+}
+
+void ucCmdLine_set_is_quiet(ucCmdLine *p, ucBool value) {
+    if (NULL == p) return;
+    p->is_quiet = value;
+}
+
+ucBool ucCmdLine_get_is_quiet(ucCmdLine *p) {
+    if (NULL == p) return ucBool_FALSE;
+    return p->is_quiet;
+}
+
+void ucCmdLine_set_handle_invalid_command(ucCmdLine *p, ucCmdLine_HandleInvalidCommandFunc *value) {
+    if (NULL == p) return;
+    p->handle_invalid_command = value;
+}
+
+ucCmdLine_HandleInvalidCommandFunc *ucCmdLine_get_handle_invalid_command(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->handle_invalid_command;
+}
+
+void ucCmdLine_set_handle_invalid_command_state(ucCmdLine *p, void *value) {
+    if (NULL == p) return;
+    p->handle_invalid_command_state = value;
+}
+
+void *ucCmdLine_get_handle_invalid_command_state(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->handle_invalid_command_state;
+}
+
+ucBool ucCmdLine_handle_invalid_command(ucCmdLine *p, const char *invalid_command) {
+    if (NULL == p) return ucBool_FALSE;
+    if (NULL == p->handle_invalid_command) return ucBool_FALSE;
+    return p->handle_invalid_command(invalid_command, p->handle_invalid_command_state);
+}
+
+size_t ucCmdLine_get_response_size_max(ucCmdLine *p) {
+    if (NULL == p) return 0;
+    return sizeof(p->response);
+}
+
+void ucCmdLine_set_response_terminator(ucCmdLine *p, const char *value) {
+    if (NULL == p) return;
+    p->response_terminator = value;
+}
+
+const char *ucCmdLine_get_response_terminator(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->response_terminator;
+}
+
+void ucCmdLine_set_command_acknowledgment(ucCmdLine *p, const char *value) {
+    if (NULL == p) return;
+    p->command_acknowledgment = value;
+}
+
+const char *ucCmdLine_get_command_acknowledgment(ucCmdLine *p) {
+    if (NULL == p) return NULL;
+    return p->command_acknowledgment;
+}
+
+void ucCmdLine_acknowledge_command(ucCmdLine *p) {
+    const char *command_acknowledgment = ucCmdLine_get_command_acknowledgment(p);
+    if (command_acknowledgment) {
+        ucCmdLine_respond(p, command_acknowledgment);
+    }
+}
+
+void ucCmdLine_terminate_response(ucCmdLine *p) {
+    const char *response_terminator = ucCmdLine_get_response_terminator(p);
+    if (response_terminator) {
+        ucCmdLine_respond(p, response_terminator);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucCmdLineApp.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,214 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ucmd_internal.h"
+
+typedef struct HelpState {
+    ucCmdLineApp *app;
+    ucCmdLineOpt *cmd_opt;
+} HelpState;
+
+typedef struct QuitState {
+    ucCmdLineApp *app;
+} QuitState;
+
+static const char *quit(ucCmdLine *cmd, void *state) {
+    QuitState *s = (QuitState*)state;
+    return ucCmdLineApp_get_escape_response(s->app);
+}
+
+static const char *help(ucCmdLine *cmd, void *state) {
+    HelpState *s;
+    ucArgTok *arg_tok;
+    ucCmdLineOpt *cmd_opt;
+
+    s = (HelpState*)state;
+    cmd_opt = s->cmd_opt;
+
+    arg_tok = ucCmdTok_get_arg(ucCmdLine_get_cmd_tok(cmd));
+    if (NULL != arg_tok) {
+        cmd_opt = ucCmdLineOpt_find_by_name(cmd_opt, ucTok_get_value(arg_tok));
+        if (NULL != cmd_opt) {
+            ucCmdLineOpt_send_help(cmd_opt, cmd);
+            return 0;
+        }
+        ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Invalid command: no option found for \"%s\".", ucTok_get_value(arg_tok)));
+        return 0;
+    }
+
+    ucCmdLine_respond(cmd, "Commands");
+    while (NULL != cmd_opt) {
+        ucOpt_send_help((ucOpt*)cmd_opt, cmd, "\t");
+        cmd_opt = ucCmdLineOpt_get_next(cmd_opt);
+    }
+    ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Type \"%s\" followed by a command name for additional help with that command.", ucCmdLineApp_get_help_command(s->app)));
+
+    return 0;
+}
+
+static ucErr run(ucCmdLineApp *p, ucCmdLineOpt *cmd_opt) {
+    char *command;
+    const char *response;
+    ucCmdTok *cmd_tok;
+    ucCmdLine *cmd;
+    ucCmdLineOpt *quit_opt, *main_opt;
+    HelpState HelpState_s;
+    QuitState QuitState_s;
+
+    if (NULL == p) return -1;
+
+    /* Create options for help and quit. */
+    quit_opt = ucCmdLineOpt_create(quit, &QuitState_s, ucCmdLineApp_get_quit_command(p), "Exits the command interface.", NULL, NULL, cmd_opt);
+    main_opt = ucCmdLineOpt_create(help, &HelpState_s, ucCmdLineApp_get_help_command(p), "Shows command information.", ucArgOpt_create("<command>", "If provided, help is shown for the given command.", NULL), NULL, quit_opt);
+
+    /* Set the state used for the help and quit commands. */
+    QuitState_s.app = p;
+    HelpState_s.app = p;
+    HelpState_s.cmd_opt = main_opt;
+
+    /* Get this app's command object. */
+    cmd = ucCmdLineApp_get_cmd(p);
+
+    /* Show the banner. */
+    ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Type %s to quit.", ucCmdLineApp_get_quit_command(p)));
+    ucCmdLine_respond(cmd, ucCmdLine_format_response(cmd, "Type %s for help.", ucCmdLineApp_get_help_command(p)));
+
+    /* Loop until quit. */
+    for (;;) {
+                
+        /* Read the command. */
+        command = ucCmdLineApp_receive(p);
+
+        /* Parse the input into a command token. */
+        cmd_tok = ucCmdParser_parse(ucCmdLineApp_get_cmd_parser(p), command);
+
+        /* Set the command's parsed command token. */
+        ucCmdLine_set_cmd_tok(cmd, cmd_tok);
+
+        /* Process the command. */
+        response = ucCmdLineOpt_process(main_opt, cmd);
+
+        /* Check if we got a response. */
+        if (response) {
+
+            /* Check if the response is the escape response. */
+            if (0 == strcmp(response, ucCmdLineApp_get_escape_response(p))) {
+
+                /* We've been signaled to quit the app. */
+                break;
+            }
+        }
+    }
+
+    /* Clear the options we created. */
+    ucCmdLineOpt_destroy(quit_opt);
+    ucCmdLineOpt_destroy(main_opt);
+
+    /* If we got here, then the app was quit. */
+    return ucErr_NONE;
+}
+
+void ucCmdLineApp_set_escape_response(ucCmdLineApp *p, const char *value) {
+    if (NULL == p) return;
+    p->escape_response = value;
+}
+
+const char *ucCmdLineApp_get_escape_response(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->escape_response;
+}
+
+void ucCmdLineApp_set_receive(ucCmdLineApp *p, ucCmdLineApp_ReceiveFunc *value) {
+    if (NULL == p) return;
+    p->receive = value;
+}
+
+ucCmdLineApp_ReceiveFunc *ucCmdLineApp_get_receive(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->receive;
+}
+
+void *ucCmdLineApp_get_receive_state(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->receive_state;
+}
+
+void ucCmdLineApp_set_receive_state(ucCmdLineApp *p, void *value) {
+    if (NULL == p) return;
+    p->receive_state = value;
+}
+
+void ucCmdLineApp_set_quit_command(ucCmdLineApp *p, const char *value) {
+    if (NULL == p) return;
+    p->quit_command = value;
+}
+
+const char *ucCmdLineApp_get_quit_command(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->quit_command;
+}
+
+void ucCmdLineApp_set_help_command(ucCmdLineApp *p, const char *value) {
+    if (NULL == p) return;
+    p->help_command = value;
+}
+
+const char *ucCmdLineApp_get_help_command(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->help_command;
+}
+
+void ucCmdLineApp_set_cmd(ucCmdLineApp *p, ucCmdLine *value) {
+    if (NULL == p) return;
+    p->cmd = value;
+}
+
+ucCmdLine *ucCmdLineApp_get_cmd(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->cmd;
+}
+
+ucCmdParser *ucCmdLineApp_get_cmd_parser(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    return p->cmd_parser;
+}
+
+ucCmdLineApp *ucCmdLineApp_init(ucCmdLineApp *p, ucCmdParser *cmd_parser, ucCmdLine *cmd) {
+    if (NULL == p) return NULL;
+    p->cmd = cmd;
+    p->cmd_parser = cmd_parser;
+    p->run = run;
+    p->receive = NULL;
+    p->receive_state = NULL;
+    p->help_command = "help";
+    p->quit_command = "quit";
+    p->escape_response = "\x1b";
+    return p;
+}
+
+ucCmdLineApp *ucCmdLineApp_get_instance(void) {
+    static ucCmdLineApp instance = { 0 };
+    static ucCmdLineApp *pointer = NULL;
+    if (pointer == NULL) {
+        pointer = ucCmdLineApp_init(&instance, ucCmdParser_get_instance(), ucCmdLine_get_instance());
+    }
+    return pointer;
+}
+
+ucErr ucCmdLineApp_run(ucCmdLineApp *p, ucCmdLineOpt *cmd_opt) {
+    if (NULL == p) return -1;
+    if (NULL == p->run) return -2;
+    return p->run(p, cmd_opt);
+}
+
+char *ucCmdLineApp_receive(ucCmdLineApp *p) {
+    if (NULL == p) return NULL;
+    if (NULL == p->receive) return NULL;
+    return p->receive(p->cmd_str, sizeof(p->cmd_str), p->receive_state);
+}
+
+size_t ucCmdLineApp_get_cmd_str_size_max(ucCmdLineApp *p) {
+    if (NULL == p) return 0;
+    return ucCmdLineApp_CMD_STR_SIZE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucCmdLineOpt.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,266 @@
+#include <string.h>
+#include "ucmd_internal.h"
+
+ucMemoryManager_INIT(ucCmdLineOpt, ucCmdLineOpt_COUNT);
+
+static ucCmdLineOpt *create_cmd_line_opt(void) {
+    return ucMemoryManager_create();
+}
+
+static const char *add_opt_to_usage_response(ucOpt *opt, ucCmdLine *cmd, const char *response) {
+    static const char *required_format = "%s %s";
+    static const char *optional_format = "%s [%s]";
+    return ucCmdLine_format_response(
+        cmd,
+        ucOpt_is_required(opt) ? required_format : optional_format,
+        response,
+        ucOpt_get_name(opt)
+    );
+}
+
+static const char *add_arg_opts_to_usage_response(ucArgOpt *arg_opt, ucCmdLine *cmd, const char *response) {
+    
+    while (NULL != arg_opt) {
+        response = add_opt_to_usage_response((ucOpt*)arg_opt, cmd, response);
+        arg_opt = ucArgOpt_get_next(arg_opt);
+    }
+
+    return response;
+}
+
+static void send_arg_opts_help(ucArgOpt *arg_opt, ucCmdLine *cmd, const char *prefix) {
+    while (NULL != arg_opt) {
+        ucOpt_send_help((ucOpt*)arg_opt, cmd, prefix);
+        arg_opt = ucArgOpt_get_next(arg_opt);
+    }
+}
+
+ucCmdLineOpt *ucCmdLineOpt_get_next(ucCmdLineOpt *p) {
+    if (NULL == p) return NULL;
+    return p->next;
+}
+
+ucArgOpt *ucCmdLineOpt_get_arg_opt(ucCmdLineOpt *p) {
+    if (NULL == p) return NULL;
+    return ucArgOptOwner_get_arg_opt((ucArgOptOwner*)p);
+}
+
+ucSwitchOpt *ucCmdLineOpt_get_switch_opt(ucCmdLineOpt *p) {
+    if (NULL == p) return NULL;
+    return p->switch_opt;
+}
+
+ucCmdLineOpt *ucCmdLineOpt_init(ucCmdLineOpt *p, ucCmdLineOpt_Func *func, void* state, const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt* next) {
+    if (NULL == p) return NULL;
+    if (NULL == ucArgOptOwner_init((ucArgOptOwner*)p, name, desc, ucBool_TRUE, arg_opt)) return NULL;
+    p->func = func;
+    p->state = state;
+    p->switch_opt = switch_opt;
+    p->next = next;
+    return p;
+}
+
+ucCmdLineOpt *ucCmdLineOpt_create(ucCmdLineOpt_Func *func, void *state, const char *name, const char *desc, ucArgOpt* arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt *next) {
+    return ucCmdLineOpt_init(create_cmd_line_opt(), func, state, name, desc, arg_opt, switch_opt, next);
+}
+
+ucCmdLineOpt *ucCmdLineOpt_find_by_name(ucCmdLineOpt* p, const char *name) {
+    while (NULL != p) {
+        if (0 == strcmp(name, ucOpt_get_name((ucOpt*)p))) {
+            return p;
+        }
+        p = ucCmdLineOpt_get_next(p);
+    }
+    return NULL;
+}
+
+ucCmdLineOpt_Func *ucCmdLineOpt_get_func(ucCmdLineOpt *p) {
+    if (NULL == p) return NULL;
+    return p->func;
+}
+
+void *ucCmdLineOpt_get_state(ucCmdLineOpt *p) {
+    if (NULL == p) return NULL;
+    return p->state;
+}
+
+void ucCmdLineOpt_send_usage(ucCmdLineOpt *p, ucCmdLine *cmd) {
+    ucSwitchOpt *switch_opt;
+
+    /* start the usage string with the name of the command */
+    const char *response = ucCmdLine_format_response(cmd, "%s", ucOpt_get_name((ucOpt*)p));
+
+    /* add each available argument option of the command
+       to the usage string */
+    response = add_arg_opts_to_usage_response(ucCmdLineOpt_get_arg_opt(p), cmd, response);
+
+    /* loop through each available switch option */
+    switch_opt = ucCmdLineOpt_get_switch_opt(p);
+    while (NULL != switch_opt) {
+
+        /* add it to the usage string */
+        response = add_opt_to_usage_response((ucOpt*)switch_opt, cmd, response);
+
+        /* also add each of the switch's argument options to the
+           usage string */
+        response = add_arg_opts_to_usage_response(ucSwitchOpt_get_arg_opt(switch_opt), cmd, response);
+
+        /* go to the next switch */
+        switch_opt = ucSwitchOpt_get_next(switch_opt);
+    }
+
+    /* send the completed usage string */
+    ucCmdLine_respond(cmd, response);
+}
+
+void ucCmdLineOpt_send_help(ucCmdLineOpt *p, ucCmdLine *cmd) {
+    static const char *single_tab = "\t";
+    static const char *double_tab = "\t\t";
+
+    ucSwitchOpt *switch_opt;
+
+    ucCmdLineOpt_send_usage(p, cmd);
+
+    ucOpt_send_help((ucOpt*)p, cmd, "");
+    send_arg_opts_help(ucCmdLineOpt_get_arg_opt(p), cmd, single_tab);    
+
+    switch_opt = ucCmdLineOpt_get_switch_opt(p);
+    while (NULL != switch_opt) {
+        ucOpt_send_help((ucOpt*)switch_opt, cmd, single_tab);
+        send_arg_opts_help(ucSwitchOpt_get_arg_opt(switch_opt), cmd, double_tab);
+        switch_opt = ucSwitchOpt_get_next(switch_opt);
+    }
+}
+
+const char *ucCmdLineOpt_format_validation_err(ucCmdLineOpt *p, ucCmdLine *cmd) {
+    static const char *invalid_switch = "Invalid switch: ";
+
+    ucCmdTok *cmd_tok;
+    ucSwitchOpt *switch_opt, *found_switch_opt, *next_switch_opt;
+    ucSwitchTok *switch_tok, *found_switch_tok, *next_switch_tok;
+    const char *switch_name, *validation;
+
+    cmd_tok = ucCmdLine_get_cmd_tok(cmd);
+    
+    validation = ucArgOptOwner_format_validation_err((ucArgOptOwner*)p, cmd, ucCmdTok_get_arg(cmd_tok), NULL);
+    if (NULL != validation) return validation;
+
+    switch_tok = ucCmdTok_get_switch(cmd_tok);
+    switch_opt = ucCmdLineOpt_get_switch_opt(p);
+
+    if (NULL == switch_opt) {
+        if (NULL != switch_tok) {
+            return ucCmdLine_format_response(cmd, "%sno switch options exist for command \"%s\".", invalid_switch, ucTok_get_value((ucTok*)cmd_tok));
+        }
+        return NULL;
+    }
+
+    next_switch_tok = switch_tok;
+
+    while (NULL != next_switch_tok) {
+        found_switch_opt = ucSwitchOpt_find(switch_opt, ucTok_get_value((ucTok*)next_switch_tok));
+        if (NULL == found_switch_opt) {
+            return ucCmdLine_format_response(cmd, "%sno option exists for switch \"%s\".", invalid_switch, ucTok_get_value(next_switch_tok));
+        }
+        next_switch_tok = ucSwitchTok_get_next(next_switch_tok);
+    }
+
+    next_switch_opt = switch_opt;
+
+    while (NULL != next_switch_opt) {
+        switch_name = ucOpt_get_name((ucOpt*)next_switch_opt);
+        found_switch_tok = ucSwitchTok_find(switch_tok, switch_name);
+
+        if (ucOpt_is_required((ucOpt*)next_switch_opt)) {
+            if (NULL == found_switch_tok) {
+                return ucCmdLine_format_response(cmd, "%sthe switch \"%s\" is required.", invalid_switch, switch_name);
+            }
+        }
+
+        if (NULL != found_switch_tok) {
+            validation = ucSwitchOpt_format_validation_err(next_switch_opt, cmd, found_switch_tok);
+            if (NULL != validation) return validation;
+        }
+
+        next_switch_opt = ucSwitchOpt_get_next(next_switch_opt);
+    }
+    
+    return NULL;
+}
+
+static const char *internal_process(ucCmdLineOpt *p, ucCmdLine *cmd, ucBool *invalid_command_handled) {
+    ucCmdTok *cmd_tok;
+    ucCmdLineOpt *opt;
+    ucCmdLineOpt_Func *func;
+    const char *cmd_value;
+    const char *validation;
+
+    /* Get the command token of the command structure. */
+    cmd_tok = ucCmdLine_get_cmd_tok(cmd);
+
+    /* Get the command option that we'll process by finding
+    the one that matches the name of the command. */
+    cmd_value = ucTok_get_value((ucTok*)cmd_tok);
+    opt = ucCmdLineOpt_find_by_name(p, cmd_value);
+    if (NULL == opt) {
+
+        /* The command is invalid (meaning it doesn't exist).
+        Try to handle it. */
+        *invalid_command_handled = ucCmdLine_handle_invalid_command(cmd, cmd_value);
+
+        /* If the command was handled, then we don't return an error. */
+        if (*invalid_command_handled) {
+            return NULL;
+        }
+    }
+
+    /* Send an indication that the command was received. */
+    ucCmdLine_acknowledge_command(cmd);
+
+    /* Check to see if the command is unknown. */
+    if (NULL == opt) return ucCmdLine_format_response(cmd, "Invalid command: no option found for \"%s\"", cmd_value);
+
+    /* Validate the command structure against the option.
+    If validation fails, then return the validation result. */
+    validation = ucCmdLineOpt_format_validation_err(opt, cmd);
+    if (validation) return validation;
+
+    /* Get the function callback from the command option. */
+    func = ucCmdLineOpt_get_func(opt);
+    if (NULL == func) return "Invalid function: null pointer";
+
+    /* Invoke the callback. */
+    return func(cmd, ucCmdLineOpt_get_state(opt));
+}
+
+const char *ucCmdLineOpt_process(ucCmdLineOpt* p, ucCmdLine *cmd) {
+    ucBool invalid_command_handled = ucBool_FALSE;
+    const char *response = internal_process(p, cmd, &invalid_command_handled);
+    if (invalid_command_handled) {
+        return response;
+    }
+
+    if (response) {
+        ucCmdLine_respond(cmd, response);
+    }
+
+    ucCmdLine_terminate_response(cmd);
+
+    return response;
+}
+
+void ucCmdLineOpt_destroy(ucCmdLineOpt *p) {
+    ucMemoryManager_destroy(p);
+}
+
+void ucCmdLineOpt_destroy_chain(ucCmdLineOpt *p) {
+    ucCmdLineOpt *next = p;
+    while (NULL != next) {
+        p = next;
+        next = ucCmdLineOpt_get_next(p);
+        ucArgOpt_destroy_chain(ucCmdLineOpt_get_arg_opt(p));
+        ucSwitchOpt_destroy_chain(ucCmdLineOpt_get_switch_opt(p));
+        ucCmdLineOpt_destroy(p);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucCmdLineToks.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,17 @@
+#include "ucmd_internal.h"
+
+ucCmdTok *ucCmdLineToks_get_cmd_tok(ucCmdLineToks *p) {
+    if (NULL == p) return NULL;
+    return p->cmd_tok;
+}
+
+ucArgTok *ucCmdLineToks_get_arg_tok(ucCmdLineToks *p) {
+    if (NULL == p) return NULL;
+    return p->arg_tok;
+}
+
+ucSwitchTok *ucCmdLineToks_get_switch_tok(ucCmdLineToks *p) {
+    if (NULL == p) return NULL;
+    return p->switch_tok;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucCmdParser.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,121 @@
+#include <string.h>
+#include "ucmd_internal.h"
+
+static ucBool is_char_white_space(char c) {
+    /* The native isspace function in ctype.h was giving some weird behavior in the uVision simulator. */
+    return (((c >= 0x09) && (c <= 0x0D)) || (c == 0x020)) ? ucBool_TRUE : ucBool_FALSE;
+}
+
+static char is_char_a_quote(char c) {
+    if (c == '"') return '"';
+    if (c == '\'') return '\'';
+    return 0;
+}
+
+static void remove_cmd_char(char *cmd, int index) {
+    if (NULL == cmd) return;
+    while (cmd[index] != uc_cmd_terminator) {
+        cmd[index] = cmd[index + 1];
+        index++;
+    }
+}
+
+static ucCmdTok *parse(ucCmdParser *p, char *cmd) {
+    int i, j, len;
+    char quote, current_quote;
+
+    if (NULL == cmd) return NULL;
+
+    /* get the length of the whole command */
+    len = strlen(cmd);
+
+    /* replace any command-terminating characters in the string with a space */
+    for (i = 0; i < len; i++) {
+        if (cmd[i] == uc_cmd_terminator) {
+            cmd[i] = ' ';
+        }
+    }
+
+    /* append a command terminator */
+    cmd[len + 1] = uc_cmd_terminator;
+
+    /* loop through each character in the command */
+    i = 0;
+    current_quote = 0;
+    while (cmd[i] != uc_cmd_terminator) {
+
+        /* check if this command character is a quote */
+        quote = is_char_a_quote(cmd[i]);
+        if (quote) {
+
+            /* check if this is our current quote */
+            if (quote == current_quote) {
+
+                /* remove the quote only if this is
+                   not an empty quote */
+                if ((0 < i) && (current_quote != cmd[i - 1])) {
+                    cmd[i] = ' ';
+                }
+
+                /* the quoted item is finished */
+                current_quote = 0;
+            }
+            else {
+
+                /* check if we're NOT in a quote */
+                if (!current_quote) {
+
+                    /* we've started a quote */
+                    current_quote = quote;
+
+                    /* remove the quote character 
+                       only if this is not an empty
+                       quote */
+                    if (current_quote != cmd[i + 1]) {
+                        remove_cmd_char(cmd, i);
+                    }
+                }
+            }
+        }
+
+        /* check if we're not in a quoted string */
+        if (!current_quote) {
+
+            /* check if we're in a token separator */
+            if (is_char_white_space(cmd[i])) {
+
+                /* separate this token */
+                cmd[i] = ucTok_separator;
+
+                /* remove any remaining white space */
+                j = i + 1;
+                while (is_char_white_space(cmd[j])) {
+                    remove_cmd_char(cmd, j);
+                }
+            }
+        }
+
+        /* go to the next character */
+        i++;
+    }
+
+    /* we're done parsing */
+    return (ucCmdTok*)cmd;
+}
+
+ucCmdTok *ucCmdParser_parse(ucCmdParser *p, char *cmd) {
+    if (NULL == p) return NULL;
+    if (NULL == p->parse) return NULL;
+    return p->parse(p, cmd);
+}
+
+ucCmdParser *ucCmdParser_get_instance(void) {
+    static ucCmdParser instance;
+    static ucCmdParser *p = NULL;
+    if (NULL == p) {
+        p = &instance;
+        p->parse = parse;
+    }
+    return p;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucCmdTok.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,19 @@
+#include "ucmd_internal.h"
+
+ucArgTok *ucCmdTok_get_arg(ucCmdTok *p) {
+    return ucArgTokOwner_get_arg((ucArgTokOwner*)p);
+}
+
+ucSwitchTok *ucCmdTok_get_switch(ucCmdTok *p) {
+    ucTok *tok;
+    if (NULL == p) return NULL;
+    tok = ucTok_get_next((ucTok*)p);
+    while (NULL != tok) {
+        if (ucTok_is_switch(tok)) {
+            return (ucSwitchTok*)tok;
+        }
+        tok = ucTok_get_next(tok);
+    }
+    return NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucOpt.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,41 @@
+#include "ucmd_internal.h"
+
+const char *ucOpt_validation_err_invalid_argument_prefix = "Invalid argument: ";
+const char *ucOpt_validation_err_invalid_switch_prefix = "Invalid switch: ";
+const char *ucOpt_validation_err_invalid_switch_argument_prefix = "Invalid switch argument: ";
+
+const char *ucOpt_get_name(ucOpt *p) {
+    if (NULL == p) return NULL;
+    return p->name;
+}
+
+const char *ucOpt_get_desc(ucOpt *p) {
+    if (NULL == p) return NULL;
+    return p->desc;
+}
+
+ucBool ucOpt_is_required(ucOpt *p) {
+    if (NULL == p) return ucBool_FALSE;
+    return p->is_required;
+}
+
+void ucOpt_send_help(ucOpt *p, ucCmdLine *cmd, const char *prefix) {
+    static const char *required_format = "%s%s: %s";
+    static const char *optional_format = "%s[%s]: %s";
+    ucCmdLine_respond(cmd, ucCmdLine_format_response(
+        cmd,
+        ucOpt_is_required(p) ? required_format : optional_format,
+        prefix,
+        ucOpt_get_name(p),
+        ucOpt_get_desc(p)
+    ));
+}
+
+ucOpt *ucOpt_init(ucOpt *p, const char *name, const char *desc, ucBool is_required) {
+    if (NULL == p) return NULL;
+    p->name = name;
+    p->desc = desc;
+    p->is_required = is_required;
+    return p;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucSwitchOpt.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,81 @@
+#include <string.h>
+#include "ucmd_internal.h"
+
+ucMemoryManager_INIT(ucSwitchOpt, ucSwitchOpt_COUNT);
+
+static ucSwitchOpt *create_switch_opt(void) {
+    return ucMemoryManager_create();
+}
+
+ucArgOpt *ucSwitchOpt_get_arg_opt(ucSwitchOpt *p) {
+    return ucArgOptOwner_get_arg_opt((ucArgOptOwner*)p);
+}
+
+ucSwitchOpt *ucSwitchOpt_get_next(ucSwitchOpt *p) {
+    if (NULL == p) return NULL;
+    return p->next;
+}
+
+ucSwitchOpt *ucSwitchOpt_find(ucSwitchOpt *p, const char *name) {
+    while (NULL != p) {
+        if (0 == strcmp(ucOpt_get_name((ucOpt*)p), name)) {
+            return p;
+        }
+        p = ucSwitchOpt_get_next(p);
+    }
+    return NULL;
+}
+
+ucSwitchOpt *ucSwitchOpt_init(ucSwitchOpt *p, const char *name, const char *desc, ucBool is_required, ucArgOpt *arg_opt, ucSwitchOpt *next) {
+    if (NULL == p) return NULL;
+    if (NULL == ucArgOptOwner_init((ucArgOptOwner*)p, name, desc, is_required, arg_opt)) return NULL;
+
+    p->next = next;
+    return p;
+}
+
+ucSwitchOpt *ucSwitchOpt_create(const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *next) {
+    return ucSwitchOpt_init(create_switch_opt(), name, desc, ucBool_FALSE, arg_opt, next);
+}
+
+ucSwitchOpt *ucSwitchOpt_create_required(const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *next) {
+    return ucSwitchOpt_init(create_switch_opt(), name, desc, ucBool_TRUE, arg_opt, next);
+}
+
+void ucSwitchOpt_destroy(ucSwitchOpt *p) {
+    ucMemoryManager_destroy(p);
+}
+
+void ucSwitchOpt_destroy_chain(ucSwitchOpt *p) {
+    ucSwitchOpt *next = p;
+    while (NULL != next) {
+        p = next;
+        next = ucSwitchOpt_get_next(p);
+        ucArgOpt_destroy_chain(ucSwitchOpt_get_arg_opt(p));
+        ucSwitchOpt_destroy(p);
+    }
+}
+
+const char *ucSwitchOpt_format_validation_err(ucSwitchOpt *p, ucCmdLine *cmd, ucSwitchTok *switch_tok) {
+
+    /* check if the switch option is required */
+    if (ucOpt_is_required((ucOpt*)p)) {
+
+        /* check if the switch token is missing */
+        if (NULL == switch_tok) {
+
+            /* the switch is required, but it is not
+               present, so send the error */
+            return ucCmdLine_format_response(cmd, "%sthe switch \"%s\" is required.", ucOpt_validation_err_invalid_switch_prefix, ucOpt_get_name((ucOpt*)p));
+        }
+    }
+
+    /* return the result of the argument validation */
+    return ucArgOptOwner_format_validation_err(
+        (ucArgOptOwner*)p, 
+        cmd, 
+        ucSwitchTok_get_arg(switch_tok), 
+        ucOpt_get_name((ucOpt*)p)
+    );
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucSwitchTok.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,40 @@
+#include "ucmd_internal.h"
+
+ucArgTok *ucSwitchTok_get_arg(ucSwitchTok *p) {
+    return ucArgTokOwner_get_arg((ucArgTokOwner*)p);
+}
+
+ucSwitchTok *ucSwitchTok_get_next(ucSwitchTok *p) {
+    ucTok *tok;
+    if (NULL == p) return NULL;
+    tok = ucTok_get_next((ucTok*)p);
+    while (NULL != tok) {
+        if (ucTok_is_switch(tok)) return (ucSwitchTok*)tok;
+        tok = ucTok_get_next((ucTok*)tok);
+    }
+    return NULL;
+}
+
+int ucSwitchTok_count(ucSwitchTok* p) {
+    int count = 0;
+    while (NULL != p) {
+        count++;
+        p = ucSwitchTok_get_next(p);
+    }
+    return count;
+}
+
+ucSwitchTok *ucSwitchTok_find(ucSwitchTok *p, const char *switch_value) {
+    while (NULL != p) {
+        if (ucTok_equals((ucTok*)p, switch_value)) {
+            return p;
+        }
+        p = ucSwitchTok_get_next(p);
+    }
+    return NULL;
+}
+
+ucBool ucSwitchTok_contains(ucSwitchTok* p, const char *switch_value) {
+    return NULL == ucSwitchTok_find(p, switch_value) ? ucBool_FALSE : ucBool_TRUE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucTok.c	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,248 @@
+#include <stdlib.h>
+#include <string.h>
+#include "ucmd_internal.h"
+
+const char ucTok_separator = '\0';
+const char uc_cmd_terminator = '\n';
+
+static ucBool is_char_digit(char c) {
+    /* The native isdigit function in ctype.h was giving some weird behavior in the uVision simulator. */
+    static const char *digits = "0123456789";
+    const char *d;
+    for (d = digits; *d; d++) {
+        if (*d == c) {
+            return ucBool_TRUE;
+        }
+    }
+    return ucBool_FALSE;
+}
+
+int ucTok_get_length(ucTok *p) {
+    int length;
+    if (NULL == p) return 0;
+
+    for (length = 0; *p != ucTok_separator; length++, p++);
+
+    return length;
+}
+
+const char *ucTok_get_value(ucTok *p) {
+    if (NULL == p) return NULL;
+    return (const char*)p;
+}
+
+ucBool ucTok_equals(ucTok *p, const char *value) {
+    int i, len;
+
+    /* check if these pointers are the same */
+    if (value == p) return ucBool_TRUE;
+
+    /* make sure neither arg is null */
+    if (NULL == p) return ucBool_FALSE;
+    if (NULL == value) return ucBool_FALSE;
+
+    /* check if the string lengths are the same */
+    len = ucTok_get_length(p);
+    if (strlen(value) != len) return ucBool_FALSE;
+
+    /* check for character equality */
+    for (i = 0; i < len; i++) {
+        if (p[i] != value[i]) {
+            return ucBool_FALSE;
+        }
+    }
+
+    /* if we got here, then the strings are equal */
+    return ucBool_TRUE;
+}
+
+ucBool ucTok_is_numeric(ucTok *p) {
+    int i, len;
+    ucBool dec_found;
+
+    /* check if p is NULL */
+    if (NULL == p) return ucBool_FALSE;
+    
+    /* get the length of the string */
+    len = ucTok_get_length(p);
+    
+    /* numbers need to have at least 1 character */
+    if (len < 1) return ucBool_FALSE;
+    
+    /* we are allowed to start with a '-' or '.' for negative numbers and decimals */
+    if ((p[0] == '-') || (p[0] == '.')) {
+        
+        /* but we need more than 1 char if we do */
+        if (len < 2) return ucBool_FALSE;
+    }
+
+    // initialize vars
+    dec_found = ucBool_FALSE;
+
+    /* loop through the chars */
+    for (i = 0; i < len; i++) {
+        
+        switch(p[i]) {
+        
+            /* allow a dash only at the beginning */
+            case '-':
+                if (i != 0) return ucBool_FALSE;
+                break;
+                
+            /* allow only 1 dot */
+            case '.':
+                if (dec_found) return ucBool_FALSE;
+                dec_found = ucBool_TRUE;
+                break;
+                
+            /* everything else has to be a number */
+            default:
+                if (is_char_digit(p[i]) == ucBool_FALSE) return ucBool_FALSE;
+                break;
+        }
+    }
+    
+    /* if we got here, it's a number */
+    return ucBool_TRUE;
+}
+
+ucBool ucTok_try_parse_numeric(ucTok *p, double *value) {
+    if (ucTok_is_numeric(p)) {
+        if (value) {
+            *value = atof(ucTok_get_value(p));
+        }
+        return ucBool_TRUE;
+    }
+    return ucBool_FALSE;
+}
+
+double ucTok_parse_numeric(ucTok *p) {
+    double value = 0;
+    ucTok_try_parse_numeric(p, &value);
+    return value;
+}
+
+ucBool ucTok_is_boolean(ucTok *p) {
+    int i, len;
+    const char *b[] = { ucTok_BOOLEAN_FALSE, ucTok_BOOLEAN_TRUE };
+    if (NULL == p) return ucBool_FALSE;
+    len = sizeof(b) / sizeof(b[0]);
+    for (i = 0; i < len; i++) {
+        if (ucTok_equals(p, b[i])) {
+            return ucBool_TRUE;
+        }
+    }
+    return ucBool_FALSE;
+}
+
+ucBool ucTok_try_parse_boolean(ucTok *p, ucBool *value) {
+    int i, len;
+    const char *t[] = { ucTok_BOOLEAN_TRUE };
+    const char *f[] = { ucTok_BOOLEAN_FALSE };
+    len = sizeof(t) / sizeof(t[0]);
+    for (i = 0; i < len; i++) {
+        if (ucTok_equals(p, t[i])) {
+            if (value) {
+                *value = ucBool_TRUE;
+            }
+            return ucBool_TRUE;
+        }
+    }
+    len = sizeof(f) / sizeof(f[0]);
+    for (i = 0; i < len; i++) {
+        if (ucTok_equals(p, f[i])) {
+            if (value) {
+                *value = ucBool_FALSE;
+            }
+            return ucBool_TRUE;
+        }
+    }
+    return ucBool_FALSE;
+}
+
+ucBool ucTok_parse_boolean(ucTok *p) {
+    ucBool value = ucBool_FALSE;
+    ucTok_try_parse_boolean(p, &value);
+    return value;
+}
+
+ucBool ucTok_is_switch(ucTok* p) {
+    int len = 0;
+
+    /* check for a null pointer */
+    if (NULL == p) return ucBool_FALSE;
+    
+    /* get the length so we can use it */
+    len = ucTok_get_length(p);
+    
+    /* check for at least 2 characters (one '-' and at least another char) */
+    if (len < 2) return ucBool_FALSE;
+    
+    /* check if it starts with a '-' */
+    if (p[0] != '-') return ucBool_FALSE;
+    
+    /* check if this is a numeric argument (negative numbers aren't switches) */
+    if (ucTok_is_numeric(p)) return ucBool_FALSE;
+
+    /* ok, it's a switch */
+    return ucBool_TRUE;
+}
+
+ucTok *ucTok_get_next(ucTok *p) {
+    int i;
+    if (NULL == p) return NULL;
+
+    /* loop until we've hit the max length */
+    i = 0;
+    while (ucTok_LENGTH_MAX > ++i) {
+
+        /* check if the previous character was a separator */
+        if (ucTok_separator == p[i - 1]) {
+
+            /* check if this character is the terminator */
+            if (uc_cmd_terminator == p[i]) {
+
+                /* it is, so no more tokens exist */
+                return NULL;
+            }
+
+            /* make sure this character isn't another separator */
+            if (ucTok_separator == p[i]) {
+                continue;
+            }
+
+            /* the previous character was a separator,
+               and this character is NOT the terminator,
+               OR another separator, so this character is 
+               the start of a new token */
+            return (ucTok*)&p[i];
+        }
+    }
+
+    /* the max length was exceeded,
+       which probably means something
+       went wrong. */
+    return NULL;
+}
+
+int ucTok_count(ucTok *p) {
+    int count;
+
+    /* make sure we have a pointer */
+    if (NULL == p) return 0;
+
+    /* if the first character is the terminator, then we have no tokens */
+    if (p[0] == uc_cmd_terminator) return 0;
+
+    /* start off the count according to whether or not
+       we're starting at a token */
+    count = ucTok_separator == p[0] ? -1 : 0;
+
+    /* count the tokens in the chain */
+    while (NULL != p) {
+        count++;
+        p = ucTok_get_next(p);
+    }
+    return count;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucmd.h	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,1223 @@
+#ifndef UCMD_H
+#define UCMD_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+/* Sets the size of the command buffer when using
+   the command-line application framework. All
+   entered commands must have a size equal to or
+   less than this buffer's size. */
+#ifndef ucCmdLineApp_CMD_STR_SIZE
+#define ucCmdLineApp_CMD_STR_SIZE 200
+#endif
+
+/* Sets the size of the command response buffer.
+   All response strings must have a size equal to
+   or less than the size of this buffer to avoid
+   truncation. */
+#ifndef ucCmdLine_RESPONSE_SIZE
+#define ucCmdLine_RESPONSE_SIZE 200
+#endif
+
+/* Sets the number of available command options.
+   The number of created command options must be
+   equal to or less than this number. */
+#ifndef ucCmdLineOpt_COUNT
+#define ucCmdLineOpt_COUNT 10
+#endif
+
+/* Sets the number of available switch options.
+   The number of created switch options must be
+   equal to or less than this number. */
+#ifndef ucSwitchOpt_COUNT
+#define ucSwitchOpt_COUNT 50
+#endif
+
+/* Sets the number of available argument options.
+   This is the total number of options available
+   to commands and switches, combined. */
+#ifndef ucArgOpt_COUNT
+#define ucArgOpt_COUNT 50
+#endif
+
+/* Sets the maximum expected length of a single
+   token in a command line. */
+#ifndef ucTok_LENGTH_MAX
+#define ucTok_LENGTH_MAX ucCmdLineApp_CMD_STR_SIZE
+#endif
+
+#ifndef ucTok_BOOLEAN_TRUE
+#define ucTok_BOOLEAN_TRUE "1", "on", "yes", "true"
+#endif
+
+#ifndef ucTok_BOOLEAN_FALSE
+#define ucTok_BOOLEAN_FALSE "0", "off", "no", "false"
+#endif
+
+/* Sets the numeric type of numeric argument
+   options. */
+#ifndef ucArgOpt_NUMERIC_TYPE
+#define ucArgOpt_NUMERIC_TYPE double
+#endif
+
+/* Include this def when using the library with another
+   program on Windows.
+   Exported functions will be decorated with dllimport
+   to make them available to external programs. */
+#ifdef uc_DECLSPEC_DLLIMPORT
+#define uc_EXPORTED uc_EXTERN_C __declspec(dllimport)
+#endif
+
+/* Include this def when compiling this program on
+   Windows.
+   Exported functions will be decorated with dllexport
+   to make them available to external programs. */
+#ifdef uc_DECLSPEC_DLLEXPORT
+#define uc_EXPORTED uc_EXTERN_C __declspec(dllexport)
+#endif
+
+/* Prepend extern "C" if we're in a C++
+   compiler. */
+#ifdef __cplusplus
+#define uc_EXTERN_C extern "C"
+#else
+#define uc_EXTERN_C
+#endif
+
+/* Default to setting uc_EXPORTED to the result
+   of our extern "C" check. */
+#ifndef uc_EXPORTED
+#define uc_EXPORTED uc_EXTERN_C
+#endif
+
+/* Define NULL, if it hasn't been defined. */
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+/* 
+ * Summary:
+ *   Definition for the type returned
+ *   by functions that use an error code. 
+ */
+typedef int ucErr;
+
+/* 
+ * Summary:
+ *   Defines the value that represents no error.
+ */
+#define ucErr_NONE 0
+
+/*
+ * Summary:
+ *   Boolean type definition. This definition is used
+ *   to increase the readability of the source by replacing
+ *   integer representations of boolean values with the
+ *   more familiar "true" and "false" values.
+ */
+typedef enum ucBool {
+    ucBool_FALSE = 0,
+    ucBool_TRUE = !ucBool_FALSE
+} ucBool;
+
+/*
+ * Summary:
+ *   Base structure for tokenized values in a command.
+ */
+typedef const char ucTok;
+
+/*
+ * Summary:
+ *   Gets the length of the token.
+ * Returns:
+ *   The number of characters in the token.
+ */
+uc_EXPORTED int ucTok_get_length(ucTok*);
+
+/*
+ * Summary:
+ *   Determines whether or not the given token equals the value.
+ * Parameters:
+ *   value: The value against which the token is checked for equality.
+ * Returns:
+ *   ucBool_TRUE if the token value equals the given value. Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucTok_equals(ucTok*, const char *value);
+
+/*
+ * Summary:
+ *   Determines whether or not the given token is considered numeric.
+ * Returns:
+ *   ucBool_TRUE if the token is considered numeric. Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucTok_is_numeric(ucTok*);
+uc_EXPORTED ucBool ucTok_try_parse_numeric(ucTok*, double *value);
+uc_EXPORTED double ucTok_parse_numeric(ucTok*);
+uc_EXPORTED ucBool ucTok_is_boolean(ucTok*);
+uc_EXPORTED ucBool ucTok_try_parse_boolean(ucTok*, ucBool *value);
+uc_EXPORTED ucBool ucTok_parse_boolean(ucTok*);
+
+/*
+ * Summary:
+ *   Determines whether or not the given token is considered a switch.
+ * Returns:
+ *   ucBool_TRUE if the token is a switch. Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucTok_is_switch(ucTok*);
+
+/*
+ * Summary:
+ *   Gets the next token in the list.
+ * Returns:
+ *   A pointer to the token that comes next in the list, or NULL
+ *   if no further tokens exist.
+ */
+uc_EXPORTED ucTok *ucTok_get_next(ucTok*);
+
+/*
+ * Summary:
+ *   Counts the number of tokens in the linked list.
+ * Returns:
+ *   The number of tokens in the list.
+ */
+uc_EXPORTED int ucTok_count(ucTok*);
+
+/*
+ * Summary:
+ *   Gets the value of the token.
+ * Returns:
+ *   The string value of the token.
+ */
+uc_EXPORTED const char *ucTok_get_value(ucTok*);
+
+/*
+ * Summary:
+ *   An argument token. This type is a child of the
+ *   base token type. All functions that take an 
+ *   instance of the base type can be used with an 
+ *   instance of this type.
+ */
+typedef const char ucArgTok;
+
+/*
+ * Summary:
+ *   Gets the next argument after the given argument.
+ * Returns:
+ *   The next argument in the list.
+ */
+uc_EXPORTED ucArgTok *ucArgTok_get_next(ucArgTok*);
+
+/*
+ * Summary:
+ *   Counts the number of arguments in the linked list.
+ * Returns:
+ *   The number of arguments in the list.
+ */
+uc_EXPORTED int ucArgTok_count(ucArgTok*);
+
+/*
+ * Summary:
+ *   Finds the argument in the list with the specified value.
+ * Parameters:
+ *   arg_value: The value of the argument to find.
+ * Returns:
+ *   The argument with the specified value, or NULL if none exists.
+ */
+uc_EXPORTED ucArgTok *ucArgTok_find(ucArgTok*, const char *arg_value);
+
+/*
+ * Summary:
+ *   Gets a value indicating whether or not the value exists in
+ *   the argument list.
+ * Parameters:
+ *   arg_value: The value of the argument to be found.
+ * Returns:
+ *   ucBool_TRUE if an argument token with the given value is found.
+ *   Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucArgTok_contains(ucArgTok*, const char *arg_value);
+
+/*
+ * Summary:
+ *   Type definition for tokens (i.e. switch and command tokens)
+ *   that contain arguments. This type is a child of the base
+ *   token type. All functions that take an instance of the base
+ *   type can be used with an instance of this type.
+ */
+typedef const char ucArgTokOwner;
+
+/*
+ * Summary
+ *   Gets the first argument that belongs to the given owner.
+ * Returns:
+ *   The first argument that belongs to the owner, or NULL if
+ *   no arguments exist.
+ */
+uc_EXPORTED ucArgTok *ucArgTokOwner_get_arg(ucArgTokOwner*);
+
+/*
+ * Summary:
+ *   A switch token. This type is a child of the
+ *   base token type. All functions that take an 
+ *   instance of the base type can be used with an 
+ *   instance of this type.
+ */
+typedef const char ucSwitchTok;
+
+/*
+ * Summary:
+ *   Gets the next switch token after the given token.
+ * Returns:
+ *   The next switch token after the given token.
+ */
+uc_EXPORTED ucSwitchTok *ucSwitchTok_get_next(ucSwitchTok*);
+
+/*
+ * Summary:
+ *   Counts the number of switches in the linked list.
+ * Returns:
+ *   The number of switches in the list.
+ */
+uc_EXPORTED int ucSwitchTok_count(ucSwitchTok*);
+
+/*
+ * Summary:
+ *   Finds the switch with the specified value.
+ * Parameters:
+ *   switch_value: The value of the switch to be found.
+ * Returns:
+ *   The switch with the specified value, or NULL if none exist.
+ */
+uc_EXPORTED ucSwitchTok *ucSwitchTok_find(ucSwitchTok*, const char *switch_value);
+
+/*
+ * Summary:
+ *   Gets a value indicating whether or not a value exists in the switch list.
+ * Parameters:
+ *   switch_value: The value of the switch to be found.
+ * Returns:
+ *   ucBool_TRUE if a switch with the given value was found in the list. Otherwise,
+ *   ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucSwitchTok_contains(ucSwitchTok*, const char *switch_value);
+
+/*
+ * Summary:
+ *   Gets the first argument token of the switch.
+ * Returns:
+ *   A pointer to the first argument of the switch, or NULL
+ *   if no arguments exist.
+ */
+uc_EXPORTED ucArgTok *ucSwitchTok_get_arg(ucSwitchTok*);
+
+/*
+ * Summary:
+ *   Type definition for a command token. This is
+ *   the first token (the command part) in a list
+ *   of tokens. This type is a child of the base
+ *   token type. All functions that take an instance
+ *   of the base type can be used with an instance
+ *   of this type.
+ */
+typedef const char ucCmdTok;
+
+/*
+ * Summary:
+ *   Gets the first argument of the command.
+ * Returns:
+ *   A pointer to the first argument token, or NULL if no arguments
+ *   exist for the command.
+ */
+uc_EXPORTED ucArgTok *ucCmdTok_get_arg(ucCmdTok*);
+
+/*
+ * Summary:
+ *   Gets the first switch of the command.
+ * Returns:
+ *   A pointer to the first switch token of the command, or NULL
+ *   if no switches exist.
+ */
+uc_EXPORTED ucSwitchTok *ucCmdTok_get_switch(ucCmdTok*);
+
+/*
+ * Summary:
+ *   A group of tokens that represent the first
+ *   of each token type in a command.
+ */
+typedef struct ucCmdLineToks {
+
+    /*
+     * Summary:
+     *   The command token of the command. This token's
+     *   value is the invoked command.
+     */
+    ucCmdTok *cmd_tok;
+
+    /*
+     * Summary:
+     *   The command's first argument token, or
+     *   NULL if no arguments exist.
+     */
+    ucArgTok *arg_tok;
+
+    /*
+     * Summary:
+     *   The command's first switch token, or
+     *   NULL if no switches exist.
+     */
+    ucSwitchTok *switch_tok;
+
+} ucCmdLineToks;
+
+/*
+ * Summary:
+ *   Gets the command token of the command. This token's
+ *   value is the invoked command.
+ * Returns:
+ *   A pointer to the command token.
+ */
+uc_EXPORTED ucCmdTok *ucCmdLineToks_get_cmd_tok(ucCmdLineToks*);
+
+/*
+ * Summary:
+ *   The command's first argument token, or
+ *   NULL if no arguments exist.
+ * Returns:
+ *   A pointer to the argument token, or NULL if no argument
+ *   tokens exist.
+ */
+uc_EXPORTED ucArgTok *ucCmdLineToks_get_arg_tok(ucCmdLineToks*);
+
+/*
+ * Summary:
+ *   The command's first switch token, or
+ *   NULL if no switches exist.
+ * Returns:
+ *   A pointer to the switch token, or NULL if no switch tokens exist.
+ */
+uc_EXPORTED ucSwitchTok *ucCmdLineToks_get_switch_tok(ucCmdLineToks*);
+
+/*
+ * Summary:
+ *   A command structure. This structure consists
+ *   of the parsed command and the ability to respond.
+ */
+typedef struct ucCmdLine ucCmdLine;
+
+/*
+ * Summary:
+ *   The type of function used by a command structure
+ *   to transmit responses.
+ * Parameters:
+ *   response: The string to be transmitted.
+ *   state: A stateful object.
+ */
+typedef void (ucCmdLine_TransmitFunc)(const char *response, void *state);
+
+/*
+ * Summary:
+ *   The type of function used by a command structure
+ *   to determine whether or not the command is canceled.
+ * Parameters:
+ *   state: A stateful object.
+ * Returns:
+ *   ucBool_TRUE if the command has been canceled. Otherwise, ucBool_FALSE.
+ */
+typedef ucBool (ucCmdLine_IsCanceledFunc)(void *state);
+
+/*
+ * Summary:
+ *   The type of the function that is invoked when an
+ *   invalid command is encountered. An invalid command
+ *   is one that does not exist in the list of command
+ *   options.
+ * Parameters:
+ *   invalid_command: The invalid command string that was encountered.
+ *   state: The stateful object for this callback.
+ * Returns:
+ *   ucBool_TRUE if the invalid command was handeled. Otherwise, ucBool_FALSE.
+ */
+typedef ucBool (ucCmdLine_HandleInvalidCommandFunc)(const char *invalid_command, void *state);
+
+/*
+ * Summary:
+ *   Gets the command token from the command structure.
+ * Returns:
+ *   A pointer to the command token of the structure.
+ */
+uc_EXPORTED ucCmdTok *ucCmdLine_get_cmd_tok(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Sets the command token for the structure.
+ * Parameters:
+ *   value: The command token.
+ */
+uc_EXPORTED void ucCmdLine_set_cmd_tok(ucCmdLine*, ucCmdTok *value);
+
+/*
+ * Summary:
+ *   Fills the buffer with the specified tokens of the command structure.
+ * Parameters:
+ *   buffer: A pointer to the token structure whose properties will be set per the command.
+ * Returns:
+ *   A pointer to the buffer.
+ */
+uc_EXPORTED ucCmdLineToks *ucCmdLine_get_cmd_toks(ucCmdLine*, ucCmdLineToks *buffer);
+
+/*
+ * Summary:
+ *   Sets the function used by the command structure to transmit responses.
+ * Parameters:
+ *   value: A pointer to the function used to transmit responses.
+ */
+uc_EXPORTED void ucCmdLine_set_transmit(ucCmdLine*, ucCmdLine_TransmitFunc *value);
+
+/*
+ * Summary:
+ *   Gets the function used by the command structure to transmit responses.
+ * Returns:
+ *   A pointer to the function used by the structure to transmit responses.
+ */
+uc_EXPORTED ucCmdLine_TransmitFunc *ucCmdLine_get_transmit(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Gets the stateful object passed to the command's transmit function.
+ * Returns:
+ *   A pointer to the stateful object passed to the command's transmit function.
+ */
+uc_EXPORTED void *ucCmdLine_get_transmit_state(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Sets the stateful object passed to the command's transmit function.
+ * Parameters:
+ *   value: A pointer to the stateful object that is passed to the command's transmit function.
+ */
+uc_EXPORTED void ucCmdLine_set_transmit_state(ucCmdLine*, void *value);
+
+/*
+ * Summary:
+ *   Determines whether or not the command has been canceled.
+ * Returns:
+ *   ucBool_TRUE if the command has been canceled. Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucCmdLine_is_canceled(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Sets the function used by the command structure to check for cancellation.
+ * Parameters:
+ *   value: A pointer to the function used to check for cancellation.
+ */
+uc_EXPORTED void ucCmdLine_set_is_canceled(ucCmdLine*, ucCmdLine_IsCanceledFunc *value);
+
+/*
+ * Summary:
+ *   Gets the function used by the command structure to check for cancellation.
+ * Returns:
+ *   A pointer to the function used to check for cancellation.
+ */
+uc_EXPORTED ucCmdLine_IsCanceledFunc *ucCmdLine_get_is_canceled(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Gets the stateful object passed to the command's cancellation function.
+ * Returns:
+ *   A pointer to the stateful object passed to the command's cancellation function.
+ */
+uc_EXPORTED void *ucCmdLine_get_is_canceled_state(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Sets the stateful object passed to the command's cancellation function.
+ * Parameters:
+ *   value: The stateful object passed to the command's cancellation function.
+ */
+uc_EXPORTED void ucCmdLine_set_is_canceled_state(ucCmdLine*, void *value);
+
+uc_EXPORTED void ucCmdLine_set_handle_invalid_command(ucCmdLine*, ucCmdLine_HandleInvalidCommandFunc *value);
+
+uc_EXPORTED ucCmdLine_HandleInvalidCommandFunc *ucCmdLine_get_handle_invalid_command(ucCmdLine*);
+
+uc_EXPORTED void ucCmdLine_set_handle_invalid_command_state(ucCmdLine*, void *value);
+
+uc_EXPORTED void *ucCmdLine_get_handle_invalid_command_state(ucCmdLine*);
+
+uc_EXPORTED size_t ucCmdLine_get_response_size_max(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Gets a static, default instance of the command structure.
+ * Returns:
+ *   The static, default instance of the command structure.
+ */
+uc_EXPORTED ucCmdLine *ucCmdLine_get_instance(void);
+
+/*
+ * Summary:
+ *   Formats the command's response using the given parameters.
+ * Parameters:
+ *   format: The format string.
+ *   ...: Parameters to the format string.
+ * Returns:
+ *   The formatted string.
+ */
+uc_EXPORTED const char *ucCmdLine_format_response(ucCmdLine*, const char *format, ...);
+
+/*
+ * Summary:
+ *   Formats the command's response using the given parameters.
+ * Parameters:
+ *   format: The format string.
+ *   arg_list: A variable length argument list with parameters to the format string.
+ * Returns:
+ *   The formatted string.
+ */
+uc_EXPORTED const char *ucCmdLine_format_response_va(ucCmdLine*, const char *format, va_list arg_list);
+
+/*
+ * Summary
+ *   Responds to the command.
+ * Parameters:
+ *   response: The response string.
+ */
+uc_EXPORTED void ucCmdLine_respond(ucCmdLine*, const char *response);
+
+/*
+ * Summary:
+ *   Sets whether or not the command structure is quiet, meaning no response
+ *   strings will be sent.
+ * Parameters:
+ *   value: A boolean true value if the command structure should not send
+ *          any response strings. Otherwise, false.
+ */
+uc_EXPORTED void ucCmdLine_set_is_quiet(ucCmdLine*, ucBool value);
+
+/*
+ * Summary:
+ *   Gets a flag that indicates whether or not the command structure is quiet,
+ *   meaning no response strings are sent.
+ * Returns:
+ *   A boolean true value if the command structure is not sending any
+ *   response strings. Otherwise, false.
+ */
+uc_EXPORTED ucBool ucCmdLine_get_is_quiet(ucCmdLine*);
+
+uc_EXPORTED void            ucCmdLine_acknowledge_command(ucCmdLine*);
+uc_EXPORTED const char*     ucCmdLine_get_command_acknowledgment(ucCmdLine*);
+uc_EXPORTED const char*     ucCmdLine_get_response_terminator(ucCmdLine*);
+uc_EXPORTED void            ucCmdLine_set_response_terminator(ucCmdLine*, const char *value);
+uc_EXPORTED void            ucCmdLine_set_command_acknowledgment(ucCmdLine*, const char *value);
+uc_EXPORTED void            ucCmdLine_terminate_response(ucCmdLine*);
+
+/*
+ * Summary:
+ *   Base type for command, argument, and switch options.
+ */
+typedef struct ucOpt ucOpt;
+
+/*
+ * Summary:
+ *   Gets the name of the option.
+ * Returns:
+ *   The name of the option.
+ */
+uc_EXPORTED const char* ucOpt_get_name(ucOpt*);
+
+/*
+ * Summary:
+ *   Gets the description of the option.
+ * Returns:
+ *   The description of the option.
+ */
+uc_EXPORTED const char *ucOpt_get_desc(ucOpt*);
+
+/*
+ * Summary:
+ *   Gets a flag that indicates whether or not the option
+ *   is required.
+ * Returns:
+ *   ucBool_TRUE if the option is required. Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucOpt_is_required(ucOpt*);
+
+/*
+ * Summary:
+ *   Uses the provided command structure to send help information
+ *   for this option.
+ * Parameters:
+ *   cmd: A pointer to the command structure used to respond
+ *        with the help information.
+ *   prefix: A string used to prefix the help information.
+ */
+uc_EXPORTED void ucOpt_send_help(ucOpt*, ucCmdLine *cmd, const char *prefix);
+
+/*
+ * Summary:
+ *   An argument option. This type is a child
+ *   of the base option type.
+ */
+typedef struct ucArgOpt ucArgOpt;
+
+/*
+ * Summary:
+ *   Gets the minimum allowed token count of the argument option.
+ * Returns:
+ *   The minimum number of argument tokens allowed for this option.
+ */
+uc_EXPORTED int ucArgOpt_get_min_tok_count(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Gets the maximum allowed token count of the argument option.
+ * Returns:
+ *   The maximum number of argument tokens allowed for this option.
+ */
+uc_EXPORTED int ucArgOpt_get_max_tok_count(ucArgOpt*);
+
+uc_EXPORTED ucBool ucArgOpt_is_boolean(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Gets a flag that indicates whether or not this argument option
+ *   is numeric.
+ * Returns:
+ *   ucBool_TRUE if the argument is numeric. Otherwise, ucBool_FALSE.
+ */
+uc_EXPORTED ucBool ucArgOpt_is_numeric(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Gets the minimum value if this argument option is numeric.
+ * Returns:
+ *   The minimum numeric value of the argument.
+ */
+uc_EXPORTED ucArgOpt_NUMERIC_TYPE ucArgOpt_get_numeric_min(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Gets the maximum value if this argument is numeric.
+ * Returns:
+ *   The maximum numeric value of the argument.
+ */
+uc_EXPORTED ucArgOpt_NUMERIC_TYPE ucArgOpt_get_numeric_max(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Creates a new argument option.
+ * Parameters:
+ *   name: The name of the option.
+ *   desc: The description of the option.
+ *   next: The next option in the chain that the created option precedes,
+ *         or NULL if the created option is the last.
+ * Returns:
+ *   A pointer to the newly created argument option.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_create(const char *name, const char *desc, ucArgOpt *next);
+
+/*
+ * Summary:
+ *   Creates a new argument option that allows multiple tokens.
+ * Parameters:
+ *   name: The name of the option.
+ *   desc: The description of the option.
+ *   min_tok_count: The minimum number of argument tokens allowed for this option.
+ *   max_tok_count: The maximum number of argument tokens allowed for this option.
+ * Returns:
+ *   A pointer to the newly created argument option.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_create_multiple(const char *name, const char *desc, int min_tok_count, int max_tok_count);
+
+/*
+ * Summary:
+ *   Creates a new, required argument option.
+ * Parameters:
+ *   name: The name of the option.
+ *   desc: The description of the option.
+ *   next: The next option in the chain that the created option precedes,
+ *         or NULL if the created option is the last.
+ * Returns:
+ *   A pointer to the newly created argument option. The option will have its
+ *   'required' property set to true.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_create_required(const char *name, const char *desc, ucArgOpt *next);
+
+uc_EXPORTED ucArgOpt *ucArgOpt_create_boolean(const char *desc, ucArgOpt *next);
+uc_EXPORTED ucArgOpt *ucArgOpt_create_required_boolean(const char *desc, ucArgOpt *next);
+
+/*
+ * Summary:
+ *   Creates a new, numeric argument option.
+ * Parameters:
+ *   desc: The description of the argument.
+ *   numeric_min: The minimum value of the argument.
+ *   numeric_max: The maximum value of the argument.
+ *   next: A pointer to the next option in the chain that the created option precedes,
+ *         or NULL if the created option is the last.
+ * Returns:
+ *   A pointer to the newly created argument option.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_create_numeric(const char *desc, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next);
+
+/*
+ * Summary:
+ *   Creates a new, numeric argument option that accepts multiple argument tokens.
+ * Parameters:
+ *   desc: The description of the argument.
+ *   min_tok_count: The minimum number of allowed argument tokens.
+ *   max_tok_count: The maximum number of allowed argument tokens.
+ *   numeric_min: The minimum value of the argument.
+ *   numeric_max: The maximum value of the argument.
+ * Returns:
+ *   A pointer to the newly created argument option.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_create_multiple_numeric(const char *desc, int min_tok_count, int max_tok_count, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max);
+
+/*
+ * Summary:
+ *   Creates a new, numeric, required argument option.
+ * Parameters:
+ *   desc: The description of the argument.
+ *   numeric_min: The minimum value of the argument.
+ *   numeric_max: The maximum value of the argument.
+ *   next: A pointer to the next option in the chain that the created option precedes,
+ *         or NULL if the created option is the last.
+ * Returns:
+ *   A pointer to the newly created argument option. The option will have its
+ *   'required' property set to true.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_create_required_numeric(const char *desc, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next);
+
+/*
+ * Summary:
+ *   Gets the next argument option after the given option.
+ * Returns:
+ *   A pointer to the option that the given option precedes,
+ *   or NULL of no further options exist.
+ */
+uc_EXPORTED ucArgOpt *ucArgOpt_get_next(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Releases memory used by the argument option.
+ */
+uc_EXPORTED void ucArgOpt_destroy(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Releases memory used by the argument option
+ *   and all proceeding options in the list.
+ */
+uc_EXPORTED void ucArgOpt_destroy_chain(ucArgOpt*);
+
+/*
+ * Summary:
+ *   Base structure for options (switches and commands)
+ *   that contain argument options. This type is a child
+ *   of the base option type.
+ */
+typedef struct ucArgOptOwner ucArgOptOwner;
+
+/*
+ * Summary:
+ *   Gets the first argument option of the given option owner.
+ * Returns:
+ *   A pointer to the first argument option of the given option owner.
+ */
+uc_EXPORTED ucArgOpt *ucArgOptOwner_get_arg_opt(ucArgOptOwner*);
+
+/*
+ * Summary:
+ *   A command switch option. This type is a child
+ *   of the base option type.
+ */
+typedef struct ucSwitchOpt ucSwitchOpt;
+
+/*
+ * Summary:
+ *   Creates a new switch option.
+ * Parameters:
+ *   name: The name of the switch.
+ *   desc: A description of the switch.
+ *   arg_opt: The first argument option of the switch.
+ *   next: The switch option that the created option precedes,
+ *         or NULL if no further switch options exist.
+ * Returns:
+ *   A pointer to the newly created switch option.
+ */
+uc_EXPORTED ucSwitchOpt *ucSwitchOpt_create(const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *next);
+
+/*
+ * Summary:
+ *   Creates a new, required switch option.
+ * Parameters:
+ *   name: The name of the switch.
+ *   desc: A description of the switch.
+ *   arg_opt: The first argument option of the switch.
+ *   next: The switch option that the created option precedes,
+ *         or NULL if no further switch options exist.
+ * Returns:
+ *   A pointer to the newly created switch option. The option's
+ *   'required' property will be set to true.
+ */
+uc_EXPORTED ucSwitchOpt *ucSwitchOpt_create_required(const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *next);
+
+/*
+ * Summary:
+ *   Gets the first argument option of the given switch.
+ * Returns:
+ *   A pointer to the first argument option of the switch, or NULL
+ *   if no argument options exist.
+ */
+uc_EXPORTED ucArgOpt *ucSwitchOpt_get_arg_opt(ucSwitchOpt*);
+
+/*
+ * Summary:
+ *   Finds the switch option in the linked list with the given name.
+ * Parameters:
+ *   name: The name of the switch option to be found.
+ * Returns:
+ *   The switch option with the given name, or NULL if
+ *   no switch option is found.
+ */
+uc_EXPORTED ucSwitchOpt *ucSwitchOpt_find(ucSwitchOpt*, const char *name);
+
+/*
+ * Summary:
+ *   Gets the next switch option.
+ * Returns:
+ *   A pointer to the next switch option in the list, or NULL
+ *   if no further options exist.
+ */
+uc_EXPORTED ucSwitchOpt *ucSwitchOpt_get_next(ucSwitchOpt*);
+
+/*
+ * Summary:
+ *   Releases memory used by the switch option.
+ */
+uc_EXPORTED void ucSwitchOpt_destroy(ucSwitchOpt*);
+
+/*
+ * Summary:
+ *   Releases memory used by the switch option and all
+ *   proceeding options in the list. All memory used by
+ *   any argument options belonging to the switches in
+ *   the list is also released.
+ */
+uc_EXPORTED void ucSwitchOpt_destroy_chain(ucSwitchOpt*);
+
+/*
+ * Summary:
+ *   Type that can be used to parse command lines.
+ *   The result of the parse can be used as the command
+ *   token for a command structure.
+ */
+typedef struct ucCmdParser ucCmdParser;
+
+/*
+ * Summary:
+ *   Gets a static, default instance of the parser.
+ * Returns:
+ *   The static, default instance of the parser, or NULL
+ *   if an error occurred.
+ */
+uc_EXPORTED ucCmdParser *ucCmdParser_get_instance(void);
+
+/*
+ * Summary:
+ *   Parses a command so that it can be used as a command token.
+ * Parameters:
+ *   cmd: The command string to be parsed. This string is mutated.
+ * Returns:
+ *   A pointer to the command token that was parsed, or NULL if an
+ *   error occurred.
+ */
+uc_EXPORTED ucCmdTok *ucCmdParser_parse(ucCmdParser*, char *cmd);
+
+/*
+ * Summary:
+ *   A command option. This type is a child of the
+ *   base option type.
+ */
+typedef struct ucCmdLineOpt ucCmdLineOpt;
+
+/*
+ * Summary:
+ *   Defines the signature of the function called when a command option is processed.
+ * Parameters:
+ *   cmd: The parsed command structure that represents the function parameters.
+ *   state: The state pointer with which the command option was created.
+ * Returns:
+ *   A message that can be used to respond to the command.
+ */
+typedef const char *(ucCmdLineOpt_Func)(ucCmdLine *cmd, void *state);
+
+/*
+ * Summary:
+ *   Creates a new command option.
+ * Parameters:
+ *   func: A pointer to the function that is called when this command is invoked or selected.
+ *   state: A pointer that gets passed to the function to maintain state.
+ *   name: The name of the command.
+ *   desc: The description of the command.
+ *   arg_opt: The argument options available to the command.
+ *   switch_opt: The switch options available to the command.
+ *   next: The next command that the created command precedes, or NULL if no further commands exist.
+ * Returns:
+ *   A pointer to the newly created command option.
+ */
+uc_EXPORTED ucCmdLineOpt *ucCmdLineOpt_create(ucCmdLineOpt_Func *func, void *state, const char *name, const char *desc, ucArgOpt *arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt* next);
+
+/*
+ * Summary:
+ *   Gets the next command option after the given option.
+ * Returns:
+ *   A pointer to the next command option.
+ */
+uc_EXPORTED ucCmdLineOpt *ucCmdLineOpt_get_next(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Gets the first argument option of the command.
+ * Returns:
+ *   A pointer to the first argument option of the command,
+ *   or NULL if no argument options exist.
+ */
+uc_EXPORTED ucArgOpt *ucCmdLineOpt_get_arg_opt(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Gets the first switch option of the command option.
+ * Returns:
+ *   A pointer to the first switch option of the command option,
+ *   or NULL if no switch options exist.
+ */
+uc_EXPORTED ucSwitchOpt *ucCmdLineOpt_get_switch_opt(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Finds the command option that matches the given name.
+ * Parameters:
+ *   name: The name of the command whose option is to be found.
+ * Returns:
+ *   A pointer to the command option that matches the given name, or NULL
+ *   if no option is found.
+ */
+uc_EXPORTED ucCmdLineOpt *ucCmdLineOpt_find_by_name(ucCmdLineOpt*, const char *name);
+
+/*
+ * Summary:
+ *   Gets the pointer to the function invoked when the command option
+ *   is processed.
+ * Returns:
+ *   A pointer to the function invoked when the command option is processed.
+ */
+uc_EXPORTED ucCmdLineOpt_Func *ucCmdLineOpt_get_func(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Gets the state pointer that is passed to the command option's function
+ *   when it is invoked.
+ * Returns:
+ *   A pointer to the command option's state.
+ */
+uc_EXPORTED void *ucCmdLineOpt_get_state(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Releases memory used by the command option.
+ */
+uc_EXPORTED void ucCmdLineOpt_destroy(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Releases memory used by the command option and all proceeding options
+ *   in the list. All memory used by any argument options, switch options,
+ *   and switch-argument options is also released.
+ */
+uc_EXPORTED void ucCmdLineOpt_destroy_chain(ucCmdLineOpt*);
+
+/*
+ * Summary:
+ *   Invokes the function of the command option that matches the command structure.
+ * Parameters:
+ *   cmd: The command structure whose option is invoked.
+ * Returns:
+ *   The response to the command.
+ */
+uc_EXPORTED const char *ucCmdLineOpt_process(ucCmdLineOpt*, ucCmdLine *cmd);
+
+/*
+ * Summary:
+ *   Uses the provided command structure to respond with a usage string 
+ *   for this command option.
+ * Parameters:
+ *   cmd: The command structure used to respond with the usage string.
+ */
+uc_EXPORTED void ucCmdLineOpt_send_usage(ucCmdLineOpt*, ucCmdLine *cmd);
+
+/*
+ * Summary:
+ *   Uses the provided command structure to respond with help information
+ *   for the this command option.
+ * Parameters:
+ *   cmd: The command structure used to respond with the help information.
+ */
+uc_EXPORTED void ucCmdLineOpt_send_help(ucCmdLineOpt*, ucCmdLine *cmd);
+
+/*
+ * Summary:
+ *   An application that runs with a set of command options.
+ */
+typedef struct ucCmdLineApp ucCmdLineApp;
+
+/*
+ * Summary:
+ *   The type of the function used by an application to
+ *   receive data.
+ * Parameters:
+ *   buf: A string buffer that can be used to store the data received.
+ *   buf_size: The size of the string buffer used to store received data.
+ *   state: A stateful object.
+ * Returns:
+ *   The data that was received.
+ */
+typedef char *(ucCmdLineApp_ReceiveFunc)(char *buf, size_t buf_size, void *state);
+
+/*
+ * Summary:
+ *   Sets the escape string that will cause the app to exit.
+ * Parameters:
+ *   value: The escape string that, when returned in a response,
+ *          causes the app to exit.
+ */
+uc_EXPORTED void ucCmdLineApp_set_escape_response(ucCmdLineApp*, const char *value);
+
+/*
+ * Summary:
+ *   Gets the escape string that causes the app to exit.
+ * Returns:
+ *   The escape string that, when returned in a response,
+ *   causes the app to exit.
+ */
+uc_EXPORTED const char *ucCmdLineApp_get_escape_response(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Runs the application with the given options.
+ * Parameters:
+ *   cmd_opt: A pointer to the first command option for the app.
+ * Returns:
+ *   An error code, if one occurred.
+ */ 
+uc_EXPORTED ucErr ucCmdLineApp_run(ucCmdLineApp*, ucCmdLineOpt *cmd_opt);
+
+/*
+ * Summary:
+ *   Gets a static, default instance of the application.
+ * Returns:
+ *   The static, default instance of the application.
+ */
+uc_EXPORTED ucCmdLineApp *ucCmdLineApp_get_instance(void);
+
+/*
+ * Summary:
+ *   Sets the function that the app uses to receive data.
+ * Parameters:
+ *   value: A pointer to the function used to receive data.
+ */
+uc_EXPORTED void ucCmdLineApp_set_receive(ucCmdLineApp*, ucCmdLineApp_ReceiveFunc *value);
+
+/*
+ * Summary:
+ *   Gets the function that the app uses to receive data.
+ * Returns:
+ *   A pointer to the function used to receive data.
+ */ 
+uc_EXPORTED ucCmdLineApp_ReceiveFunc *ucCmdLineApp_get_receive(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Gets the stateful object passed to the application's receive function.
+ * Returns:
+ *   A pointer to the stateful object passed to the application's receive function.
+ */
+uc_EXPORTED void *ucCmdLineApp_get_receive_state(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Sets the stateful object passed to the application's receive function.
+ * Parameters:
+ *   value: The stateful object passed to the application's receive function.
+ */
+uc_EXPORTED void ucCmdLineApp_set_receive_state(ucCmdLineApp*, void *value);
+
+/*
+ * Summary:
+ *   Sets the command used to quit the application.
+ * Parameters:
+ *   value: The value of the command that quits the application.
+ */
+uc_EXPORTED void ucCmdLineApp_set_quit_command(ucCmdLineApp*, const char *value);
+
+/*
+ * Summary:
+ *   Gets the value of the command that quits the application.
+ * Returns:
+ *   The value of the command that quits the application.
+ */
+uc_EXPORTED const char *ucCmdLineApp_get_quit_command(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Sets the value of the command that shows help information.
+ * Parameters:
+ *   value: The value of the command that shows help information.
+ */
+uc_EXPORTED void ucCmdLineApp_set_help_command(ucCmdLineApp*, const char *value);
+
+/*
+ * Summary:
+ *   Gets the value of the command that shows help information.
+ * Returns:
+ *   The value of the command that shows help information.
+ */
+uc_EXPORTED const char *ucCmdLineApp_get_help_command(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Sets the command structure that the application uses.
+ * Parameters:
+ *   value: The command structure to be used by the application.
+ */
+uc_EXPORTED void ucCmdLineApp_set_cmd(ucCmdLineApp*, ucCmdLine *value);
+
+/*
+ * Summary:
+ *   Gets the command structure used by the application.
+ * Returns:
+ *   A pointer to the command structure used by the application.
+ */
+uc_EXPORTED ucCmdLine *ucCmdLineApp_get_cmd(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Gets the command parser used by the application.
+ * Returns:
+ *   A pointer to the command parser used by the application.
+ */
+uc_EXPORTED ucCmdParser *ucCmdLineApp_get_cmd_parser(ucCmdLineApp*);
+
+/*
+ * Summary:
+ *   Gets the size of the application's command-string buffer.
+ * Returns:
+ *   The size of the command-string buffer.
+ */
+uc_EXPORTED size_t ucCmdLineApp_get_cmd_str_size_max(ucCmdLineApp *p);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucmd_internal.h	Mon Oct 12 21:09:07 2015 +0000
@@ -0,0 +1,131 @@
+#ifndef     UCMD_INTERNAL_H
+#define     UCMD_INTERNAL_H
+
+#include    "ucmd.h"
+
+extern      const char                          uc_cmd_terminator;
+extern      const char                          ucTok_separator;
+extern      const char*                         ucOpt_validation_err_invalid_argument_prefix;
+extern      const char*                         ucOpt_validation_err_invalid_switch_prefix;
+extern      const char*                         ucOpt_validation_err_invalid_switch_argument_prefix;
+
+            struct                              ucCmdParser {
+            ucCmdTok*                           (*parse)(ucCmdParser *p, char *cmd); };
+
+uc_EXPORTED ucOpt*                              ucOpt_init(ucOpt*, const char *name, const char *desc, ucBool is_required);
+            struct                              ucOpt {
+            const char*                         name;
+            const char*                         desc;
+            ucBool                              is_required; };
+
+uc_EXPORTED const char*                         ucArgOpt_format_validation_err(ucArgOpt*, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name);
+uc_EXPORTED ucArgOpt*                           ucArgOpt_init(ucArgOpt*, const char *name, const char *desc, ucBool is_required, int min_tok_count, int max_tok_count, ucBool is_boolean, ucBool is_numeric, ucArgOpt_NUMERIC_TYPE numeric_min, ucArgOpt_NUMERIC_TYPE numeric_max, ucArgOpt *next);
+            struct                              ucArgOpt {
+            ucOpt                               base;
+            ucBool                              is_boolean;
+            ucBool                              is_numeric;
+            ucArgOpt_NUMERIC_TYPE               numeric_min;
+            ucArgOpt_NUMERIC_TYPE               numeric_max;
+            int                                 max_tok_count;
+            int                                 min_tok_count;
+            ucArgOpt*                           next; };            
+
+uc_EXPORTED const char*                         ucArgOptOwner_format_validation_err(ucArgOptOwner*, ucCmdLine *cmd, ucArgTok *arg_tok, const char *switch_name);
+uc_EXPORTED ucArgOptOwner*                      ucArgOptOwner_init(ucArgOptOwner*, const char *name, const char *desc, ucBool is_required, ucArgOpt *arg_opt);
+            struct                              ucArgOptOwner {
+            ucOpt                               base;
+            ucArgOpt*                           arg_opt; };
+
+uc_EXPORTED const char*                         ucSwitchOpt_format_validation_err(ucSwitchOpt*, ucCmdLine *cmd, ucSwitchTok *switch_tok);
+uc_EXPORTED ucSwitchOpt*                        ucSwitchOpt_init(ucSwitchOpt*, const char *name, const char *desc, ucBool is_required, ucArgOpt *arg_opt, ucSwitchOpt *next);
+            struct                              ucSwitchOpt {
+            ucArgOptOwner                       base;
+            ucSwitchOpt*                        next; };
+
+uc_EXPORTED ucBool                              ucCmdLine_handle_invalid_command(ucCmdLine*, const char *invalid_command);
+uc_EXPORTED ucCmdLine*                          ucCmdLine_init(ucCmdLine*);
+            struct                              ucCmdLine {
+            ucCmdTok*                           cmd_tok;
+            ucCmdLine_TransmitFunc*             transmit;
+            ucCmdLine_IsCanceledFunc*           is_canceled;
+            ucCmdLine_HandleInvalidCommandFunc* handle_invalid_command;
+            void*                               transmit_state;
+            void*                               is_canceled_state;
+            void*                               handle_invalid_command_state;
+            const char*                         response_terminator;
+            const char*                         command_acknowledgment;
+            char                                response[ucCmdLine_RESPONSE_SIZE];
+	        char                                response_buffer[ucCmdLine_RESPONSE_SIZE];
+            ucBool                              is_quiet; };
+
+uc_EXPORTED const char*                         ucCmdLineOpt_format_validation_err(ucCmdLineOpt*, ucCmdLine *cmd);
+uc_EXPORTED ucCmdLineOpt*                       ucCmdLineOpt_init(ucCmdLineOpt*, ucCmdLineOpt_Func *func, void* state, const char *name, const char *desc, ucArgOpt* arg_opt, ucSwitchOpt *switch_opt, ucCmdLineOpt *next);
+            struct                              ucCmdLineOpt {
+            ucArgOptOwner                       base;
+            ucCmdLineOpt_Func*                  func;
+            void*                               state;
+            ucSwitchOpt*                        switch_opt;
+            ucCmdLineOpt*                       next; };
+
+uc_EXPORTED ucCmdLineApp*                       ucCmdLineApp_init(ucCmdLineApp*, ucCmdParser*, ucCmdLine*);
+uc_EXPORTED char*                               ucCmdLineApp_receive(ucCmdLineApp*);
+            struct                              ucCmdLineApp {
+            ucCmdLine*                          cmd;
+            ucCmdParser*                        cmd_parser;
+            ucCmdLineApp_ReceiveFunc*           receive;
+            void*                               receive_state;
+            ucErr                               (*run)(ucCmdLineApp *p, ucCmdLineOpt *cmd_opt);
+            const char*                         help_command;
+            const char*                         quit_command;
+            const char*                         escape_response;            
+            char                                cmd_str[ucCmdLineApp_CMD_STR_SIZE + 1]; };
+
+/* 
+ * Summary:
+ *   Defines a macro that is used to provide a dynamic
+ *   feel to static-memory allocation. Calling it in a
+ *   source file exposes functions to create and destroy
+ *   objects of the specified type.
+ * Parameters:
+ *   TYPE: The type of the object instances that are
+ *         created and destroyed using the manager.
+ *   COUNT: The number of object instances that is
+ *          available to the program. Once this number
+ *          is exceeded, NULL is returned from the
+ *          create function until instances are released
+ *          using the destroy function.
+ */
+#define ucMemoryManager_INIT(TYPE, COUNT)                                           \
+    typedef struct ucMemoryManager_Instance {                                       \
+        TYPE inst;                                                                  \
+        char used;                                                                  \
+    } ucMemoryManager_Instance;                                                     \
+                                                                                    \
+    static ucMemoryManager_Instance ucMemoryManager_Instances[COUNT] = { 0 };       \
+                                                                                    \
+    static TYPE *ucMemoryManager_create(void) {                                     \
+        int i;                                                                      \
+        ucMemoryManager_Instance *inst;                                             \
+        for (i = 0; i < COUNT; i++) {                                               \
+            inst = &ucMemoryManager_Instances[i];                                   \
+            if (inst->used == 0) {                                                  \
+                inst->used = 1;                                                     \
+                return &inst->inst;                                                 \
+            }                                                                       \
+        }                                                                           \
+        return NULL;                                                                \
+    }                                                                               \
+                                                                                    \
+    static void ucMemoryManager_destroy(TYPE *p) {                                  \
+        int i;                                                                      \
+        ucMemoryManager_Instance *inst;                                             \
+        for (i = 0; i < COUNT; i++) {                                               \
+            inst = &ucMemoryManager_Instances[i];                                   \
+            if (p == (&inst->inst)) {                                               \
+                inst->used = 0;                                                     \
+            }                                                                       \
+        }                                                                           \
+    }
+
+#endif /* #ifndef UCMD_INTERNAL_H */
+