diff options
Diffstat (limited to 'tools/ioemu/gui/textconfig.cc')
-rw-r--r-- | tools/ioemu/gui/textconfig.cc | 995 |
1 files changed, 995 insertions, 0 deletions
diff --git a/tools/ioemu/gui/textconfig.cc b/tools/ioemu/gui/textconfig.cc new file mode 100644 index 0000000000..7b5b098453 --- /dev/null +++ b/tools/ioemu/gui/textconfig.cc @@ -0,0 +1,995 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: textconfig.cc,v 1.18 2003/10/24 15:39:57 vruppert Exp $ +///////////////////////////////////////////////////////////////////////// +// +// This is code for a text-mode configuration interface. Note that this file +// does NOT include bochs.h. Instead, it does all of its contact with +// the simulator through an object called SIM, defined in siminterface.cc +// and siminterface.h. This separation adds an extra layer of method +// calls before any work can be done, but the benefit is that the compiler +// enforces the rules. I can guarantee that textconfig.cc doesn't call any +// I/O device objects directly, for example, because the bx_devices symbol +// isn't even defined in this context. +// + +#include "config.h" + +extern "C" { +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +} +#include "osdep.h" +#include "textconfig.h" +#include "siminterface.h" +#include "extplugin.h" +#ifdef WIN32 +#include "win32dialog.h" +#endif + +#define CI_PATH_LENGTH 512 + +#define BX_INSERTED 11 + +/* functions for changing particular options */ +void bx_config_interface_init (); +int bx_read_rc (char *rc); +int bx_write_rc (char *rc); +void bx_log_options (int individual); + +/******************************************************************/ +/* lots of code stolen from bximage.c */ +/* remove leading spaces, newline junk at end. returns pointer to + cleaned string, which is between s0 and the null */ +char * +clean_string (char *s0) +{ + char *s = s0; + char *ptr; + /* find first nonblank */ + while (isspace (*s)) + s++; + /* truncate string at first non-alphanumeric */ + ptr = s; + while (isprint (*ptr)) + ptr++; + *ptr = 0; + return s; +} + +void +double_percent (char *s, int max_len) +{ + char d[CI_PATH_LENGTH]; + int i=0,j=0; + + if (max_len>CI_PATH_LENGTH) + max_len=CI_PATH_LENGTH; + + max_len--; + + while((s[i]!=0)&&(j<max_len)) + { + d[j++]=s[i]; + if((s[i]=='%')&&(j<max_len)) + { + d[j++]=s[i]; + } + i++; + } + d[j]=0; + strcpy(s,d); +} + +/* returns 0 on success, -1 on failure. The value goes into out. */ +int +ask_uint (char *prompt, Bit32u min, Bit32u max, Bit32u the_default, Bit32u *out, int base) +{ + Bit32u n = max + 1; + char buffer[1024]; + char *clean; + int illegal; + assert (base==10 || base==16); + while (1) { + printf (prompt, the_default); + if (!fgets (buffer, sizeof(buffer), stdin)) + return -1; + clean = clean_string (buffer); + if (strlen(clean) < 1) { + // empty line, use the default + *out = the_default; + return 0; + } + const char *format = (base==10) ? "%d" : "%x"; + illegal = (1 != sscanf (buffer, format, &n)); + if (illegal || n<min || n>max) { + printf ("Your choice (%s) was not an integer between %u and %u.\n\n", + clean, min, max); + } else { + // choice is okay + *out = n; + return 0; + } + } +} + +// identical to ask_uint, but uses signed comparisons +int +ask_int (char *prompt, Bit32s min, Bit32s max, Bit32s the_default, Bit32s *out) +{ + int n = max + 1; + char buffer[1024]; + char *clean; + int illegal; + while (1) { + printf (prompt, the_default); + if (!fgets (buffer, sizeof(buffer), stdin)) + return -1; + clean = clean_string (buffer); + if (strlen(clean) < 1) { + // empty line, use the default + *out = the_default; + return 0; + } + illegal = (1 != sscanf (buffer, "%d", &n)); + if (illegal || n<min || n>max) { + printf ("Your choice (%s) was not an integer between %d and %d.\n\n", + clean, min, max); + } else { + // choice is okay + *out = n; + return 0; + } + } +} + +int +ask_menu (char *prompt, int n_choices, char *choice[], int the_default, int *out) +{ + char buffer[1024]; + char *clean; + int i; + *out = -1; + while (1) { + printf (prompt, choice[the_default]); + if (!fgets (buffer, sizeof(buffer), stdin)) + return -1; + clean = clean_string (buffer); + if (strlen(clean) < 1) { + // empty line, use the default + *out = the_default; + return 0; + } + for (i=0; i<n_choices; i++) { + if (!strcmp (choice[i], clean)) { + // matched, return the choice number + *out = i; + return 0; + } + } + if (clean[0] != '?') + printf ("Your choice (%s) did not match any of the choices:\n", clean); + for (i=0; i<n_choices; i++) { + if (i>0) printf (", "); + printf ("%s", choice[i]); + } + printf ("\n"); + } +} + +int +ask_yn (char *prompt, Bit32u the_default, Bit32u *out) +{ + char buffer[16]; + char *clean; + *out = 1<<31; + while (1) { + // if there's a %s field, substitute in the default yes/no. + printf (prompt, the_default ? "yes" : "no"); + if (!fgets (buffer, sizeof(buffer), stdin)) + return -1; + clean = clean_string (buffer); + if (strlen(clean) < 1) { + // empty line, use the default + *out = the_default; + return 0; + } + switch (tolower(clean[0])) { + case 'y': *out=1; return 0; + case 'n': *out=0; return 0; + } + printf ("Please type either yes or no.\n"); + } +} + +// returns -1 on error (stream closed or something) +// returns 0 if default was taken +// returns 1 if value changed +int +ask_string (char *prompt, char *the_default, char *out) +{ + char buffer[1024]; + char *clean; + assert (the_default != out); + out[0] = 0; + printf (prompt, the_default); + if (fgets (buffer, sizeof(buffer), stdin) == NULL) + return -1; + clean = clean_string (buffer); + if (strlen(clean) < 1) { + // empty line, use the default + strcpy (out, the_default); + return 0; + } + strcpy (out, clean); + return 1; +} + +/******************************************************************/ + +static char *startup_menu_prompt = +"------------------------------\n" +"Bochs Configuration: Main Menu\n" +"------------------------------\n" +"\n" +"This is the Bochs Configuration Interface, where you can describe the\n" +"machine that you want to simulate. Bochs has already searched for a\n" +"configuration file (typically called bochsrc.txt) and loaded it if it\n" +"could be found. When you are satisfied with the configuration, go\n" +"ahead and start the simulation.\n" +"\n" +"You can also start bochs with the -q option to skip these menus.\n" +"\n" +"1. Restore factory default configuration\n" +"2. Read options from...\n" +"3. Edit options\n" +"4. Save options to...\n" +"5. Begin simulation\n" +"6. Quit now\n" +"\n" +"Please choose one: [%d] "; + +static char *startup_options_prompt = +"------------------\n" +"Bochs Options Menu\n" +"------------------\n" +"0. Return to previous menu\n" +"1. Log file: %s\n" +"2. Log prefix: %s\n" +"3. Debug log file: %s\n" +"4. Log options for all devices\n" +"5. Log options for individual devices\n" +"6. Memory options\n" +"7. Interface options\n" +"8. Disk options\n" +"9. Serial or Parallel port options\n" +"10. Sound Blaster 16 options\n" +"11. NE2000 network card options\n" +"12. Keyboard options\n" +"13. Other options\n" +"\n" +"Please choose one: [0] "; + +static char *runtime_menu_prompt = +"---------------------\n" +"Bochs Runtime Options\n" +"---------------------\n" +"1. Floppy disk 0: %s\n" +"2. Floppy disk 1: %s\n" +"3. 1st CDROM: %s\n" +"4. 2nd CDROM: %s\n" +"5. 3rd CDROM: %s\n" +"6. 4th CDROM: %s\n" +"7. (not implemented)\n" +"8. Log options for all devices\n" +"9. Log options for individual devices\n" +"10. VGA Update Interval: %d\n" +"11. Mouse: %s\n" +"12. Keyboard paste delay: %d\n" +"13. Userbutton shortcut: %s\n" +"14. Instruction tracing: off (doesn't exist yet)\n" +"15. Continue simulation\n" +"16. Quit now\n" +"\n" +"Please choose one: [15] "; + +#define NOT_IMPLEMENTED(choice) \ + fprintf (stderr, "ERROR: choice %d not implemented\n", choice); + +#define BAD_OPTION(menu,choice) \ + do {fprintf (stderr, "ERROR: menu %d has no choice %d\n", menu, choice); \ + assert (0); } while (0) + +void build_runtime_options_prompt (char *format, char *buf, int size) +{ + bx_floppy_options floppyop; + bx_atadevice_options cdromop; +/* bx_param_num_c *ips = SIM->get_param_num (BXP_IPS); */ + char buffer[6][128]; + for (int i=0; i<2; i++) { + SIM->get_floppy_options (i, &floppyop); + if (floppyop.Odevtype->get () == BX_FLOPPY_NONE) + strcpy (buffer[i], "(not present)"); + else { + sprintf (buffer[i], "%s, size=%s, %s", floppyop.Opath->getptr (), + SIM->get_floppy_type_name (floppyop.Otype->get ()), + (floppyop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected"); + if (!floppyop.Opath->getptr ()[0]) strcpy (buffer[i], "none"); + } + } + + // 4 cdroms supported at run time + int device; + for (Bit8u cdrom=0; cdrom<4; cdrom++) { + if (!SIM->get_cdrom_options (cdrom, &cdromop, &device) || !cdromop.Opresent->get ()) + sprintf (buffer[2+cdrom], "(not present)"); + else + sprintf (buffer[2+cdrom], "(%s on ata%d) %s, %s", + device&1?"slave":"master", device/2, cdromop.Opath->getptr (), + (cdromop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected"); + } + + snprintf (buf, size, format, buffer[0], buffer[1], buffer[2], + buffer[3], buffer[4], buffer[5], + /* ips->get (), */ + SIM->get_param_num (BXP_VGA_UPDATE_INTERVAL)->get (), + SIM->get_param_num (BXP_MOUSE_ENABLED)->get () ? "enabled" : "disabled", + SIM->get_param_num (BXP_KBD_PASTE_DELAY)->get (), + SIM->get_param_string (BXP_USER_SHORTCUT)->getptr ()); +} + +int do_menu (bx_id id) { + bx_list_c *menu = (bx_list_c *)SIM->get_param (id); + while (1) { + menu->get_choice()->set (0); + int status = menu->text_ask (stdin, stderr); + if (status < 0) return status; + bx_param_num_c *choice = menu->get_choice(); + if (choice->get () < 1) + return choice->get (); + else { + int index = choice->get () - 1; // choosing 1 means list[0] + bx_param_c *chosen = menu->get (index); + assert (chosen != NULL); + chosen->text_ask (stdin, stderr); + } + } +} + +void askparam (bx_id id) +{ + bx_param_c *param = SIM->get_param (id); + param->text_ask (stdin, stderr); +} + +int bx_config_interface (int menu) +{ + Bit32u choice; + while (1) { + switch (menu) + { + case BX_CI_INIT: + bx_config_interface_init (); + return 0; + case BX_CI_START_SIMULATION: { + SIM->begin_simulation (bx_startup_flags.argc, bx_startup_flags.argv); + // we don't expect it to return, but if it does, quit + SIM->quit_sim(1); + break; + } + case BX_CI_START_MENU: + { + Bit32u default_choice; + switch (SIM->get_param_enum(BXP_BOCHS_START)->get ()) { + case BX_LOAD_START: + default_choice = 2; break; + case BX_EDIT_START: + default_choice = 3; break; + default: + default_choice = 5; break; + } + + if (ask_uint (startup_menu_prompt, 1, 6, default_choice, &choice, 10) < 0) return -1; + switch (choice) { + case 1: + fprintf (stderr, "I reset all options back to their factory defaults.\n\n"); + SIM->reset_all_param (); + SIM->get_param_enum(BXP_BOCHS_START)->set(BX_EDIT_START); + break; + case 2: + // Before reading a new configuration, reset every option to its + // original state. + SIM->reset_all_param (); + if (bx_read_rc (NULL) >= 0) + SIM->get_param_enum(BXP_BOCHS_START)->set(BX_RUN_START); + break; + case 3: + bx_config_interface (BX_CI_START_OPTS); + SIM->get_param_enum(BXP_BOCHS_START)->set(BX_RUN_START); + break; + case 4: bx_write_rc (NULL); break; + case 5: bx_config_interface (BX_CI_START_SIMULATION); break; + case 6: SIM->quit_sim (1); return -1; + default: BAD_OPTION(menu, choice); + } + } + break; + case BX_CI_START_OPTS: + { + char prompt[CI_PATH_LENGTH]; + char oldpath[CI_PATH_LENGTH]; + char olddebuggerpath[CI_PATH_LENGTH]; + char oldprefix[CI_PATH_LENGTH]; + int retval; + + retval = SIM->get_log_file (oldpath, CI_PATH_LENGTH); + assert (retval >= 0); + double_percent(oldpath,CI_PATH_LENGTH); + retval = SIM->get_log_prefix (oldprefix, CI_PATH_LENGTH); + assert (retval >= 0); + double_percent(oldprefix,CI_PATH_LENGTH); + retval = SIM->get_debugger_log_file (olddebuggerpath, CI_PATH_LENGTH); + assert (retval >= 0); + double_percent(olddebuggerpath,CI_PATH_LENGTH); + + sprintf (prompt, startup_options_prompt, oldpath, oldprefix, olddebuggerpath); + if (ask_uint (prompt, 0, 13, 0, &choice, 10) < 0) return -1; + switch (choice) { + case 0: return 0; + case 1: askparam (BXP_LOG_FILENAME); break; + case 2: askparam (BXP_LOG_PREFIX); break; + case 3: askparam (BXP_DEBUGGER_LOG_FILENAME); break; + case 4: bx_log_options (0); break; + case 5: bx_log_options (1); break; + case 6: do_menu (BXP_MENU_MEMORY); break; + case 7: do_menu (BXP_MENU_INTERFACE); break; + case 8: do_menu (BXP_MENU_DISK); break; + case 9: do_menu (BXP_MENU_SERIAL_PARALLEL); break; + case 10: do_menu (BXP_SB16); break; + case 11: do_menu (BXP_NE2K); break; + case 12: do_menu (BXP_MENU_KEYBOARD); break; + case 13: do_menu (BXP_MENU_MISC); break; + default: BAD_OPTION(menu, choice); + } + } + break; + case BX_CI_RUNTIME: + char prompt[1024]; + bx_floppy_options floppyop; + bx_atadevice_options cdromop; + build_runtime_options_prompt (runtime_menu_prompt, prompt, 1024); + if (ask_uint (prompt, 1, 16, 15, &choice, 10) < 0) return -1; + switch (choice) { + case 1: + SIM->get_floppy_options (0, &floppyop); + if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYA); + break; + case 2: + SIM->get_floppy_options (1, &floppyop); + if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYB); + break; + case 3: + case 4: + case 5: + case 6: + int device; + if (SIM->get_cdrom_options (choice - 3, &cdromop, &device) && cdromop.Opresent->get ()) { + // disable type selection + SIM->get_param((bx_id)(BXP_ATA0_MASTER_TYPE + device))->set_enabled(0); + SIM->get_param((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled(0); + SIM->get_param((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled(0); + do_menu ((bx_id)(BXP_ATA0_MASTER + device)); + } + break; + case 7: // not implemented yet because I would have to mess with + // resetting timers and pits and everything on the fly. + // askparam (BXP_IPS); + break; + case 8: bx_log_options (0); break; + case 9: bx_log_options (1); break; + case 10: askparam (BXP_VGA_UPDATE_INTERVAL); break; + case 11: askparam (BXP_MOUSE_ENABLED); break; + case 12: askparam (BXP_KBD_PASTE_DELAY); break; + case 13: askparam (BXP_USER_SHORTCUT); break; + case 14: NOT_IMPLEMENTED (choice); break; + case 15: fprintf (stderr, "Continuing simulation\n"); return 0; + case 16: + fprintf (stderr, "You chose quit on the configuration interface.\n"); + SIM->quit_sim (1); + return -1; + default: fprintf (stderr, "Menu choice %d not implemented.\n", choice); + } + break; + default: + fprintf (stderr, "Unknown config interface menu type.\n"); + assert (menu >=0 && menu < BX_CI_N_MENUS); + } + } +} + +static void bx_print_log_action_table () +{ + // just try to print all the prefixes first. + fprintf (stderr, "Current log settings:\n"); + fprintf (stderr, " Debug Info Error Panic Pass\n"); + fprintf (stderr, "ID Device Action Action Action Action Action\n"); + fprintf (stderr, "---- --------- --------- --------- ---------- ---------- ----------\n"); + int i, j, imax=SIM->get_n_log_modules (); + for (i=0; i<imax; i++) { + if (strcmp(SIM->get_prefix(i), "[ ]")) { + fprintf (stderr, "%3d. %s ", i, SIM->get_prefix (i)); + for (j=0; j<SIM->get_max_log_level (); j++) { + fprintf (stderr, "%10s ", SIM->get_action_name (SIM->get_log_action (i, j))); + } + fprintf (stderr, "\n"); + } + } +} + +static char *log_options_prompt1 = "Enter the ID of the device to edit, or -1 to return: [-1] "; +static char *log_level_choices[] = { "ignore", "report", "ask", "fatal", "no change" }; +static int log_level_n_choices_normal = 4; + +void bx_log_options (int individual) +{ + if (individual) { + int done = 0; + while (!done) { + bx_print_log_action_table (); + Bit32s id, level, action; + Bit32s maxid = SIM->get_n_log_modules (); + if (ask_int (log_options_prompt1, -1, maxid-1, -1, &id) < 0) + return; + if (id < 0) return; + fprintf (stderr, "Editing log options for the device %s\n", SIM->get_prefix (id)); + for (level=0; level<SIM->get_max_log_level (); level++) { + char prompt[1024]; + int default_action = SIM->get_log_action (id, level); + sprintf (prompt, "Enter action for %s event: [%s] ", SIM->get_log_level_name (level), SIM->get_action_name(default_action)); + // don't show the no change choice (choices=3) + if (ask_menu (prompt, log_level_n_choices_normal, log_level_choices, default_action, &action)<0) + return; + SIM->set_log_action (id, level, action); + } + } + } else { + // provide an easy way to set log options for all devices at once + bx_print_log_action_table (); + for (int level=0; level<SIM->get_max_log_level (); level++) { + char prompt[1024]; + int action, default_action = 3; // default to no change + sprintf (prompt, "Enter action for %s event on all devices: [no change] ", SIM->get_log_level_name (level)); + // do show the no change choice (choices=4) + if (ask_menu (prompt, log_level_n_choices_normal+1, log_level_choices, default_action, &action)<0) + return; + if (action < 3) { + SIM->set_default_log_action (level, action); + SIM->set_log_action (-1, level, action); + } + } + } +} + +int bx_read_rc (char *rc) +{ + if (rc && SIM->read_rc (rc) >= 0) return 0; + char oldrc[CI_PATH_LENGTH]; + if (SIM->get_default_rc (oldrc, CI_PATH_LENGTH) < 0) + strcpy (oldrc, "none"); + char newrc[CI_PATH_LENGTH]; + while (1) { + if (ask_string ("\nWhat is the configuration file name?\nTo cancel, type 'none'. [%s] ", oldrc, newrc) < 0) return -1; + if (!strcmp (newrc, "none")) return -1; + if (SIM->read_rc (newrc) >= 0) return 0; + fprintf (stderr, "The file '%s' could not be found.\n", newrc); + } +} + +int bx_write_rc (char *rc) +{ + char oldrc[CI_PATH_LENGTH], newrc[CI_PATH_LENGTH]; + if (rc == NULL) { + if (SIM->get_default_rc (oldrc, CI_PATH_LENGTH) < 0) + strcpy (oldrc, "none"); + } else { + strncpy (oldrc, rc, CI_PATH_LENGTH); + } + while (1) { + if (ask_string ("Save configuration to what file? To cancel, type 'none'.\n[%s] ", oldrc, newrc) < 0) return -1; + if (!strcmp (newrc, "none")) return 0; + // try with overwrite off first + int status = SIM->write_rc (newrc, 0); + if (status >= 0) { + fprintf (stderr, "Wrote configuration to '%s'.\n", newrc); + return 0; + } else if (status == -2) { + // return code -2 indicates the file already exists, and overwrite + // confirmation is required. + Bit32u overwrite = 0; + char prompt[256]; + sprintf (prompt, "Configuration file '%s' already exists. Overwrite it? [no] ", newrc); + if (ask_yn (prompt, 0, &overwrite) < 0) return -1; + if (!overwrite) continue; // if "no", start loop over, asking for a different file + // they confirmed, so try again with overwrite bit set + if (SIM->write_rc (newrc, 1) >= 0) { + fprintf (stderr, "Overwriting existing configuration '%s'.\n", newrc); + return 0; + } else { + fprintf (stderr, "Write failed to '%s'.\n", newrc); + } + } + } +} + +char *log_action_ask_choices[] = { "cont", "alwayscont", "die", "abort", "debug" }; +int log_action_n_choices = 4 + (BX_DEBUGGER?1:0); + +BxEvent * +config_interface_notify_callback (void *unused, BxEvent *event) +{ +#ifdef WIN32 + int opts; + bx_param_c *param; + bx_param_string_c *sparam; +#endif + event->retcode = -1; + switch (event->type) + { + case BX_SYNC_EVT_TICK: + event->retcode = 0; + return event; + case BX_SYNC_EVT_ASK_PARAM: +#ifdef WIN32 + param = event->u.param.param; + if (param->get_type() == BXT_PARAM_STRING) { + sparam = (bx_param_string_c *)param; + opts = sparam->get_options()->get(); + if (opts & sparam->IS_FILENAME) { + if (param->get_id() == BXP_NULL) { + event->retcode = AskFilename(GetBochsWindow(), (bx_param_filename_c *)sparam); + } else { + event->retcode = FloppyDialog((bx_param_filename_c *)sparam); + } + return event; + } else { + event->retcode = AskString(sparam); + return event; + } + } +#endif + event->u.param.param->text_ask (stdin, stderr); + return event; + case BX_SYNC_EVT_LOG_ASK: + { +#ifdef WIN32 + LogAskDialog(event); +#else + int level = event->u.logmsg.level; + fprintf (stderr, "========================================================================\n"); + fprintf (stderr, "Event type: %s\n", SIM->get_log_level_name (level)); + fprintf (stderr, "Device: %s\n", event->u.logmsg.prefix); + fprintf (stderr, "Message: %s\n\n", event->u.logmsg.msg); + fprintf (stderr, "A %s has occurred. Do you want to:\n", SIM->get_log_level_name (level)); + fprintf (stderr, " cont - continue execution\n"); + fprintf (stderr, " alwayscont - continue execution, and don't ask again.\n"); + fprintf (stderr, " This affects only %s events from device %s\n", SIM->get_log_level_name (level), event->u.logmsg.prefix); + fprintf (stderr, " die - stop execution now\n"); + fprintf (stderr, " abort - dump core %s\n", + BX_HAVE_ABORT ? "" : "(Disabled)"); +#if BX_DEBUGGER + fprintf (stderr, " debug - continue and return to bochs debugger\n"); +#endif + int choice; +ask: + if (ask_menu ("Choose one of the actions above: [%s] ", + log_action_n_choices, log_action_ask_choices, 2, &choice) < 0) + event->retcode = -1; + // return 0 for continue, 1 for alwayscontinue, 2 for die, 3 for debug. + if (!BX_HAVE_ABORT && choice==BX_LOG_ASK_CHOICE_DUMP_CORE) goto ask; + fflush(stdout); + fflush(stderr); + event->retcode = choice; +#endif + } + return event; + case BX_ASYNC_EVT_REFRESH: + case BX_ASYNC_EVT_DBG_MSG: + // The text mode interface does not use these events, so just ignore + // them. + return event; + default: + fprintf (stderr, "Control panel: notify callback called with event type %04x\n", event->type); + return event; + } + assert (0); // switch statement should return +} + +void bx_config_interface_init () { + //fprintf (stderr, "bx_config_interface_init()\n"); + SIM->set_notify_callback (config_interface_notify_callback, NULL); +} + +///////////////////////////////////////////////////////////////////// +// implement the text_* methods for bx_param types. + +void +bx_param_num_c::text_print (FILE *fp) +{ + //fprintf (fp, "number parameter, id=%u, name=%s\n", get_id (), get_name ()); + //fprintf (fp, "value=%u\n", get ()); + if (get_format ()) { + fprintf (fp, get_format (), get ()); + } else { + char *format = "%s: %d"; + assert (base==10 || base==16); + if (base==16) format = "%s: 0x%x"; + fprintf (fp, format, get_name (), get ()); + } +} + +void +bx_param_bool_c::text_print (FILE *fp) +{ + if (get_format ()) { + fprintf (fp, get_format (), get () ? "yes" : "no"); + } else { + char *format = "%s: %s"; + fprintf (fp, format, get_name (), get () ? "yes" : "no"); + } +} + +void +bx_param_enum_c::text_print (FILE *fp) +{ + int n = get (); + assert (n >= min && n <= max); + char *choice = choices[n - min]; + if (get_format ()) { + fprintf (fp, get_format (), choice); + } else { + char *format = "%s: %s"; + fprintf (fp, format, get_name (), choice); + } +} + +void +bx_param_string_c::text_print (FILE *fp) +{ + char *value = getptr (); + int opts = options->get (); + if (opts & RAW_BYTES) { + char buffer[1024]; + buffer[0] = 0; + char sep_string[2]; + sep_string[0] = separator; + sep_string[1] = 0; + for (int i=0; i<maxsize; i++) { + char eachbyte[16]; + sprintf (eachbyte, "%s%02x", (i>0)?sep_string : "", (unsigned int)0xff&val[i]); + strncat (buffer, eachbyte, sizeof(buffer)); + } + if (strlen (buffer) > sizeof(buffer)-4) { + assert (0); // raw byte print buffer is probably overflowing. increase the max or make it dynamic + } + value = buffer; + } + if (get_format ()) { + fprintf (fp, get_format (), value); + } else { + fprintf (fp, "%s: %s", get_name (), value); + } +} + +void +bx_list_c::text_print (FILE *fp) +{ + //fprintf (fp, "This is a list.\n"); + //fprintf (fp, "title=%s\n", title->getptr ()); + fprintf (fp, "%s: ", get_name ()); + /* + fprintf (fp, "options=%s%s%s\n", + (options->get () == 0) ? "none" : "", + (options->get () & SHOW_PARENT) ? "SHOW_PARENT " : "", + (options->get () & SERIES_ASK) ? "SERIES_ASK " : ""); + */ + for (int i=0; i<size; i++) { + //fprintf (fp, "param[%d] = %p\n", i, list[i]); + assert (list[i] != NULL); + if (list[i]->get_enabled ()) { + if ((i>0) && (options->get () & SERIES_ASK)) + fprintf (fp, ", "); + list[i]->text_print (fp); + if (!(options->get () & SERIES_ASK)) + fprintf (fp, "\n"); + } + } +} + +int +bx_param_num_c::text_ask (FILE *fpin, FILE *fpout) +{ + fprintf (fpout, "\n"); + int status; + char *prompt = get_ask_format (); + if (prompt == NULL) { + // default prompt, if they didn't set an ask format string + text_print (fpout); + fprintf (fpout, "\n"); + prompt = "Enter new value: [%d] "; + if (base==16) + prompt = "Enter new value in hex: [%x] "; + } + Bit32u n = get (); + status = ask_uint (prompt, min, max, n, &n, base); + if (status < 0) return status; + set (n); + return 0; +} + +int +bx_param_bool_c::text_ask (FILE *fpin, FILE *fpout) +{ + fprintf (fpout, "\n"); + int status; + char *prompt = get_ask_format (); + char buffer[512]; + if (prompt == NULL) { + // default prompt, if they didn't set an ask format string + sprintf (buffer, "%s? [%%s] ", get_name ()); + prompt = buffer; + } + Bit32u n = get (); + status = ask_yn (prompt, n, &n); + if (status < 0) return status; + set (n); + return 0; +} + +int +bx_param_enum_c::text_ask (FILE *fpin, FILE *fpout) +{ + fprintf (fpout, "\n"); + char *prompt = get_ask_format (); + if (prompt == NULL) { + // default prompt, if they didn't set an ask format string + fprintf (fpout, "%s = ", get_name ()); + text_print (fpout); + fprintf (fpout, "\n"); + prompt = "Enter new value: [%s] "; + } + Bit32s n = (Bit32s)(get () - min); + int status = ask_menu (prompt, (max-min+1), choices, n, &n); + if (status < 0) return status; + n += (Bit32s)min; + set (n); + return 0; +} + +int parse_raw_bytes (char *dest, char *src, int destsize, char separator) +{ + //printf ("parsing src='%s'\n", src); + int i; + unsigned int n; + for (i=0; i<destsize; i++) + dest[i] = 0; + for (i=0; i<destsize; i++) { + while (*src == separator) + src++; + if (*src == 0) break; + // try to read a byte of hex + if (sscanf (src, "%02x", &n) == 1) { + //printf ("found a byte %02x\n", n); + dest[i] = n; + src+=2; + } else { + return -1; + } + } + return 0; +} + +int +bx_param_string_c::text_ask (FILE *fpin, FILE *fpout) +{ + fprintf (fpout, "\n"); + int status; + char *prompt = get_ask_format (); + if (prompt == NULL) { + // default prompt, if they didn't set an ask format string + text_print (fpout); + fprintf (fpout, "\n"); + prompt = "Enter a new value, or press return for no change.\n"; + } + while (1) { + char buffer[1024]; + status = ask_string (prompt, getptr(), buffer); + if (status < 0) return status; + int opts = options->get (); + char buffer2[1024]; + strcpy (buffer2, buffer); + if (status == 1 && opts & RAW_BYTES) { + // copy raw hex into buffer + status = parse_raw_bytes (buffer, buffer2, maxsize, separator); + if (status < 0) { + fprintf (fpout, "Illegal raw byte format. I expected something like 3A%c03%c12%c...\n", separator, separator, separator); + continue; + } + } + if (!equals (buffer)) + set (buffer); + return 0; + } +} + +int +bx_list_c::text_ask (FILE *fpin, FILE *fpout) +{ + char *my_title = title->getptr (); + fprintf (fpout, "\n"); + int i, imax = strlen (my_title); + for (i=0; i<imax; i++) fprintf (fpout, "-"); + fprintf (fpout, "\n%s\n", my_title); + for (i=0; i<imax; i++) fprintf (fpout, "-"); + fprintf (fpout, "\n"); //fprintf (fp, "options=%s\n", options->get ()); + if (options->get () & SERIES_ASK) { + for (int i=0; i<size; i++) { + if (list[i]->get_enabled ()) + list[i]->text_ask (fpin, fpout); + } + } else { + if (options->get () & SHOW_PARENT) + fprintf (fpout, "0. Return to previous menu\n"); + for (int i=0; i<size; i++) { + assert (list[i] != NULL); + fprintf (fpout, "%d. ", i+1); + if (list[i]->get_enabled ()) { + list[i]->text_print (fpout); + fprintf (fpout, "\n"); + } else + fprintf (fpout, "(disabled)\n"); + } + fprintf (fpout, "\n"); + Bit32u n = choice->get (); + int min = (options->get () & SHOW_PARENT) ? 0 : 1; + int max = size; + int status = ask_uint ("Please choose one: [%d] ", min, max, n, &n, 10); + if (status < 0) return status; + choice->set (n); + } + return 0; +} + +static int ci_callback (void *userdata, ci_command_t command) +{ + switch (command) + { + case CI_START: + //fprintf (stderr, "textconfig.cc: start\n"); + bx_config_interface_init (); + if (SIM->get_param_enum(BXP_BOCHS_START)->get () == BX_QUICK_START) + bx_config_interface (BX_CI_START_SIMULATION); + else { + if (!SIM->test_for_text_console ()) + return CI_ERR_NO_TEXT_CONSOLE; + bx_config_interface (BX_CI_START_MENU); + } + break; + case CI_RUNTIME_CONFIG: + bx_config_interface (BX_CI_RUNTIME); + break; + case CI_SHUTDOWN: + //fprintf (stderr, "textconfig.cc: shutdown\n"); + break; + } + return 0; +} + +// if I can make things compile without this module linked in, then +// this file can become a plugin too. +int init_text_config_interface () +{ + //fprintf (stderr, "plugin_init for textconfig.cc\n"); + SIM->register_configuration_interface ("textconfig", ci_callback, NULL); + return 0; // success +} |