[kernel][lib][console] C to C++ conversion

Minimal conversion.
clang-format the result.

Tested: build and run the kernel, validate command line still functions.

Change-Id: I8db5462435e452cc032f8f8f0c6413cfff5286a7
diff --git a/kernel/lib/console/console.c b/kernel/lib/console/console.c
deleted file mode 100644
index 3cd48d5..0000000
--- a/kernel/lib/console/console.c
+++ /dev/null
@@ -1,871 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-// Copyright (c) 2008-2009 Travis Geiselbrecht
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#include <debug.h>
-#include <trace.h>
-#include <assert.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-#include <err.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <kernel/cmdline.h>
-#include <kernel/thread.h>
-#include <kernel/mutex.h>
-#include <lib/console.h>
-#include <lk/init.h>
-
-#ifndef CONSOLE_ENABLE_HISTORY
-#define CONSOLE_ENABLE_HISTORY 1
-#endif
-
-#define LINE_LEN 128
-
-#define PANIC_LINE_LEN 32
-
-#define MAX_NUM_ARGS 16
-
-#define HISTORY_LEN 16
-
-#define LOCAL_TRACE 0
-
-#define WHITESPACE " \t"
-
-/* debug buffer */
-static char *debug_buffer;
-
-/* echo commands? */
-static bool echo = true;
-
-/* command processor state */
-static mutex_t command_lock = MUTEX_INITIAL_VALUE(command_lock);
-int lastresult;
-static bool abort_script;
-
-#if CONSOLE_ENABLE_HISTORY
-/* command history stuff */
-static char *history; // HISTORY_LEN rows of LINE_LEN chars a piece
-static uint history_next;
-
-static void init_history(void);
-static void add_history(const char *line);
-static uint start_history_cursor(void);
-static const char *next_history(uint *cursor);
-static const char *prev_history(uint *cursor);
-static void dump_history(void);
-#endif
-
-// A linear array of statically defined commands.
-extern const cmd __start_commands[];
-extern const cmd __stop_commands[];
-
-static int cmd_help(int argc, const cmd_args *argv, uint32_t flags);
-static int cmd_echo(int argc, const cmd_args *argv, uint32_t flags);
-static int cmd_test(int argc, const cmd_args *argv, uint32_t flags);
-#if CONSOLE_ENABLE_HISTORY
-static int cmd_history(int argc, const cmd_args *argv, uint32_t flags);
-#endif
-
-STATIC_COMMAND_START
-STATIC_COMMAND_MASKED("help", "this list", &cmd_help, CMD_AVAIL_ALWAYS)
-STATIC_COMMAND("echo", NULL, &cmd_echo)
-#if LK_DEBUGLEVEL > 1
-STATIC_COMMAND("test", "test the command processor", &cmd_test)
-#if CONSOLE_ENABLE_HISTORY
-STATIC_COMMAND("history", "command history", &cmd_history)
-#endif
-#endif
-STATIC_COMMAND_END(help);
-
-static void console_init(uint level)
-{
-#if CONSOLE_ENABLE_HISTORY
-    init_history();
-#endif
-}
-
-LK_INIT_HOOK(console, console_init, LK_INIT_LEVEL_HEAP);
-
-#if CONSOLE_ENABLE_HISTORY
-static int cmd_history(int argc, const cmd_args *argv, uint32_t flags)
-{
-    dump_history();
-    return 0;
-}
-
-static inline char *history_line(uint line)
-{
-    return history + line * LINE_LEN;
-}
-
-static inline uint ptrnext(uint ptr)
-{
-    return (ptr + 1) % HISTORY_LEN;
-}
-
-static inline uint ptrprev(uint ptr)
-{
-    return (ptr - 1) % HISTORY_LEN;
-}
-
-static void dump_history(void)
-{
-    printf("command history:\n");
-    uint ptr = ptrprev(history_next);
-    int i;
-    for (i=0; i < HISTORY_LEN; i++) {
-        if (history_line(ptr)[0] != 0)
-            printf("\t%s\n", history_line(ptr));
-        ptr = ptrprev(ptr);
-    }
-}
-
-static void init_history(void)
-{
-    /* allocate and set up the history buffer */
-    history = calloc(1, HISTORY_LEN * LINE_LEN);
-    history_next = 0;
-}
-
-static void add_history(const char *line)
-{
-    // reject some stuff
-    if (line[0] == 0)
-        return;
-
-    uint last = ptrprev(history_next);
-    if (strcmp(line, history_line(last)) == 0)
-        return;
-
-    strlcpy(history_line(history_next), line, LINE_LEN);
-    history_next = ptrnext(history_next);
-}
-
-static uint start_history_cursor(void)
-{
-    return ptrprev(history_next);
-}
-
-static const char *next_history(uint *cursor)
-{
-    uint i = ptrnext(*cursor);
-
-    if (i == history_next)
-        return ""; // can't let the cursor hit the head
-
-    *cursor = i;
-    return history_line(i);
-}
-
-static const char *prev_history(uint *cursor)
-{
-    uint i;
-    const char *str = history_line(*cursor);
-
-    /* if we are already at head, stop here */
-    if (*cursor == history_next)
-        return str;
-
-    /* back up one */
-    i = ptrprev(*cursor);
-
-    /* if the next one is gonna be null */
-    if (history_line(i)[0] == '\0')
-        return str;
-
-    /* update the cursor */
-    *cursor = i;
-    return str;
-}
-#endif
-
-static const cmd *match_command(const char *command, const uint8_t availability_mask)
-{
-    for (const cmd *curr_cmd = __start_commands;
-         curr_cmd != __stop_commands;
-         ++curr_cmd) {
-        if ((availability_mask & curr_cmd->availability_mask) != 0 &&
-            strcmp(command, curr_cmd->cmd_str) == 0) {
-            return curr_cmd;
-        }
-    }
-    return NULL;
-}
-
-static inline int cgetchar(void) {
-    char c;
-    int r = platform_dgetc(&c, true);
-    return (r < 0) ? r : c;
-}
-static inline void cputchar(char c) {
-    platform_dputc(c);
-}
-static inline void cputs(const char* s) {
-    platform_dputs_thread(s, strlen(s));
-}
-
-static int read_debug_line(const char **outbuffer, void *cookie)
-{
-    int pos = 0;
-    int escape_level = 0;
-#if CONSOLE_ENABLE_HISTORY
-    uint history_cursor = start_history_cursor();
-#endif
-
-    char *buffer = debug_buffer;
-
-    for (;;) {
-        /* loop until we get a char */
-        int c;
-        if ((c = cgetchar()) < 0)
-            continue;
-
-//      TRACEF("c = 0x%hhx\n", c);
-
-        if (escape_level == 0) {
-            switch (c) {
-                case '\r':
-                case '\n':
-                    if (echo)
-                        cputchar('\n');
-                    goto done;
-
-                case 0x7f: // backspace or delete
-                case 0x8:
-                    if (pos > 0) {
-                        pos--;
-                        cputs("\b \b"); // wipe out a character
-                    }
-                    break;
-
-                case 0x1b: // escape
-                    escape_level++;
-                    break;
-
-                default:
-                    buffer[pos++] = c;
-                    if (echo)
-                        cputchar(c);
-            }
-        } else if (escape_level == 1) {
-            // inside an escape, look for '['
-            if (c == '[') {
-                escape_level++;
-            } else {
-                // we didn't get it, abort
-                escape_level = 0;
-            }
-        } else { // escape_level > 1
-            switch (c) {
-                case 67: // right arrow
-                    buffer[pos++] = ' ';
-                    if (echo)
-                        cputchar(' ');
-                    break;
-                case 68: // left arrow
-                    if (pos > 0) {
-                        pos--;
-                        if (echo) {
-                            cputs("\b \b"); // wipe out a character
-                        }
-                    }
-                    break;
-#if CONSOLE_ENABLE_HISTORY
-                case 65: // up arrow -- previous history
-                case 66: // down arrow -- next history
-                    // wipe out the current line
-                    while (pos > 0) {
-                        pos--;
-                        if (echo) {
-                            cputs("\b \b"); // wipe out a character
-                        }
-                    }
-
-                    if (c == 65)
-                        strlcpy(buffer, prev_history(&history_cursor), LINE_LEN);
-                    else
-                        strlcpy(buffer, next_history(&history_cursor), LINE_LEN);
-                    pos = strlen(buffer);
-                    if (echo)
-                        cputs(buffer);
-                    break;
-#endif
-                default:
-                    break;
-            }
-            escape_level = 0;
-        }
-
-        /* end of line. */
-        if (pos == (LINE_LEN - 1)) {
-            cputs("\nerror: line too long\n");
-            pos = 0;
-            goto done;
-        }
-    }
-
-done:
-//  dprintf("returning pos %d\n", pos);
-
-    // null terminate
-    buffer[pos] = 0;
-
-#if CONSOLE_ENABLE_HISTORY
-    // add to history
-    add_history(buffer);
-#endif
-
-    // return a pointer to our buffer
-    *outbuffer = buffer;
-
-    return pos;
-}
-
-static int tokenize_command(const char *inbuffer, const char **continuebuffer, char *buffer, size_t buflen, cmd_args *args, int arg_count)
-{
-    int inpos;
-    int outpos;
-    int arg;
-    enum {
-        INITIAL = 0,
-        NEXT_FIELD,
-        SPACE,
-        IN_SPACE,
-        TOKEN,
-        IN_TOKEN,
-        QUOTED_TOKEN,
-        IN_QUOTED_TOKEN,
-        VAR,
-        IN_VAR,
-        COMMAND_SEP,
-    } state;
-    char varname[128];
-    int varnamepos;
-
-    inpos = 0;
-    outpos = 0;
-    arg = 0;
-    varnamepos = 0;
-    state = INITIAL;
-    *continuebuffer = NULL;
-
-    for (;;) {
-        char c = inbuffer[inpos];
-
-//      dprintf(SPEW, "c 0x%hhx state %d arg %d inpos %d pos %d\n", c, state, arg, inpos, outpos);
-
-        switch (state) {
-            case INITIAL:
-            case NEXT_FIELD:
-                if (c == '\0')
-                    goto done;
-                if (isspace(c))
-                    state = SPACE;
-                else if (c == ';')
-                    state = COMMAND_SEP;
-                else
-                    state = TOKEN;
-                break;
-            case SPACE:
-                state = IN_SPACE;
-                break;
-            case IN_SPACE:
-                if (c == '\0')
-                    goto done;
-                if (c == ';') {
-                    state = COMMAND_SEP;
-                } else if (!isspace(c)) {
-                    state = TOKEN;
-                } else {
-                    inpos++; // consume the space
-                }
-                break;
-            case TOKEN:
-                // start of a token
-                DEBUG_ASSERT(c != '\0');
-                if (c == '"') {
-                    // start of a quoted token
-                    state = QUOTED_TOKEN;
-                } else if (c == '$') {
-                    // start of a variable
-                    state = VAR;
-                } else {
-                    // regular, unquoted token
-                    state = IN_TOKEN;
-                    args[arg].str = &buffer[outpos];
-                }
-                break;
-            case IN_TOKEN:
-                if (c == '\0') {
-                    arg++;
-                    goto done;
-                }
-                if (isspace(c) || c == ';') {
-                    arg++;
-                    buffer[outpos] = 0;
-                    outpos++;
-                    /* are we out of tokens? */
-                    if (arg == arg_count)
-                        goto done;
-                    state = NEXT_FIELD;
-                } else {
-                    buffer[outpos] = c;
-                    outpos++;
-                    inpos++;
-                }
-                break;
-            case QUOTED_TOKEN:
-                // start of a quoted token
-                DEBUG_ASSERT(c == '"');
-
-                state = IN_QUOTED_TOKEN;
-                args[arg].str = &buffer[outpos];
-                inpos++; // consume the quote
-                break;
-            case IN_QUOTED_TOKEN:
-                if (c == '\0') {
-                    arg++;
-                    goto done;
-                }
-                if (c == '"') {
-                    arg++;
-                    buffer[outpos] = 0;
-                    outpos++;
-                    /* are we out of tokens? */
-                    if (arg == arg_count)
-                        goto done;
-
-                    state = NEXT_FIELD;
-                }
-                buffer[outpos] = c;
-                outpos++;
-                inpos++;
-                break;
-            case VAR:
-                DEBUG_ASSERT(c == '$');
-
-                state = IN_VAR;
-                args[arg].str = &buffer[outpos];
-                inpos++; // consume the dollar sign
-
-                // initialize the place to store the variable name
-                varnamepos = 0;
-                break;
-            case IN_VAR:
-                if (c == '\0' || isspace(c) || c == ';') {
-                    // hit the end of variable, look it up and stick it inline
-                    varname[varnamepos] = 0;
-#if WITH_LIB_ENV
-                    int rc = env_get(varname, &buffer[outpos], buflen - outpos);
-#else
-                    (void)varname[0]; // nuke a warning
-                    int rc = -1;
-#endif
-                    if (rc < 0) {
-                        buffer[outpos++] = '0';
-                        buffer[outpos++] = 0;
-                    } else {
-                        outpos += strlen(&buffer[outpos]) + 1;
-                    }
-                    arg++;
-                    /* are we out of tokens? */
-                    if (arg == arg_count)
-                        goto done;
-
-                    state = NEXT_FIELD;
-                } else {
-                    varname[varnamepos] = c;
-                    varnamepos++;
-                    inpos++;
-                }
-                break;
-            case COMMAND_SEP:
-                // we hit a ;, so terminate the command and pass the remainder of the command back in continuebuffer
-                DEBUG_ASSERT(c == ';');
-
-                inpos++; // consume the ';'
-                *continuebuffer = &inbuffer[inpos];
-                goto done;
-        }
-    }
-
-done:
-    buffer[outpos] = 0;
-    return arg;
-}
-
-static void convert_args(int argc, cmd_args *argv)
-{
-    int i;
-
-    for (i = 0; i < argc; i++) {
-        unsigned long u = atoul(argv[i].str);
-        argv[i].u = u;
-        argv[i].p = (void *)u;
-        argv[i].i = atol(argv[i].str);
-
-        if (!strcmp(argv[i].str, "true") || !strcmp(argv[i].str, "on")) {
-            argv[i].b = true;
-        } else if (!strcmp(argv[i].str, "false") || !strcmp(argv[i].str, "off")) {
-            argv[i].b = false;
-        } else {
-            argv[i].b = (argv[i].u == 0) ? false : true;
-        }
-    }
-}
-
-
-static zx_status_t command_loop(int (*get_line)(const char **, void *),
-                                void *get_line_cookie, bool showprompt,
-                                bool locked) TA_NO_THREAD_SAFETY_ANALYSIS
-{
-    bool exit;
-#if WITH_LIB_ENV
-    bool report_result;
-#endif
-    cmd_args *args = NULL;
-    const char *buffer;
-    const char *continuebuffer;
-    char *outbuf = NULL;
-
-    args = (cmd_args *) malloc (MAX_NUM_ARGS * sizeof(cmd_args));
-    if (unlikely(args == NULL)) {
-        goto no_mem_error;
-    }
-
-    const size_t outbuflen = 1024;
-    outbuf = malloc(outbuflen);
-    if (unlikely(outbuf == NULL)) {
-        goto no_mem_error;
-    }
-
-    exit = false;
-    continuebuffer = NULL;
-    while (!exit) {
-        // read a new line if it hadn't been split previously and passed back from tokenize_command
-        if (continuebuffer == NULL) {
-            if (showprompt)
-                cputs("] ");
-
-            int len = get_line(&buffer, get_line_cookie);
-            if (len < 0)
-                break;
-            if (len == 0)
-                continue;
-        } else {
-            buffer = continuebuffer;
-        }
-
-//      dprintf("line = '%s'\n", buffer);
-
-        /* tokenize the line */
-        int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen,
-                                    args, MAX_NUM_ARGS);
-        if (argc < 0) {
-            if (showprompt)
-                printf("syntax error\n");
-            continue;
-        } else if (argc == 0) {
-            continue;
-        }
-
-//      dprintf("after tokenize: argc %d\n", argc);
-//      for (int i = 0; i < argc; i++)
-//          dprintf("%d: '%s'\n", i, args[i].str);
-
-        /* convert the args */
-        convert_args(argc, args);
-
-        /* try to match the command */
-        const cmd *command = match_command(args[0].str, CMD_AVAIL_NORMAL);
-        if (!command) {
-            printf("command \"%s\" not found\n", args[0].str);
-            continue;
-        }
-
-        if (!locked)
-            mutex_acquire(&command_lock);
-
-        abort_script = false;
-        lastresult = command->cmd_callback(argc, args, 0);
-
-#if WITH_LIB_ENV
-        bool report_result;
-        env_get_bool("reportresult", &report_result, false);
-        if (report_result) {
-            if (lastresult < 0)
-                printf("FAIL %d\n", lastresult);
-            else
-                printf("PASS %d\n", lastresult);
-        }
-#endif
-
-#if WITH_LIB_ENV
-        // stuff the result in an environment var
-        env_set_int("?", lastresult, true);
-#endif
-
-        // someone must have aborted the current script
-        if (abort_script)
-            exit = true;
-        abort_script = false;
-
-        if (!locked)
-            mutex_release(&command_lock);
-    }
-
-    free(outbuf);
-    free(args);
-    return ZX_OK;
-
-no_mem_error:
-    if (outbuf)
-        free(outbuf);
-
-    if (args)
-        free(args);
-
-    dprintf(INFO, "%s: not enough memory\n", __func__);
-    return ZX_ERR_NO_MEMORY;
-}
-
-void console_abort_script(void)
-{
-    abort_script = true;
-}
-
-static void console_start(void)
-{
-    debug_buffer = malloc(LINE_LEN);
-
-    dprintf(INFO, "entering main console loop\n");
-
-
-    while (command_loop(&read_debug_line, NULL, true, false) == ZX_OK)
-        ;
-
-    dprintf(INFO, "exiting main console loop\n");
-
-    free (debug_buffer);
-}
-
-struct line_read_struct {
-    const char *string;
-    int pos;
-    char *buffer;
-    size_t buflen;
-};
-
-static int fetch_next_line(const char **buffer, void *cookie)
-{
-    struct line_read_struct *lineread = (struct line_read_struct *)cookie;
-
-    // we're done
-    if (lineread->string[lineread->pos] == 0)
-        return -1;
-
-    size_t bufpos = 0;
-    while (lineread->string[lineread->pos] != 0) {
-        if (lineread->string[lineread->pos] == '\n') {
-            lineread->pos++;
-            break;
-        }
-        if (bufpos == (lineread->buflen - 1))
-            break;
-        lineread->buffer[bufpos] = lineread->string[lineread->pos];
-        lineread->pos++;
-        bufpos++;
-    }
-    lineread->buffer[bufpos] = 0;
-
-    *buffer = lineread->buffer;
-
-    return bufpos;
-}
-
-static int console_run_script_etc(const char *string, bool locked)
-{
-    struct line_read_struct lineread;
-
-    lineread.string = string;
-    lineread.pos = 0;
-    lineread.buffer = malloc(LINE_LEN);
-    lineread.buflen = LINE_LEN;
-
-    command_loop(&fetch_next_line, (void *)&lineread, false, locked);
-
-    free(lineread.buffer);
-
-    return lastresult;
-}
-
-int console_run_script(const char *string)
-{
-    return console_run_script_etc(string, false);
-}
-
-int console_run_script_locked(const char *string)
-{
-    return console_run_script_etc(string, true);
-}
-
-console_cmd *console_get_command_handler(const char *commandstr)
-{
-    const cmd *command = match_command(commandstr, CMD_AVAIL_NORMAL);
-
-    if (command)
-        return command->cmd_callback;
-    else
-        return NULL;
-}
-
-static int cmd_help(int argc, const cmd_args *argv, uint32_t flags)
-{
-    printf("command list:\n");
-
-    /* filter out commands based on if we're called at normal or panic time */
-    uint8_t availability_mask = (flags & CMD_FLAG_PANIC) ? CMD_AVAIL_PANIC : CMD_AVAIL_NORMAL;
-
-    for (const cmd *curr_cmd = __start_commands;
-         curr_cmd != __stop_commands;
-         ++curr_cmd) {
-        if ((availability_mask & curr_cmd->availability_mask) == 0) {
-            // Skip commands that aren't available in the current shell.
-            continue;
-        }
-        if (curr_cmd->help_str)
-            printf("\t%-16s: %s\n", curr_cmd->cmd_str, curr_cmd->help_str);
-    }
-
-    return 0;
-}
-
-static int cmd_echo(int argc, const cmd_args *argv, uint32_t flags)
-{
-    if (argc > 1)
-        echo = argv[1].b;
-    return ZX_OK;
-}
-
-static void panic_putc(char c) {
-    platform_pputc(c);
-}
-
-static void panic_puts(const char* str) {
-    for (;;) {
-        char c = *str++;
-        if (c == 0) {
-            break;
-        }
-        platform_pputc(c);
-    }
-}
-
-static int panic_getc(void) {
-    char c;
-    if (platform_pgetc(&c, false) < 0) {
-        return -1;
-    } else {
-        return c;
-    }
-}
-
-static void read_line_panic(char *buffer, const size_t len)
-{
-    size_t pos = 0;
-
-    for (;;) {
-        int c;
-        if ((c = panic_getc()) < 0) {
-            continue;
-        }
-
-        switch (c) {
-            case '\r':
-            case '\n':
-                panic_putc('\n');
-                goto done;
-            case 0x7f: // backspace or delete
-            case 0x8:
-                if (pos > 0) {
-                    pos--;
-                    panic_puts("\b \b"); // wipe out a character
-                }
-                break;
-            default:
-                buffer[pos++] = c;
-                panic_putc(c);
-        }
-        if (pos == (len - 1)) {
-            panic_puts("\nerror: line too long\n");
-            pos = 0;
-            goto done;
-        }
-    }
-done:
-    buffer[pos] = 0;
-}
-
-void panic_shell_start(void)
-{
-    dprintf(INFO, "entering panic shell loop\n");
-    char input_buffer[PANIC_LINE_LEN];
-    cmd_args args[MAX_NUM_ARGS];
-
-    for (;;) {
-        panic_puts("! ");
-        read_line_panic(input_buffer, PANIC_LINE_LEN);
-
-        int argc;
-        char *tok = strtok(input_buffer, WHITESPACE);
-        for (argc = 0; argc < MAX_NUM_ARGS; argc++) {
-            if (tok == NULL) {
-                break;
-            }
-            args[argc].str = tok;
-            tok = strtok(NULL, WHITESPACE);
-        }
-
-        if (argc == 0) {
-            continue;
-        }
-
-        convert_args(argc, args);
-
-        const cmd *command = match_command(args[0].str, CMD_AVAIL_PANIC);
-        if (!command) {
-            panic_puts("command not found\n");
-            continue;
-        }
-
-        command->cmd_callback(argc, args, CMD_FLAG_PANIC);
-    }
-}
-
-#if LK_DEBUGLEVEL > 1
-static int cmd_test(int argc, const cmd_args *argv, uint32_t flags)
-{
-    int i;
-
-    printf("argc %d, argv %p\n", argc, argv);
-    for (i = 0; i < argc; i++)
-        printf("\t%d: str '%s', i %ld, u %#lx, b %d\n", i, argv[i].str, argv[i].i, argv[i].u, argv[i].b);
-
-    return 0;
-}
-#endif
-
-static void kernel_shell_init(uint level)
-{
-    if (cmdline_get_bool("kernel.shell", false)) {
-        console_start();
-    }
-}
-
-LK_INIT_HOOK(kernel_shell, kernel_shell_init, LK_INIT_LEVEL_USER);
diff --git a/kernel/lib/console/console.cpp b/kernel/lib/console/console.cpp
new file mode 100644
index 0000000..408df89
--- /dev/null
+++ b/kernel/lib/console/console.cpp
@@ -0,0 +1,838 @@
+// Copyright 2016 The Fuchsia Authors
+// Copyright (c) 2008-2009 Travis Geiselbrecht
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+#include <lib/console.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <debug.h>
+#include <err.h>
+#include <kernel/cmdline.h>
+#include <kernel/mutex.h>
+#include <kernel/thread.h>
+#include <lk/init.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#ifndef CONSOLE_ENABLE_HISTORY
+#define CONSOLE_ENABLE_HISTORY 1
+#endif
+
+#define LINE_LEN 128
+
+#define PANIC_LINE_LEN 32
+
+#define MAX_NUM_ARGS 16
+
+#define HISTORY_LEN 16
+
+#define LOCAL_TRACE 0
+
+#define WHITESPACE " \t"
+
+/* debug buffer */
+static char* debug_buffer;
+
+/* echo commands? */
+static bool echo = true;
+
+/* command processor state */
+static mutex_t command_lock = MUTEX_INITIAL_VALUE(command_lock);
+int lastresult;
+static bool abort_script;
+
+#if CONSOLE_ENABLE_HISTORY
+/* command history stuff */
+static char* history; // HISTORY_LEN rows of LINE_LEN chars a piece
+static uint history_next;
+
+static void init_history(void);
+static void add_history(const char* line);
+static uint start_history_cursor(void);
+static const char* next_history(uint* cursor);
+static const char* prev_history(uint* cursor);
+static void dump_history(void);
+#endif
+
+// A linear array of statically defined commands.
+extern const cmd __start_commands[];
+extern const cmd __stop_commands[];
+
+static int cmd_help(int argc, const cmd_args* argv, uint32_t flags);
+static int cmd_echo(int argc, const cmd_args* argv, uint32_t flags);
+static int cmd_test(int argc, const cmd_args* argv, uint32_t flags);
+#if CONSOLE_ENABLE_HISTORY
+static int cmd_history(int argc, const cmd_args* argv, uint32_t flags);
+#endif
+
+STATIC_COMMAND_START
+STATIC_COMMAND_MASKED("help", "this list", &cmd_help, CMD_AVAIL_ALWAYS)
+STATIC_COMMAND_MASKED("echo", NULL, &cmd_echo, CMD_AVAIL_ALWAYS)
+#if LK_DEBUGLEVEL > 1
+STATIC_COMMAND_MASKED("test", "test the command processor", &cmd_test, CMD_AVAIL_ALWAYS)
+#if CONSOLE_ENABLE_HISTORY
+STATIC_COMMAND_MASKED("history", "command history", &cmd_history, CMD_AVAIL_ALWAYS)
+#endif
+#endif
+STATIC_COMMAND_END(help);
+
+static void console_init(uint level) {
+#if CONSOLE_ENABLE_HISTORY
+    init_history();
+#endif
+}
+
+LK_INIT_HOOK(console, console_init, LK_INIT_LEVEL_HEAP);
+
+#if CONSOLE_ENABLE_HISTORY
+static int cmd_history(int argc, const cmd_args* argv, uint32_t flags) {
+    dump_history();
+    return 0;
+}
+
+static inline char* history_line(uint line) {
+    return history + line * LINE_LEN;
+}
+
+static inline uint ptrnext(uint ptr) {
+    return (ptr + 1) % HISTORY_LEN;
+}
+
+static inline uint ptrprev(uint ptr) {
+    return (ptr - 1) % HISTORY_LEN;
+}
+
+static void dump_history(void) {
+    printf("command history:\n");
+    uint ptr = ptrprev(history_next);
+    int i;
+    for (i = 0; i < HISTORY_LEN; i++) {
+        if (history_line(ptr)[0] != 0)
+            printf("\t%s\n", history_line(ptr));
+        ptr = ptrprev(ptr);
+    }
+}
+
+static void init_history(void) {
+    /* allocate and set up the history buffer */
+    history = static_cast<char*>(calloc(1, HISTORY_LEN * LINE_LEN));
+    history_next = 0;
+}
+
+static void add_history(const char* line) {
+    // reject some stuff
+    if (line[0] == 0)
+        return;
+
+    uint last = ptrprev(history_next);
+    if (strcmp(line, history_line(last)) == 0)
+        return;
+
+    strlcpy(history_line(history_next), line, LINE_LEN);
+    history_next = ptrnext(history_next);
+}
+
+static uint start_history_cursor(void) {
+    return ptrprev(history_next);
+}
+
+static const char* next_history(uint* cursor) {
+    uint i = ptrnext(*cursor);
+
+    if (i == history_next)
+        return ""; // can't let the cursor hit the head
+
+    *cursor = i;
+    return history_line(i);
+}
+
+static const char* prev_history(uint* cursor) {
+    uint i;
+    const char* str = history_line(*cursor);
+
+    /* if we are already at head, stop here */
+    if (*cursor == history_next)
+        return str;
+
+    /* back up one */
+    i = ptrprev(*cursor);
+
+    /* if the next one is gonna be null */
+    if (history_line(i)[0] == '\0')
+        return str;
+
+    /* update the cursor */
+    *cursor = i;
+    return str;
+}
+#endif
+
+static const cmd* match_command(const char* command, const uint8_t availability_mask) {
+    for (const cmd* curr_cmd = __start_commands;
+         curr_cmd != __stop_commands;
+         ++curr_cmd) {
+        if ((availability_mask & curr_cmd->availability_mask) != 0 &&
+            strcmp(command, curr_cmd->cmd_str) == 0) {
+            return curr_cmd;
+        }
+    }
+    return NULL;
+}
+
+static inline int cgetchar(void) {
+    char c;
+    int r = platform_dgetc(&c, true);
+    return (r < 0) ? r : c;
+}
+static inline void cputchar(char c) {
+    platform_dputc(c);
+}
+static inline void cputs(const char* s) {
+    platform_dputs_thread(s, strlen(s));
+}
+
+static int read_debug_line(const char** outbuffer, void* cookie) {
+    size_t pos = 0;
+    int escape_level = 0;
+#if CONSOLE_ENABLE_HISTORY
+    uint history_cursor = start_history_cursor();
+#endif
+
+    char* buffer = debug_buffer;
+
+    for (;;) {
+        /* loop until we get a char */
+        int ci;
+        if ((ci = cgetchar()) < 0)
+            continue;
+
+        char c = static_cast<char>(ci);
+
+        //      TRACEF("c = 0x%hhx\n", c);
+
+        if (escape_level == 0) {
+            switch (c) {
+            case '\r':
+            case '\n':
+                if (echo)
+                    cputchar('\n');
+                goto done;
+
+            case 0x7f: // backspace or delete
+            case 0x8:
+                if (pos > 0) {
+                    pos--;
+                    cputs("\b \b"); // wipe out a character
+                }
+                break;
+
+            case 0x1b: // escape
+                escape_level++;
+                break;
+
+            default:
+                buffer[pos++] = c;
+                if (echo)
+                    cputchar(c);
+            }
+        } else if (escape_level == 1) {
+            // inside an escape, look for '['
+            if (c == '[') {
+                escape_level++;
+            } else {
+                // we didn't get it, abort
+                escape_level = 0;
+            }
+        } else { // escape_level > 1
+            switch (c) {
+            case 67: // right arrow
+                buffer[pos++] = ' ';
+                if (echo)
+                    cputchar(' ');
+                break;
+            case 68: // left arrow
+                if (pos > 0) {
+                    pos--;
+                    if (echo) {
+                        cputs("\b \b"); // wipe out a character
+                    }
+                }
+                break;
+#if CONSOLE_ENABLE_HISTORY
+            case 65: // up arrow -- previous history
+            case 66: // down arrow -- next history
+                // wipe out the current line
+                while (pos > 0) {
+                    pos--;
+                    if (echo) {
+                        cputs("\b \b"); // wipe out a character
+                    }
+                }
+
+                if (c == 65)
+                    strlcpy(buffer, prev_history(&history_cursor), LINE_LEN);
+                else
+                    strlcpy(buffer, next_history(&history_cursor), LINE_LEN);
+                pos = strlen(buffer);
+                if (echo)
+                    cputs(buffer);
+                break;
+#endif
+            default:
+                break;
+            }
+            escape_level = 0;
+        }
+
+        /* end of line. */
+        if (pos == (LINE_LEN - 1)) {
+            cputs("\nerror: line too long\n");
+            pos = 0;
+            goto done;
+        }
+    }
+
+done:
+    //  dprintf("returning pos %d\n", pos);
+
+    // null terminate
+    buffer[pos] = 0;
+
+#if CONSOLE_ENABLE_HISTORY
+    // add to history
+    add_history(buffer);
+#endif
+
+    // return a pointer to our buffer
+    *outbuffer = buffer;
+
+    return static_cast<int>(pos);
+}
+
+static int tokenize_command(const char* inbuffer, const char** continuebuffer,
+                            char* buffer, size_t buflen, cmd_args* args, int arg_count) {
+    size_t inpos;
+    size_t outpos;
+    int arg;
+    enum {
+        INITIAL = 0,
+        NEXT_FIELD,
+        SPACE,
+        IN_SPACE,
+        TOKEN,
+        IN_TOKEN,
+        QUOTED_TOKEN,
+        IN_QUOTED_TOKEN,
+        VAR,
+        IN_VAR,
+        COMMAND_SEP,
+    } state;
+    char varname[128];
+    size_t varnamepos;
+
+    inpos = 0;
+    outpos = 0;
+    arg = 0;
+    varnamepos = 0;
+    state = INITIAL;
+    *continuebuffer = NULL;
+
+    for (;;) {
+        char c = inbuffer[inpos];
+
+        //      dprintf(SPEW, "c 0x%hhx state %d arg %d inpos %zu pos %zu\n", c, state, arg, inpos, outpos);
+
+        switch (state) {
+        case INITIAL:
+        case NEXT_FIELD:
+            if (c == '\0')
+                goto done;
+            if (isspace(c))
+                state = SPACE;
+            else if (c == ';')
+                state = COMMAND_SEP;
+            else
+                state = TOKEN;
+            break;
+        case SPACE:
+            state = IN_SPACE;
+            break;
+        case IN_SPACE:
+            if (c == '\0')
+                goto done;
+            if (c == ';') {
+                state = COMMAND_SEP;
+            } else if (!isspace(c)) {
+                state = TOKEN;
+            } else {
+                inpos++; // consume the space
+            }
+            break;
+        case TOKEN:
+            // start of a token
+            DEBUG_ASSERT(c != '\0');
+            if (c == '"') {
+                // start of a quoted token
+                state = QUOTED_TOKEN;
+            } else if (c == '$') {
+                // start of a variable
+                state = VAR;
+            } else {
+                // regular, unquoted token
+                state = IN_TOKEN;
+                args[arg].str = &buffer[outpos];
+            }
+            break;
+        case IN_TOKEN:
+            if (c == '\0') {
+                arg++;
+                goto done;
+            }
+            if (isspace(c) || c == ';') {
+                arg++;
+                buffer[outpos] = 0;
+                outpos++;
+                /* are we out of tokens? */
+                if (arg == arg_count)
+                    goto done;
+                state = NEXT_FIELD;
+            } else {
+                buffer[outpos] = c;
+                outpos++;
+                inpos++;
+            }
+            break;
+        case QUOTED_TOKEN:
+            // start of a quoted token
+            DEBUG_ASSERT(c == '"');
+
+            state = IN_QUOTED_TOKEN;
+            args[arg].str = &buffer[outpos];
+            inpos++; // consume the quote
+            break;
+        case IN_QUOTED_TOKEN:
+            if (c == '\0') {
+                arg++;
+                goto done;
+            }
+            if (c == '"') {
+                arg++;
+                buffer[outpos] = 0;
+                outpos++;
+                /* are we out of tokens? */
+                if (arg == arg_count)
+                    goto done;
+
+                state = NEXT_FIELD;
+            }
+            buffer[outpos] = c;
+            outpos++;
+            inpos++;
+            break;
+        case VAR:
+            DEBUG_ASSERT(c == '$');
+
+            state = IN_VAR;
+            args[arg].str = &buffer[outpos];
+            inpos++; // consume the dollar sign
+
+            // initialize the place to store the variable name
+            varnamepos = 0;
+            break;
+        case IN_VAR:
+            if (c == '\0' || isspace(c) || c == ';') {
+                // hit the end of variable, look it up and stick it inline
+                varname[varnamepos] = 0;
+#if WITH_LIB_ENV
+                int rc = env_get(varname, &buffer[outpos], buflen - outpos);
+#else
+                (void)varname[0]; // nuke a warning
+                int rc = -1;
+#endif
+                if (rc < 0) {
+                    buffer[outpos++] = '0';
+                    buffer[outpos++] = 0;
+                } else {
+                    outpos += strlen(&buffer[outpos]) + 1;
+                }
+                arg++;
+                /* are we out of tokens? */
+                if (arg == arg_count)
+                    goto done;
+
+                state = NEXT_FIELD;
+            } else {
+                varname[varnamepos] = c;
+                varnamepos++;
+                inpos++;
+            }
+            break;
+        case COMMAND_SEP:
+            // we hit a ;, so terminate the command and pass the remainder of the command back in continuebuffer
+            DEBUG_ASSERT(c == ';');
+
+            inpos++; // consume the ';'
+            *continuebuffer = &inbuffer[inpos];
+            goto done;
+        }
+    }
+
+done:
+    buffer[outpos] = 0;
+    return arg;
+}
+
+static void convert_args(int argc, cmd_args* argv) {
+    int i;
+
+    for (i = 0; i < argc; i++) {
+        unsigned long u = atoul(argv[i].str);
+        argv[i].u = u;
+        argv[i].p = (void*)u;
+        argv[i].i = atol(argv[i].str);
+
+        if (!strcmp(argv[i].str, "true") || !strcmp(argv[i].str, "on")) {
+            argv[i].b = true;
+        } else if (!strcmp(argv[i].str, "false") || !strcmp(argv[i].str, "off")) {
+            argv[i].b = false;
+        } else {
+            argv[i].b = (argv[i].u == 0) ? false : true;
+        }
+    }
+}
+
+static zx_status_t command_loop(int (*get_line)(const char**, void*),
+                                void* get_line_cookie, bool showprompt,
+                                bool locked) TA_NO_THREAD_SAFETY_ANALYSIS {
+    bool exit;
+#if WITH_LIB_ENV
+    bool report_result;
+#endif
+    cmd_args* args = NULL;
+    const char* buffer;
+    const char* continuebuffer;
+    char* outbuf = NULL;
+
+    args = (cmd_args*)malloc(MAX_NUM_ARGS * sizeof(cmd_args));
+    if (unlikely(args == NULL)) {
+        return ZX_ERR_NO_MEMORY;
+    }
+
+    const size_t outbuflen = 1024;
+    outbuf = static_cast<char*>(malloc(outbuflen));
+    if (unlikely(outbuf == NULL)) {
+        free(args);
+        return ZX_ERR_NO_MEMORY;
+    }
+
+    exit = false;
+    continuebuffer = NULL;
+    while (!exit) {
+        // read a new line if it hadn't been split previously and passed back from tokenize_command
+        if (continuebuffer == NULL) {
+            if (showprompt)
+                cputs("] ");
+
+            int len = get_line(&buffer, get_line_cookie);
+            if (len < 0)
+                break;
+            if (len == 0)
+                continue;
+        } else {
+            buffer = continuebuffer;
+        }
+
+        //      dprintf("line = '%s'\n", buffer);
+
+        /* tokenize the line */
+        int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen,
+                                    args, MAX_NUM_ARGS);
+        if (argc < 0) {
+            if (showprompt)
+                printf("syntax error\n");
+            continue;
+        } else if (argc == 0) {
+            continue;
+        }
+
+        //      dprintf("after tokenize: argc %d\n", argc);
+        //      for (int i = 0; i < argc; i++)
+        //          dprintf("%d: '%s'\n", i, args[i].str);
+
+        /* convert the args */
+        convert_args(argc, args);
+
+        /* try to match the command */
+        const cmd* command = match_command(args[0].str, CMD_AVAIL_NORMAL);
+        if (!command) {
+            printf("command \"%s\" not found\n", args[0].str);
+            continue;
+        }
+
+        if (!locked)
+            mutex_acquire(&command_lock);
+
+        abort_script = false;
+        lastresult = command->cmd_callback(argc, args, 0);
+
+#if WITH_LIB_ENV
+        bool report_result;
+        env_get_bool("reportresult", &report_result, false);
+        if (report_result) {
+            if (lastresult < 0)
+                printf("FAIL %d\n", lastresult);
+            else
+                printf("PASS %d\n", lastresult);
+        }
+#endif
+
+#if WITH_LIB_ENV
+        // stuff the result in an environment var
+        env_set_int("?", lastresult, true);
+#endif
+
+        // someone must have aborted the current script
+        if (abort_script)
+            exit = true;
+        abort_script = false;
+
+        if (!locked)
+            mutex_release(&command_lock);
+    }
+
+    free(outbuf);
+    free(args);
+    return ZX_OK;
+}
+
+void console_abort_script(void) {
+    abort_script = true;
+}
+
+static void console_start(void) {
+    debug_buffer = static_cast<char*>(malloc(LINE_LEN));
+
+    dprintf(INFO, "entering main console loop\n");
+
+    while (command_loop(&read_debug_line, NULL, true, false) == ZX_OK)
+        ;
+
+    dprintf(INFO, "exiting main console loop\n");
+
+    free(debug_buffer);
+}
+
+struct line_read_struct {
+    const char* string;
+    int pos;
+    char* buffer;
+    size_t buflen;
+};
+
+static int fetch_next_line(const char** buffer, void* cookie) {
+    struct line_read_struct* lineread = (struct line_read_struct*)cookie;
+
+    // we're done
+    if (lineread->string[lineread->pos] == 0)
+        return -1;
+
+    size_t bufpos = 0;
+    while (lineread->string[lineread->pos] != 0) {
+        if (lineread->string[lineread->pos] == '\n') {
+            lineread->pos++;
+            break;
+        }
+        if (bufpos == (lineread->buflen - 1))
+            break;
+        lineread->buffer[bufpos] = lineread->string[lineread->pos];
+        lineread->pos++;
+        bufpos++;
+    }
+    lineread->buffer[bufpos] = 0;
+
+    *buffer = lineread->buffer;
+
+    return static_cast<int>(bufpos);
+}
+
+static int console_run_script_etc(const char* string, bool locked) {
+    struct line_read_struct lineread;
+
+    lineread.string = string;
+    lineread.pos = 0;
+    lineread.buffer = static_cast<char*>(malloc(LINE_LEN));
+    lineread.buflen = LINE_LEN;
+
+    command_loop(&fetch_next_line, (void*)&lineread, false, locked);
+
+    free(lineread.buffer);
+
+    return lastresult;
+}
+
+int console_run_script(const char* string) {
+    return console_run_script_etc(string, false);
+}
+
+int console_run_script_locked(const char* string) {
+    return console_run_script_etc(string, true);
+}
+
+console_cmd* console_get_command_handler(const char* commandstr) {
+    const cmd* command = match_command(commandstr, CMD_AVAIL_NORMAL);
+
+    if (command)
+        return command->cmd_callback;
+    else
+        return NULL;
+}
+
+static int cmd_help(int argc, const cmd_args* argv, uint32_t flags) {
+    printf("command list:\n");
+
+    /* filter out commands based on if we're called at normal or panic time */
+    uint8_t availability_mask = (flags & CMD_FLAG_PANIC) ? CMD_AVAIL_PANIC : CMD_AVAIL_NORMAL;
+
+    for (const cmd* curr_cmd = __start_commands;
+         curr_cmd != __stop_commands;
+         ++curr_cmd) {
+        if ((availability_mask & curr_cmd->availability_mask) == 0) {
+            // Skip commands that aren't available in the current shell.
+            continue;
+        }
+        if (curr_cmd->help_str)
+            printf("\t%-16s: %s\n", curr_cmd->cmd_str, curr_cmd->help_str);
+    }
+
+    return 0;
+}
+
+static int cmd_echo(int argc, const cmd_args* argv, uint32_t flags) {
+    if (argc > 1)
+        echo = argv[1].b;
+    return ZX_OK;
+}
+
+static void panic_putc(char c) {
+    platform_pputc(c);
+}
+
+static void panic_puts(const char* str) {
+    for (;;) {
+        char c = *str++;
+        if (c == 0) {
+            break;
+        }
+        platform_pputc(c);
+    }
+}
+
+static int panic_getc(void) {
+    char c;
+    if (platform_pgetc(&c, false) < 0) {
+        return -1;
+    } else {
+        return c;
+    }
+}
+
+static void read_line_panic(char* buffer, const size_t len) {
+    size_t pos = 0;
+
+    for (;;) {
+        int ci;
+        if ((ci = panic_getc()) < 0) {
+            continue;
+        }
+
+        char c = static_cast<char>(ci);
+
+        switch (c) {
+        case '\r':
+        case '\n':
+            panic_putc('\n');
+            goto done;
+        case 0x7f: // backspace or delete
+        case 0x8:
+            if (pos > 0) {
+                pos--;
+                panic_puts("\b \b"); // wipe out a character
+            }
+            break;
+        default:
+            buffer[pos++] = c;
+            panic_putc(c);
+        }
+        if (pos == (len - 1)) {
+            panic_puts("\nerror: line too long\n");
+            pos = 0;
+            goto done;
+        }
+    }
+done:
+    buffer[pos] = 0;
+}
+
+void panic_shell_start(void) {
+    dprintf(INFO, "entering panic shell loop\n");
+    char input_buffer[PANIC_LINE_LEN];
+    cmd_args args[MAX_NUM_ARGS];
+
+    for (;;) {
+        panic_puts("! ");
+        read_line_panic(input_buffer, PANIC_LINE_LEN);
+
+        int argc;
+        char* tok = strtok(input_buffer, WHITESPACE);
+        for (argc = 0; argc < MAX_NUM_ARGS; argc++) {
+            if (tok == NULL) {
+                break;
+            }
+            args[argc].str = tok;
+            tok = strtok(NULL, WHITESPACE);
+        }
+
+        if (argc == 0) {
+            continue;
+        }
+
+        convert_args(argc, args);
+
+        const cmd* command = match_command(args[0].str, CMD_AVAIL_PANIC);
+        if (!command) {
+            panic_puts("command not found\n");
+            continue;
+        }
+
+        command->cmd_callback(argc, args, CMD_FLAG_PANIC);
+    }
+}
+
+#if LK_DEBUGLEVEL > 1
+static int cmd_test(int argc, const cmd_args* argv, uint32_t flags) {
+    int i;
+
+    printf("argc %d, argv %p\n", argc, argv);
+    for (i = 0; i < argc; i++)
+        printf("\t%d: str '%s', i %ld, u %#lx, p %p, b %d\n", i,
+               argv[i].str, argv[i].i, argv[i].u, argv[i].p, argv[i].b);
+
+    return 0;
+}
+#endif
+
+static void kernel_shell_init(uint level) {
+    if (cmdline_get_bool("kernel.shell", false)) {
+        console_start();
+    }
+}
+
+LK_INIT_HOOK(kernel_shell, kernel_shell_init, LK_INIT_LEVEL_USER);
diff --git a/kernel/include/lib/console.h b/kernel/lib/console/include/lib/console.h
similarity index 65%
rename from kernel/include/lib/console.h
rename to kernel/lib/console/include/lib/console.h
index 4a2864d..e575bb3 100644
--- a/kernel/include/lib/console.h
+++ b/kernel/lib/console/include/lib/console.h
@@ -16,27 +16,27 @@
 
 /* command args */
 typedef struct {
-    const char *str;
+    const char* str;
     unsigned long u;
-    void *p;
+    void* p;
     long i;
     bool b;
 } cmd_args;
 
