+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sysexits.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "dcpu16.h"
+
+/*
+ * cli driver for dcpu16 core
+ *
+ * Justin Wind <justin.wind@gmail.com>
+ * 2012 04 10 - implementation started
+ *
+ */
+
+static const char * const src_id_ = "$Id$";
+
+/* global invocation options */
+struct options {
+ unsigned int verbose;
+} opt_ = {
+ .verbose = 0,
+};
+
+#define VERBOSE_PRINTF(...) do { if (opt_.verbose) printf(__VA_ARGS__); } while (0)
+
+static void usage_(char *prog, unsigned int full) {
+ FILE *f = full ? stdout : stderr;
+ char *x = strrchr(prog, '/');
+
+ if (x && *(x + 1))
+ prog = x + 1;
+
+ if (full)
+ fprintf(f, "%s -- \n\n",
+ prog);
+
+ fprintf(f, "Usage: %s [file]\n",
+ prog);
+
+ if (full) {
+ fprintf(f, "\nOptions:\n"
+ "\t [file] -- ram image to load initially\n"
+ "\t -h -- this screen\n"
+ "\t -v -- verbose execution tracing\n");
+
+ fprintf(f, "\n%78s\n", src_id_);
+ }
+}
+
+static
+int file_load_(struct dcpu16 *vm, char *filename) {
+ FILE *f;
+ size_t r;
+
+ f = fopen(filename, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "%s('%s'):%s\n", "fopen", filename, strerror(errno));
+ return -1;
+ }
+
+ r = fread(vm->ram, sizeof(DCPU16_WORD), DCPU16_RAM, f);
+ VERBOSE_PRINTF("read %zu words", r);
+
+ if (ferror(f))
+ fprintf(stderr, "%s('%s'):%s\n", "fread", filename, strerror(errno));
+
+ fclose(f);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int c;
+ char *command;
+ char *prompt = "dcpu16> ";
+ struct dcpu16 *vm;
+
+ while ( (c = getopt(argc, argv, "hv")) != EOF) {
+ switch (c) {
+ case 'v':
+ opt_.verbose++;
+ break;
+
+ case 'h':
+ usage_(argv[0], 1);
+ exit(EX_OK);
+
+ default:
+ usage_(argv[0], 0);
+ exit(EX_USAGE);
+ }
+ }
+ if (opt_.verbose < 1) {
+ dcpu16_warn_cb_set(NULL);
+ dcpu16_trace_cb_set(NULL);
+ } else if (opt_.verbose < 2) {
+ dcpu16_trace_cb_set(NULL);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((vm = dcpu16_new()) == NULL) {
+ fprintf(stderr, "could not allocate new dcpu instance\n");
+ exit(EX_UNAVAILABLE);
+ }
+
+ if (argc) {
+ file_load_(vm, *argv);
+ }
+
+ dcpu16_state_print(vm);
+ dcpu16_disassemble_print(vm, vm->pc);
+ while ( (command = readline(prompt)) ) {
+ if (strcasecmp(command, "quit") == 0)
+ break;
+
+ dcpu16_step(vm);
+ dcpu16_state_print(vm);
+ dcpu16_disassemble_print(vm, vm->pc);
+ }
+
+ printf("finished\n");
+
+ dcpu16_delete(&vm);
+
+ exit(EX_OK);
+}