-typedef int console_cmd(int argc, const cmd_args *argv, uint32_t flags);
+typedef int console_cmd(int argc, const cmd_args* argv, uint32_t flags);
 
 #define CMD_AVAIL_NORMAL (0x1 << 0)
-#define CMD_AVAIL_PANIC  (0x1 << 1)
+#define CMD_AVAIL_PANIC (0x1 << 1)
 #define CMD_AVAIL_ALWAYS (CMD_AVAIL_NORMAL | CMD_AVAIL_PANIC)
 
 /* command is happening at crash time */
-#define CMD_FLAG_PANIC   (0x1 << 0)
+#define CMD_FLAG_PANIC (0x1 << 0)
 
 /* a block of commands to register */
 typedef struct {
-    const char *cmd_str;
-    const char *help_str;
-    console_cmd *cmd_callback;
+    const char* cmd_str;
+    const char* help_str;
+    console_cmd* cmd_callback;
     uint8_t availability_mask;
 } cmd;
 
@@ -50,15 +50,17 @@
 #define STATIC_COMMAND_START \
     __USED __SECTION(".data.rel.ro.commands") static const cmd _cmd_list[] = {
 
-#define STATIC_COMMAND_END(name) };                                     \
+#define STATIC_COMMAND_END(name) \
+    }                            \
+    ;
 
-#define STATIC_COMMAND(command_str, help_str, func) { command_str, help_str, func, CMD_AVAIL_NORMAL },
-#define STATIC_COMMAND_MASKED(command_str, help_str, func, availability_mask) { command_str, help_str, func, availability_mask },
+#define STATIC_COMMAND(command_str, help_str, func) {command_str, help_str, func, CMD_AVAIL_NORMAL},
+#define STATIC_COMMAND_MASKED(command_str, help_str, func, availability_mask) {command_str, help_str, func, availability_mask},
 
 /* external api */
-int console_run_script(const char *string);
-int console_run_script_locked(const char *string); // special case from inside a command
-console_cmd *console_get_command_handler(const char *command);
+int console_run_script(const char* string);
+int console_run_script_locked(const char* string); // special case from inside a command
+console_cmd* console_get_command_handler(const char* command);
 void console_abort_script(void);
 
 /* panic shell api */
diff --git a/kernel/lib/console/rules.mk b/kernel/lib/console/rules.mk
index c67b82a..8bffb11 100644
--- a/kernel/lib/console/rules.mk
+++ b/kernel/lib/console/rules.mk
@@ -10,6 +10,6 @@
 MODULE := $(LOCAL_DIR)
 
 MODULE_SRCS += \
-	$(LOCAL_DIR)/console.c
+	$(LOCAL_DIR)/console.cpp
 
 include make/module.mk