/*
   *                                                                      
   * MODULE DESCRIPTION                                                   
   *   This module contains all the terminal I/O functions used by the
   * simulator.  It also contains the functions which intercept and handle
   * the BREAK signal.  Conditional compilation directives choose MSDOS (MSDOS),
   * UNIX (UNIX) or macintosh
   *
   *   The I/O functions operate on a sim_window structure that is contained
   * within the sim_var structure that is allocated for each dsp device.    
   * The sim_window structure is defined in simusr.h and described  
   * below. 
   *
   *    sim_window       
   *          .next        integer index of most recent insertion address
   *                       of dbuf display buffer
   *          .head        offset from last line of display to .next
   *          .dbuf        array of sv_const.winsz lines of DSP_LINE_LEN characters
   *          .curline     current display line number
   *          .curclm      current display column number
   *          .scrnest     nesting level for screen refresh
   *          .insert_o    insert/overwrite mode of keyboard input
   *
   * MAIN FUNCTIONS: Called from other modules                            
   * simw_redo(devindex) Repaint the screen from a device's screen buffer
   * simw_wscr(bufptr,flag)
   * simw_redraw(count)
   * simw_cursor(line, column)
   * simw_putc(c)
   * simw_puts(line, column,text, flag)
   * simw_gkey()
   * simw_getch()
   * simw_scrnest()
   * simw_unnest()

   * LOCAL FUNCTIONS:  Lower level functions only used by this module     
   * scr_erase()  Erase terminal display.
   * gti_scroll(direction) Scroll display region up or down a line
   * gti_ps(string, flag)
   * int intrpt1()   Sets sv_const.CTRLBR when CTRL-C is pressed
 */

#include "utsim.h"

#if UNIX
#include <memory.h>
#include <curses.h>
#include <fcntl.h>
#endif
#include "simcom.h"
#include "simdev.h"
#include "simusr.h"
#include "protocom.h"

static void winchange (int signum);
static void simw_resize (void);
static void intrpt1 (int signum);
static void scr_erase (void);
static void gti_scroll (int direction);
static void gti_ps (char *string, int flag);
static void gti_wscr (char *bufptr, int buf_type, int hilite_flag);
static int kbdhit (void);

extern struct dev_var *dv_var;
extern struct dev_const dv_const;

#if FULLSIM
extern struct sev_var *sv_var;
extern struct sev_const sv_const;

#endif

#if ADSx
static int previous_device = 0;
#endif /* ADSx */

#if macintosh
/* for obsolete function ClrAppFiles in SegLoad.h */
/* Also CountAppFiles, GetAppFiles, GetAppParms are obsolete */
/* Should be using AppleEvents from the Finder? */
#define OBSOLETE 1
#include	<QuickDraw.h>
#include	<Windows.h>
#include 	<Types.h>
#include   	<Files.h>
#include 	<Memory.h>
#include	<Events.h>
#include	<Menus.h>
#include	<Desk.h>
#include	<Fonts.h>
#include	<Dialogs.h>
#include	<StdIO.h>
#include	<Controls.h>
#include 	<Packages.h>
#include	<Strings.h>
#include <ToolUtils.h>
#include <SegLoad.h>
#include <OSEvents.h>
#include <Traps.h>
#include <Fonts.h>
#include <OSUtils.h>
#include <Resources.h>
#include <Lists.h>
#include <stdio.h>
#include <Strings.h>
#include <StandardFile.h>

static int ch,
 cw,
 font_points;
static FontInfo sf;
static ControlHandle scrollbar,
 haltbutton,
 gobutton,
 stepbutton,
 nextbutton,
 finbutton,
 viewbutton;
static char screenbuf[24][80][2];

#define	appleMenu	1
#define	fileMenu	256
#define	helpMenu	257
#define	cmdMenu		258
#define	prevMenu	259
#define	NMENUS	5
#define SBarWidth	16
#define ROOTDIRID 2L		/* Directory id of root directory of volume */
#define FIGNORENAME -1		/* FDirIndex if not using ioNamePtr */
#define FIRSTTIME -1		/* first time dialog filter is called by sfgetfile */
#define TRUE 1
#define FALSE 0
static MenuHandle myMenus[NMENUS];
static struct Rect screenRect,
 dragRect,
 pRect;
static struct WindowRecord wRecord;
static struct GrafPort *myWindow,
*whichWindow;
static struct EventRecord myEvent;
static char macstring[256];	/* filename from menu entry */

SFTypeList typeList;
OSErr err;			/* used in all OS calls */
Point gLocation =
{0x40, 0x40};
Point gZeroPt =
{0, 0};
SysEnvRec theWorld;

/* for normal SFPPutFile */
Boolean textOnly;
short MySaveDisk;
Rect freeItemBox;
Str255 myStr,
 myStr2;

/* for SetDirectory */
long MyCurDir;
Boolean CurDirValid;

#define HiWrd(aLong)	(((aLong) >> 16) & 0xFFFF)
#define LoWrd(aLong)	((aLong) & 0xFFFF)

/* Define TopLeft and BotRight macros for convenience. Notice the implicit */
/* dependency on the ordering of fields within a Rect */

#define TopLeft(aRect)	(* (Point *) &(aRect).top)
#define BotRight(aRect)	(* (Point *) &(aRect).bottom)

#endif

/*
   *   The scroll region view pointers
 */
#if WIN32
#undef n_name
#undef N_BTMASK
#undef N_TMASK
#undef N_BTSHFT
#undef N_TSHIFT
#undef REG_NONE
#include <wtypes.h>
#include <windows.h>
#include <wincon.h>
#include <winbase.h>
#include    <conio.h>
static HANDLE hConsole;
static HANDLE hStdIn,hStdOut;
static HANDLE hStdIn_saved,hStdOut_saved;
static DWORD hStdOut_dwMode;
static DWORD hStdIn_dwMode;
static WORD NORMATRB;
static WORD BOLDATRB;
#else
#if MSDOS
static union REGS inregs;
static union REGS outregs;

#if PC9801
#include    <conio.h>
#define NORMATRB 0xe1
#define BOLDATRB 0xa5
static short boldattr;

#define	ESC     0x1b
static char esc[3] =
{ESC, '[', '\0'};
static char norm[5] =
{ESC, '[', '0', 'm', '\0'};

#ifdef __WATCOMC__
#define TXTRAM 0xa0000l
#define ATTRAM 0xa2000l
#else
#define TXTRAM 0xa0000000l
#define ATTRAM 0xa2000000l
#endif

#else /* regular pc text video ram base address */
static unsigned long TXTRAM;

#endif

#endif /* MSDOS */
#endif /* WIN32 */

#if macintosh||UNIX
static char dtx[DSP_LINES_MAX][DSP_COLS_MAX + 1];	/* display text */
static char dhi[DSP_LINES_MAX][DSP_COLS_MAX];	/* display hilite flags */

#endif

#if macintosh || MSDOS || UNIX
static int hln;			/* current line in scroll region of hidden text */
static char htx[DSP_LINES_MAX][DSP_COLS_MAX + 1];	/* hidden text */
static char hhi[DSP_LINES_MAX][DSP_COLS_MAX];	/* hidden hilite flags */

#endif

#if UNIX
static int resize_flg;

#ifndef SIGWINCH
#define SIGWINCH SIGWINDOW
#endif

/*ARGSUSED */
static
void
winchange (int signum)

{
    resize_flg = 1;
    if (dv_const.nodisplay) return;
    (void) signal (SIGWINCH, winchange);
}

static
void
simw_resize (void)

{
    int oldline,
     oldcol,
     oldsz;
    char oldcmdhhi[DSP_COLS_MAX * 3];
    char oldcmdhtx[(DSP_COLS_MAX + 1) * 3];

    oldline = sv_const.curline;
    oldcol = sv_const.curclm;
    oldsz = sv_const.numlines;
    memcpy (oldcmdhtx, &htx[DSP_LINES_MAX - 3][0], (DSP_COLS_MAX + 1) * 3);
    memcpy (oldcmdhhi, &hhi[DSP_LINES_MAX - 3][0], DSP_COLS_MAX * 3);
    if (!dv_const.nodisplay)
    {
	endwin ();
	(void) resetty ();
	COLS = LINES = 0;
    }
    else
    {
	LINES = 24;
	COLS = 80;
    }
    siml_winit ();
    if (!dv_const.nodisplay)
    {
	clearok (curscr, TRUE);
    }
    simw_redo (dv_var->devindex);

    memcpy (&htx[DSP_LINES_MAX - 3][0], oldcmdhtx, (DSP_COLS_MAX + 1) * 3);
    memcpy (&hhi[DSP_LINES_MAX - 3][0], oldcmdhhi, DSP_COLS_MAX * 3);
    sv_const.curline = oldline + (sv_const.numlines - oldsz);
    sv_const.curclm = (oldcol >= sv_const.numcols) ? sv_const.numcols - 1 : oldcol;
}
#endif

/*
   * intrpt1 --- interrupt handler
   *
   * This function sets the dv_const.CTRLBR flag any time a BREAK signal is
   * intercepted in the MSDOS and UNIX versions of the simulator.
 */
#if !macintosh
/*ARGSUSED */
static
void
intrpt1 (int signum)

{
    (void) signal (SIGINT, intrpt1);
    dv_const.CTRLBR = 1;
}
#endif

#if MSDOS
static
void
fphandler (signum)
int signum;
{
}
#endif

#if WIN32
static
void
w32fphandler (int signum,int subcode)
{
}

/********************************************************************
* FUNCTION: getConX(HANDLE hCon)                                    *
*                                                                   *
* PURPROSE: to get the current width of the console output buffer   *
*                                                                   *
* INPUT: the handle to get the information for                      *
*                                                                   *
* RETURNS: the width of the current console output buffer, in chars *
********************************************************************/

static
SHORT getConX(HANDLE hCon)
{
  CONSOLE_SCREEN_BUFFER_INFO csbi;

  GetConsoleScreenBufferInfo(hCon, &csbi);
  return((SHORT) (csbi.srWindow.Right + 1 - csbi.srWindow.Left));
}

static
SHORT getConY(HANDLE hCon)
{
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  GetConsoleScreenBufferInfo(hCon, &csbi);
  return((SHORT) (csbi.srWindow.Bottom + 1 - csbi.srWindow.Top));
}

static
void getConTextAttributes(HANDLE hCon)
{
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  GetConsoleScreenBufferInfo(hCon, &csbi);
  NORMATRB = (csbi.wAttributes);

  {
      /* this is going to read the attribute at the command prompt position, 
	 which should be hilighted */
      COORD cmdline;
      DWORD numread;
      cmdline.X = 0;
      cmdline.Y = sv_const.cmdline;
      BOLDATRB = NORMATRB;
      ReadConsoleOutputAttribute(hCon,&BOLDATRB,1,cmdline,&numread);
      if (BOLDATRB == NORMATRB)
      {
	  /* this is going to create a defualt inverted color based on the
	     current normal screen text color */
	  BOLDATRB = NORMATRB^(((BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE)|
				(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE)));
      }
  }
}

static
void resizeConBufAndWindow(HANDLE hConsole, SHORT xSize, SHORT ySize)
{
  CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */
  SMALL_RECT srWindowRect; /* hold the new console size */
  COORD coordScreen;
  xSize = min (xSize,DSP_COLS_MAX-1);
  ySize = min (ySize,DSP_LINES_MAX-1);

  GetConsoleScreenBufferInfo(hConsole, &csbi);
  /* get the largest size we can size the console window to */
  coordScreen = GetLargestConsoleWindowSize(hConsole);
  /* define the new console window size and scroll position */
  srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1);
  srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1);
  srWindowRect.Left = srWindowRect.Top = (SHORT) 0;
  /* define the new console buffer size */
  coordScreen.X = xSize;
  coordScreen.Y = ySize;
  /* if the current buffer is larger than what we want, resize the */
  /* console window first, then the buffer */
  if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) xSize * ySize)
    {
    SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect);
    SetConsoleScreenBufferSize(hConsole, coordScreen);
    }
  /* if the current buffer is smaller than what we want, resize the */
  /* buffer first, then the console window */
  if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) xSize * ySize)
    {
    SetConsoleScreenBufferSize(hConsole, coordScreen);
    SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect);
    }
  sv_const.numlines = ySize;
  sv_const.numcols = xSize;
  sv_const.cmdline = ySize - 3;
  /* if the current buffer *is* the size we want, don't do anything! */
  return;
}

static
BOOL WINAPI ctrlc_handler(DWORD signum)
{
    if ((signum == CTRL_C_EVENT)||
	(signum == CTRL_BREAK_EVENT))
    {
	dv_const.CTRLBR = 1;
	return (TRUE);
    }
    return (FALSE);
}
#endif
/*
   * siml_winit --- initialize display parameters and keyboard input
   *
   * This function initializes the simulator window environment.  It is     
   * normally only called at the start-up of the simulator, or when returning
   * from the simulator SYSTEM commands.
 */

void
siml_winit (void)

{
    /* This function initializes the screen window structure and the */
    /* keyboard characteristics for the particular system. */

#if macintosh
    int sbar;

    InitGraf (&qd.thePort);
    InitFonts ();
    InitWindows ();
    InitMenus ();
    setupmenu ();
    InitDialogs (0L);
    InitCursor ();

    screenRect = qd.screenBits.bounds;
    SetRect (&dragRect, 4, 24, screenRect.right - 4, screenRect.bottom - 4);

    TextFont (monaco);
    TextSize (12);
    TextFace (normal);
    TextMode (srcCopy);
    GetFontInfo (&sf);
    cw = sf.widMax;
    if (screenRect.right > (5 + 2 + (cw * 80) + SBarWidth))
	font_points = 12;
    else
    {
	font_points = 9;	/* smaller screen */
	TextFont (monaco);
	TextSize (9);
	TextFace (normal);
	TextMode (srcCopy);
	GetFontInfo (&sf);
	cw = sf.widMax;
    }

    ch = sf.ascent + sf.descent + sf.leading;

    InitPort (qd.thePort);
    pRect.top = 40;		/* position of upper left corner of simulator window */
    pRect.left = 5;
    pRect.bottom = 20 + 40 + 9 + (ch * 24);
    pRect.right = 5 + 2 + (cw * 80) + SBarWidth;	/* 2 allows border */
    myWindow = NewWindow (&wRecord, &pRect, "\pSIMDSP", TRUE, noGrowDocProc,
			  (WindowPtr) - 1L, TRUE, 0L);
    pRect = myWindow->portRect;
    pRect.left = pRect.right - SBarWidth;
    sbar = (sv_const.winsz - sv_const.cmdline);
    scrollbar = NewControl (myWindow, &pRect, "\p", TRUE, sbar, 0, sbar,
			    scrollBarProc, 0L);

    pRect.top = 0;
    pRect.right = pRect.left - 1;
    pRect.left = pRect.right - (6 * cw);
    pRect.bottom = 20;

    haltbutton = NewControl (myWindow, &pRect, "\pHALT", TRUE, 0, 0, 0,
			     pushButProc, 0L);
    pRect.right = pRect.left - 1;
    pRect.left = pRect.right - (4 * cw);
    gobutton = NewControl (myWindow, &pRect, "\pGO", TRUE, 0, 0, 0,
			   pushButProc, 0L);
    pRect.right = pRect.left - 1;
    pRect.left = pRect.right - (6 * cw);
    stepbutton = NewControl (myWindow, &pRect, "\pSTEP", TRUE, 0, 0, 0,
			     pushButProc, 0L);

    pRect.right = pRect.left - 1;
    pRect.left = pRect.right - (6 * cw);
    nextbutton = NewControl (myWindow, &pRect, "\pNEXT", TRUE, 0, 0, 0,
			     pushButProc, 0L);

    pRect.right = pRect.left - 1;
    pRect.left = pRect.right - (5 * cw);
    finbutton = NewControl (myWindow, &pRect, "\pFIN", TRUE, 0, 0, 0,
			    pushButProc, 0L);

    pRect.right = pRect.left - 1;
    pRect.left = pRect.right - (6 * cw);
    viewbutton = NewControl (myWindow, &pRect, "\pVIEW", TRUE, 0, 0, 0,
			     pushButProc, 0L);

    pRect.top = 20 + 0;
    pRect.left = 0;
    pRect.right = 2 + (cw * 80);	/* 2 allows border */
    pRect.bottom = 20 + ch * 21;

    SetPort (myWindow);
    TextFont (monaco);
    TextSize (font_points);
    TextFace (normal);
    TextMode (srcCopy);
    sv_const.numlines = 24;
    sv_const.numcols = 80;
    sv_const.scrnest++;
    scr_erase ();		/* erase the display */
#endif /* macintosh */

#if MSDOS&(!WIN32)
    (void) signal (SIGINT, intrpt1);
    (void) signal (SIGFPE, fphandler);
    sv_const.scrnest++;
#if PC9801
    cprintf ("%s%s", esc, ">5l");	/*cursor display on     */
    cprintf ("%s%s", esc, ">3l");	/*25 line mode */
    cprintf ("%s%s", esc, ">1h");	/*disable function key */

/* set vram start address */
    {
	char *env98,
	*eptr98;
	short temp;

	inregs.w.dx = 0;
	inregs.h.ah = 0xe;
	int386 (0x18, &inregs, &inregs);
	boldattr = BOLDATRB;
	if ((env98 = getenv ("MACOLOR")) != NULL)
	{
	    temp = 0x0f & (int) strtol (env98, &eptr98, 0);
	    if (errno != ERANGE)
		boldattr = ((temp & 0x07) << 5) | ((temp & 0x08) >> 1) | 1;
	}
    }
#else /* PC9801 */
    if (!dv_const.nodisplay)
    {
	inregs.w.ax = 0x0f00;	/* read video mode */
	int386 (0x10, &inregs, &outregs);
	if (outregs.h.al == 7)
	{				/* monochrome adaptor's only possible mode */
#ifdef __WATCOMC__
	    TXTRAM = 0xb0000l;
#else
	    TXTRAM = 0xb0000000l;
#endif
	}
	else
	{				/* everything else can use mode 2 (text 80 ) */
#ifdef __WATCOMC__
	    TXTRAM = 0xb8000l;
#else
	    TXTRAM = 0xb8000000l;
#endif
	    inregs.w.ax = 0x0002;	/* select text mode 80 col */
	    int386 (0x10, &inregs, &outregs);
	    inregs.w.ax = 0x0500;	/* select display page 0 */
	    int386 (0x10, &inregs, &outregs);
	}
    }

#endif /* PC9801 */
    scr_erase ();		/* erase the display */
#endif /* MSDOS */

#if WIN32

    {
	CONSOLE_CURSOR_INFO cci; 
	DWORD dwMode;
	SHORT conx,cony;
	BOOL bSuccess;
	OSVERSIONINFO osVer; /* for GetVersionEx() */
	
	/* check if Win32s, if so, display notice and terminate */
	osVer.dwOSVersionInfoSize = sizeof(osVer);
	bSuccess = GetVersionEx(&osVer);
	if (osVer.dwPlatformId == VER_PLATFORM_WIN32s)
	{
	    exit(0);
	}

	SetConsoleTitle("Motorola DSP");
	hStdIn = hStdIn_saved = GetStdHandle(STD_INPUT_HANDLE);
	GetConsoleMode(hStdIn, &hStdIn_dwMode);
	hStdOut = hStdOut_saved = GetStdHandle(STD_OUTPUT_HANDLE);
	conx = getConX(hStdOut);
	cony = getConY(hStdOut);

	GetConsoleMode(hStdOut, &hStdOut_dwMode);
	
	cci.dwSize = 100;
	cci.bVisible = TRUE;
	SetConsoleCursorInfo(hStdOut, &cci);

	hConsole = CreateConsoleScreenBuffer(
            GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
            NULL, CONSOLE_TEXTMODE_BUFFER,NULL);					     
	getConTextAttributes(hConsole);
	
	GetConsoleMode(hConsole, &dwMode);
	SetConsoleMode(hConsole,dwMode & (~(ENABLE_PROCESSED_OUTPUT|
				   ENABLE_WRAP_AT_EOL_OUTPUT)));
	SetConsoleActiveScreenBuffer(hConsole);
	resizeConBufAndWindow(hConsole, conx,cony);

	GetConsoleMode(hStdIn, &dwMode);
	SetConsoleMode(hStdIn,(dwMode | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT) &
		       ~(ENABLE_LINE_INPUT|
			 ENABLE_ECHO_INPUT|
			 ENABLE_MOUSE_INPUT));

	SetConsoleCtrlHandler(ctrlc_handler,TRUE);
	(void) signal (SIGFPE, w32fphandler);
	sv_const.scrnest++;
	scr_erase ();		/* erase the display */
    }
#endif

#if UNIX
    if (!dv_const.nodisplay)
    {
	(void) initscr ();		/* initialize screen structures */
	cbreak ();			/* don't echo characters to screen from getch */
	noecho ();
	nonl ();			/* turn off newline optimize checks */
    }
    else
    {
	LINES = 24;
	COLS = 80;
    }
    if (signal (SIGINT, SIG_IGN) != SIG_IGN)
    (void) signal (SIGINT, intrpt1);
    (void) signal (SIGWINCH, winchange);
    sv_const.numlines = LINES;
    sv_const.numcols = COLS - 1;
    sv_const.cmdline = LINES - 3;
    scr_erase ();		/* erase the display */
#endif
}

/*
   * scr_erase --- erase the terminal display
   *
   * Not much to say about this.
 */

static void
scr_erase (void)

{
    /* Clears the display */
#if UNIX
    hln = 0;
    if (!dv_const.nodisplay)
    {
	clear ();
	touchwin (curscr);
	if ((!dv_var) || (dv_var->devindex == sv_const.viewdev))
	{
	    refresh ();
	}
    }
    (void) memset ((char *) hhi, 7, sizeof (hhi));
    (void) memset ((char *) htx, ' ', sizeof (htx));
    (void) memset ((char *) dhi, 7, sizeof (dhi));
    (void) memset ((char *) dtx, ' ', sizeof (dtx));
    sv_const.scrnest = 0;
#endif
#if PC9801
    cprintf ("%s%s2J", norm, esc);

    hln = 0;
    (void) memset ((char *) hhi, 7, sizeof (hhi));
    (void) memset ((char *) htx, ' ', sizeof (htx));
    sv_const.scrnest = 0;
#endif

#if WIN32
{
  COORD coordScreen = { 0, 0 }; /* here's where we'll home the cursor */
  DWORD cCharsWritten;
  CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
  DWORD dwConSize; /* number of character cells in the current buffer */

  /* get the number of character cells in the current buffer */
    if (!dv_const.nodisplay)
    {
	GetConsoleScreenBufferInfo(hConsole, &csbi);
	dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
	/* fill the entire screen with blanks */
	FillConsoleOutputCharacter(hConsole, (TCHAR) ' ',
				   dwConSize, coordScreen, &cCharsWritten);
	/* get the current text attribute */
	GetConsoleScreenBufferInfo(hConsole, &csbi);
	/* now set the buffer's attributes accordingly */
	FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
				   dwConSize, coordScreen, &cCharsWritten);
	/* put the cursor at (0, 0) */
	SetConsoleCursorPosition(hConsole, coordScreen);
    }
  hln = 0;
  (void) memset ((char *) hhi, 7, sizeof (hhi));
  (void) memset ((char *) htx, ' ', sizeof (htx));
  sv_const.scrnest = 0;
}
#endif

#if MSDOS&(!PC9801)&(!WIN32)
    int line;

    if (!dv_const.nodisplay)
    {
#ifdef __WATCOMC__
	inregs.w.ax = 0x600;	/* blank entire screen */
	inregs.w.bx = 0x700;
	inregs.w.cx = 0;
	inregs.w.dx = (24 << 8) | DSP_FULLINE - 1;
	int386 (0x10, &inregs, &outregs);
#else
	inregs.x.ax = 0x600;	/* blank entire screen */
	inregs.x.bx = 0x700;
	inregs.x.cx = 0;
	inregs.x.dx = (24 << 8) | DSP_FULLINE - 1;
	int86 (0x10, &inregs, &outregs);
#endif
    }
    hln = 0;
    (void) memset ((char *) hhi, 7, sizeof (hhi));
    (void) memset ((char *) htx, ' ', sizeof (htx));
    sv_const.scrnest = 0;
#endif


#if macintosh
    hln = 0;
    (void) memset ((char *) hhi, 7, sizeof (hhi));
    (void) memset ((char *) htx, ' ', sizeof (htx));
    simw_refresh ();
#endif
}

/*
   * simw_redo --- Repaint the screen from a device's display buffer
   *
   * This routine repaints the screen using the information in a device's
   * display buffer. This is done after scrolling up through the display 
   * buffer or after loading a simulator state file. Just the bottom page
   * of the display is repainted after the screen is erased.  The multiple
   * dsp simulation examples also use this function when switching the
   * displayed device on a single window display.
 */

void
simw_redo (int devindex)

{
    struct sev_window *sim_win;

    sv_var = sv_const.sv[devindex];
    if (!sv_var)
	return;
    sim_win = sv_var->win;

    /* Select last page of buffered output for re-display */
    sim_win->head = sv_const.cmdline;	/* number of display lines */
    switch (sv_var->display_mode)
    {
    case REG_DISPLAY:
	simw_redraw (sv_const.winsz);	/* redraw screen */
        break;
    case ASM_DISPLAY:
    case SRC_DISPLAY:
	siml_display_source (0x7fff);
        break;
    }
}

#define PASS_BRACES 1
#define HILITE_BRACES 0

#define COMMAND_STRING 0
#define HILITE_ON_CHAR '\017'
#define HILITE_OFF_CHAR '\007'

static void
gti_wscr (char *bufptr,  int buf_type, int hilite_flag)
{
    struct sev_window *sim_win;

    if (!sv_var)
	return;
    sim_win = sv_var->win;

    sim_win->next++;

    if (sim_win->next == sv_const.winsz)
	sim_win->next = 0;	/* circular buffer */
    sim_win->head++;
    (void) strncpy (sim_win->dbuf[sim_win->next].lbuf, bufptr, DSP_LINE_LEN - 1);	/* insert new text at "next" */

    if (hilite_flag == HILITE_BRACES)
    {
	/* replace braces with nonprintable hilite characters */
        /* don't replace braces that are escaped by a $ */
	char *cp,ch_temp;
	int i, to;
	cp = &sim_win->dbuf[sim_win->next].lbuf[0]; 
	for (i=0, to=0; i<DSP_LINE_LEN; i++, to++)
	{
	    ch_temp = cp[i];
            if ((ch_temp == '$') &&
                ((cp[i+1] == '{') || (cp[i+1] == '}')))
            {
                cp[to] = cp[i+1];
                ++i;
            }
            else if (ch_temp == '{')
	    {
		cp[to] = HILITE_ON_CHAR;
	    }
	    else if (ch_temp == '}')
	    {
		cp[to] = HILITE_OFF_CHAR;
	    }
	    else if (!ch_temp)
	    {
                cp[to] = '\0';
		break;
	    }
            else
            {
                cp[to] = ch_temp;
            }
	}
    }
    
    if (dv_var->devindex == sv_const.viewdev && (sv_var->display_mode == REG_DISPLAY))
    {
	simw_redraw (sim_win->head);	/* display the window buffer last page */
	if (sv_const.more_processing_flag)
	{
	    sv_const.lines_written++;
	    if (sv_const.lines_written >= (sv_const.cmdline))
	    {
		sv_const.lines_written = 0;
		siml_help_prnt ("{More: Type any key to continue.}\t");
		simw_refresh ();
		if (simw_gkey () == DSP_CTRLC)
	           dv_const.CTRLBR = 1;
		siml_help_prnt ("\t");
		simw_scrnest ();
	    }
	}
    }

    if (buf_type == COMMAND_STRING)
    {				/* check for a command.  If so, log to log c file */
	if (sv_const.logcfp)
	{			/* log commands only */
	    (void) fprintf (sv_const.logcfp, "%s\n", bufptr);
	    (void) fflush (sv_const.logcfp);
	}
#if macintosh
	siml_stackcmd (bufptr);
#endif
    }
    if (sv_var->stat.logsfp)
    {				/* normal non-command (session) output */
	(void) fprintf (sv_var->stat.logsfp, "%s\n", bufptr);	/* log to log s file */
	(void) fflush (sv_var->stat.logsfp);
    }
}

/*
   * simw_wscr --- write simulator output to the virtual screen buffer
   *
   * This function writes output to the scrolling portion of the simulator
   * screen.  It also takes care of logging the information to a command
   * log file or a session log file if logging has been enabled.  The
   * "flag" parameter, when set to 0, indicates that the line corresponds
   * to a simulator command.  Only commands are stored to the command log
   * file.  The simulator screen will only be updated if the device index
   * is the same as the sv_const.viewdev value, but the last sv_const.winsz lines of
   * simulator output for each device are always available in the device   
   * display buffer whether or not they are actually written to the screen.
 */

void
simw_wscr_c (char *bufptr,
             int flag)

{
#if ADSx    
    if (sv_const.viewdev != previous_device)
    {
        char buf[256];

        sprintf (buf, "{ADM #%d}", sv_const.viewdev);
        
        gti_wscr (buf, 1, HILITE_BRACES);

        previous_device = sv_const.viewdev;
    }
#endif /* ADSx */    

    gti_wscr (bufptr, flag, PASS_BRACES);
}

void
simw_wscr (char *bufptr,
	   int flag)

{
    ut_simw_wscr(bufptr);

#if ADSx    
    if (sv_const.viewdev != previous_device)
    {
        char buf[256];

        sprintf (buf, "{ADM #%d}", sv_const.viewdev);
        
        gti_wscr (buf, 1, HILITE_BRACES);

        previous_device = sv_const.viewdev;
    }
#endif /* ADSx */    

    gti_wscr (bufptr, flag, HILITE_BRACES);
}

/*
   * simw_redraw --- redraws the screen after display updates
   *
   * This function takes care of the necessary steps to update the terminal 
   * screen from a devices display buffer.  It is may be used to scroll up 
   * or down through the display as well.  The display output if buffered   
   * on systems that support buffering until the complete redraw is finished.
 */

void
simw_redraw (int count)
{
    /* Repaint the screen from the sim_win->dbuf buffer */
    struct sev_window *sim_win;
    int tail,
     next,
     nextp,
     head,
     mtail;

#if macintosh
    int y,
     sbar;
    GrafPtr saveport;

#endif
    if (!sv_var)
	return;
    sim_win = sv_var->win;
#if macintosh
    GetPort (&saveport);
    SetPort (myWindow);

    y = GetCtlValue (scrollbar) + count;
    sbar = (sv_const.winsz - sv_const.cmdline);
    if (y > sbar)
	y = sbar;
    else if (y < 0)
	y = 0;
    SetCtlValue (scrollbar, y);
#endif
    sv_const.scrnest++;		/* Buffer display */
    next = sim_win->next;
    head = sim_win->head;
    if (count < 0)
    {
	count = -count;
	tail = (head + sv_const.cmdline);
	mtail = sv_const.winsz - tail;	/* remaining part of buffer */
	if (count > mtail)
	    count = mtail;
	if (count >= sv_const.cmdline)
	{
	    head += count - sv_const.cmdline;
	    count = sv_const.cmdline;
	    tail = head + count;
	}
	nextp = next - tail;
	head += count;
	while (count-- > 0)
	{			/* scroll display down by count number of lines */
	    gti_scroll (-1);
	    if (nextp < 0)
		nextp += sv_const.winsz;
	    simw_puts (0, 0, sim_win->dbuf[nextp].lbuf, 1);
	    nextp--;
	}
    }
    else
    {
	if (count > head)
	    count = head;
	if (count >= sv_const.cmdline)
	{
	    head -= count - sv_const.cmdline;
	    count = sv_const.cmdline;
	}
	nextp = (next - head) + 1 + sv_const.winsz;
	head -= count;
	while (count-- > 0)
	{			/* scroll display up count number of lines */
	    gti_scroll (1);
	    if (nextp >= sv_const.winsz)
		nextp -= sv_const.winsz;
	    simw_puts (sv_const.cmdline - 1, 0, sim_win->dbuf[nextp].lbuf, 1);
	    nextp++;
	}
    }
    sim_win->head = head;
    simw_unnest ();
#if macintosh
    SetPort (saveport);
#endif
}

/*
   * gti_scroll --- scrolls the screen display up or down one line
   *
   * This function scrolls the area of the screen above the command line    
   * up or down one line.  The top or bottom line are left blank after this
   * function call, but will normally be updated by the simw_redraw() function
   * to display the proper line from the device display buffer.
 */

static void
gti_scroll (int direction	/* 1=scroll up, -1= scroll down */
)

{
    /* Scroll display region up or down one line */
    if (direction > 0)
    {
	hln++;
	if (hln == sv_const.cmdline)
	    hln = 0;
    }
    else
    {
	hln--;
	if (hln < 0)
	    hln = sv_const.cmdline - 1;
    }
}

/*
   * sim_cursor --- moves the cursor to the specified line and column 
   *
   * This function moves the cursor and updates the curline and curclm     
   * variables in sv_var.
 */

void
simw_cursor (int line,
	     int column)

{

#if WIN32
    if (sv_const.scrnest <= 0)
	simw_refresh ();
    sv_const.curline = line;
    sv_const.curclm = column;
    if (!dv_const.nodisplay)
    {
	COORD coordScreen;
	coordScreen.X = column;
	coordScreen.Y = (SHORT) (line);
	SetConsoleCursorPosition(hConsole, coordScreen);
    }
#else
/* Move cursor to the specified line and column */
#if MSDOS&(!PC9801)
    if (sv_const.scrnest <= 0)
	simw_refresh ();
    sv_const.curline = line;
    sv_const.curclm = column;
    if (!dv_const.nodisplay)
    {
#ifdef __WATCOMC__
	inregs.w.dx = (line << 8) | column;
	inregs.w.bx = 0;
	inregs.h.ah = 2;
#else
	inregs.x.dx = (line << 8) | column;
	inregs.x.bx = 0;
	inregs.h.ah = 2;
#endif
#ifdef __WATCOMC__
	int386 (0x10, &inregs, &outregs);
#else
	int86 (0x10, &inregs, &outregs);
#endif
    }
#endif

#if PC9801
    if (sv_const.scrnest <= 0)
	simw_refresh ();
    sv_const.curline = line;
    sv_const.curclm = column;
    {
	int tmp;

	tmp = line * 160 + column + column;	/* move cursor */
	inregs.h.ah = 0x13;
	inregs.w.dx = tmp;
	int386 (0x18, &inregs, &inregs);
    }
#endif
#endif

#if UNIX
    sv_const.curline = line;
    sv_const.curclm = column;
    if (sv_const.scrnest <= 0)
    {
	simw_refresh ();
    }
#endif
#if macintosh
    GrafPtr saveport;

    if (sv_const.scrnest <= 0)	/*??? */
	simw_refresh ();
    GetPort (&saveport);
    SetPort (myWindow);
    sv_const.curline = line;
    sv_const.curclm = column;
    MoveTo (column * cw + 1, line * ch + font_points + 20);	/* changed */
    SetPort (saveport);
#endif
}

/*
   * simw_putc --- output a character to the screen 
   *
   * This function outputs a character to the screen at the current cursor  
   * position and updates the column position.  It is not used much in the
   * simulator, so it doesn't need to be very efficient.  This implementation
   * just passes the value on to gti_ps().
 */

void
simw_putc (char c)

{
    /* Output a character to screen at current cursor position */
    /* Update current column position */
    char text[2];

    text[1] = 0;
    text[0] = c;
    sv_const.scrnest++;
    gti_ps (text, 0);
    simw_unnest ();
}

/*
   * simw_ceol --- clear to end of line from current cursor position
   *
   * This function clears to end of line and leaves the cursor back at    
   * its original position.
 */

void
simw_ceol (void)

{
    /* clear to end of line from current cursor position */
    int i,
     j,
     k,
     m;

    i = sv_const.curline;
    j = sv_const.curclm;
    if (i >= sv_const.cmdline)
	m = (DSP_LINES_MAX - 3) + (i - sv_const.cmdline);
    else
    {
	m = hln + i;
	if (m >= sv_const.cmdline)
	    m -= sv_const.cmdline;
    }

#if WIN32
    k = sv_const.numcols + 1 - j;
#else
    k = DSP_COLS_MAX - j;
#endif
    if (k > 0)
    {
	(void) memset ((char *) &hhi[m][j], 7, k);
	(void) memset ((char *) &htx[m][j], ' ', k);
    }
}

/*
   * gti_ps --- put a formatted string to the terminal on current line
   *
   * This function outputs the string to the terminal.  Some formatting     
   * characters are intercepted.  Curly braces {} set character highliting on
   * and off.  The tab character and the newline will cause a clear to the 
   * end of the line.  Non-format characters are output to the terminal in
   * strings for maximum speed.  The output is buffered until the entire string
   * is completed.
 */

static void
gti_ps (char *string,
	int flag		/*    flag         0=Normal hilite  1=on/off 2=BOLD */
	               		/*                 3=on/off with brace translation  */
)

{
    char cht;
    int h_attribute,
     m,
     i;

    h_attribute = (flag == 2) ? 0xf : 0x7;
    i = sv_const.curline;
    if (i >= sv_const.cmdline)
	m = (DSP_LINES_MAX - 3) + (i - sv_const.cmdline);
    else
    {
	m = hln + i;
	if (m >= sv_const.cmdline)
	    m -= sv_const.cmdline;
    }

    while ((cht = *string))
    {
	switch (cht)
	{
	case '\n':
	case '\t':
	    simw_ceol ();
	    break;
	case HILITE_ON_CHAR:
	    if (flag == 1)
		h_attribute = 0xf;
	    break;		/* BOLD HIGHLITE ATTRIBUTE */
	case HILITE_OFF_CHAR:
	    if (flag == 1)
		h_attribute = 0x7;
	    break;		/* NORMAL HIGHLITE ATTRIBUTE */
	case '{':
	    if (flag == 3)
	    {
		h_attribute = 0xf;
		break;		/* BOLD HIGHLITE ATTRIBUTE */
	    }
            /* FALL THROUGH */
	case '}':
	    if (flag == 3)
	    {
		h_attribute = 0x7;
		break;		/* NORMAL HIGHLITE ATTRIBUTE */
	    }
            /* FALL THROUGH */
        case '$':
            /* don't hilite if it has a $ before it */
            /* check for $ since we might have fallen through */
            /* from above */
            if ((flag==3) && cht == '$' && (*(string+1)=='}' || *(string+1)=='{'))
            {
                cht = *(string+1);
                ++string;
            }
            /* FALL THROUGH */
	default:
	    if (sv_const.curclm < DSP_COLS_MAX)
	    {
		htx[m][sv_const.curclm] = cht;
		hhi[m][sv_const.curclm] = h_attribute;
		sv_const.curclm++;
	    }
	    break;
	}
	string++;
    }				/* end of while */
    simw_ceol ();
    if (sv_const.curclm >= sv_const.numcols)
	sv_const.curclm = sv_const.numcols - 1;
}

/*
   * simw_puts --- put a text string to the terminal at line and column
   *
   * This function is normally called by the simulator when writing to the
   * command line, error line and help line.  It doesn't invoke the session
   * logging calls that are associated with calls to simw_wscr().  The exact
   * line and column are specified.  It doesn't store output in the device
   * display buffer either.
 */

void
simw_puts (int line,
	   int column,
	   char *text,
	   int flag)

{
    /* Put text string to terminal at line and column specified */
    /* The main work-horse is gti_ps. */
    sv_const.scrnest++;
    sv_const.curline = line;
    sv_const.curclm = column;
    gti_ps (text, flag);
    simw_unnest ();
}

#if macintosh
static void 
draw_cursor ()			/* draw cursor at current position */
{
    Point pt;
    Rect rect;
    PenState ps;
    GrafPtr saveport;

    GetPort (&saveport);
    SetPort (myWindow);

    GetPenState (&ps);
    pt.h = ps.pnLoc.h;
    pt.v = ps.pnLoc.v;
    SetRect (&rect, pt.h, pt.v, pt.h + cw, pt.v + 1);
    InvertRect (&rect);
    SetPort (saveport);
}
#endif

/*
   * simw_gkey --- get keyboard input and map to a simulator code   
   *
   * This function takes care of mapping raw keyboard input to a code     
   * acceptable by the simulator.  If you don't happen to like the control
   * characters used by the simulator, this is the function you should
   * modify.  Vax users may also need to modify the outofband() function
   * which intercepts control characters and does some translation before
   * they arrive here.
 */

int
simw_gkey (void)

{
    /* get key from keyboard and map to simulator key */
#if macintosh
    int key;
    long l;

    static int keymap[] =
    {
	0, 0, DSP_CTRLB, DSP_CTRLC, 0, DSP_MOVEEOL, DSP_CTRLF, 0, DSP_DELB, DSP_TABR,
	DSP_CR, DSP_DELF, DSP_CURL, DSP_CR, DSP_LINED, DSP_INSERT, 0, 0, DSP_CURR, 0,
	DSP_PAGEU, DSP_LINEU, DSP_PAGED, DSP_WINDOW, 0, 0, DSP_DELEOL, DSP_ESCAPE, DSP_CURL, DSP_CURR,
	DSP_LINEU, DSP_LINED, DSP_SPACE, 33, 34, 35, 36, 37, 38, 39,
	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
	70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
	80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
	90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
	100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
	110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
	120, 121, 122, 123, 124, 125, 126, DSP_DELB
    };

    draw_cursor ();
    while (!GetNextEvent (keyDownMask + autoKeyMask, &myEvent))
	if (key = otherevents ())
	{
	    draw_cursor ();
	    if (key == DSP_CTRLC)
		dv_const.CTRLBR = 1;
	    return (key);
	}

    if (myWindow == FrontWindow ())
    {
	key = (myEvent.message) & charCodeMask;
	if (myEvent.modifiers & cmdKey && (l = MenuKey (key)))
	{
	    docommand (l);
	    key = 0;
	}
    }
    else
	key = 0;

    draw_cursor ();		/* clear cursor */
    if (key > 127 || key < 0)
	key = 0;
    else
	key = keymap[key];
    if (key == DSP_CTRLC)
	dv_const.CTRLBR = 1;
    return (key);
#endif

#if WIN32
    int key;
    int executing, i;

    struct sev_var *sv;
    static int in_exec_handler = FALSE;

    static int vk_init;
    static int vkeymap[256];

    INPUT_RECORD inputBuffer;
    DWORD dwInputEvents; /* number of events actually read */


    if (!vk_init)
    {
        vk_init = 1;
        vkeymap[VK_LBUTTON] = DSP_CURL;
        vkeymap[VK_RBUTTON] = DSP_CURR;
        vkeymap[VK_CANCEL] = DSP_CTRLC;
        vkeymap[VK_TAB] = DSP_TABR;
        vkeymap[VK_CLEAR] = DSP_DELEOL;
        vkeymap[VK_RIGHT] = DSP_CURR;
        vkeymap[VK_LEFT] = DSP_CURL;
        vkeymap[VK_INSERT] = DSP_INSERT;
        vkeymap[VK_UP] = DSP_PAGEU;
        vkeymap[VK_DOWN] = DSP_PAGED;
        vkeymap[VK_PRIOR] = DSP_LINEU;
        vkeymap[VK_NEXT] = DSP_LINED;
        vkeymap[VK_ESCAPE] = DSP_ESCAPE;
        vkeymap[VK_SPACE] = DSP_SPACE;
        vkeymap[VK_DELETE] = DSP_DELF;
        vkeymap[VK_BACK] = DSP_DELB;
    }

#if ADSx

    key = 0;

    executing = FALSE;
    
    for (i = 0; i < dv_const.maxdevices; i++)
    {
        sv = sv_const.sv[i];
        if (sv && sv->stat.executing)
        {
            executing = TRUE;
            break;
        }
    }

    if (executing && !in_exec_handler)
    {
        in_exec_handler = TRUE;
                    
        key = 0;
        
        while (executing && !key)
        {
            int current_device;

            current_device = sv_const.viewdev;
            
            executing = FALSE;

            for (i = 0; i < dv_const.maxdevices; i++)
            {
                sv = sv_const.sv[i];
                if (sv && sv->stat.executing && !sv->stat.poll_error)
                {
                    executing = TRUE;

                    siml_switch_to_device (i);

                    if (siml_brk (i) == DSP_ERROR)
                    {
                        /* Lost communication with the device */
                        sv->stat.poll_error = TRUE;
                    }
                }
            }

            siml_switch_to_device (current_device);
                    
            /* check for an event */
            if ( WaitForSingleObject(hStdIn,0) != WAIT_TIMEOUT )
            {
                /* get the event */
                ReadConsoleInput(hStdIn, &inputBuffer, 1, &dwInputEvents);

                /* if the event is a keyboard event, 
                 * process it.
                 */
                if ( inputBuffer.EventType == KEY_EVENT )
                {
                    if (inputBuffer.Event.KeyEvent.bKeyDown)
                    {
                        int vkey = (inputBuffer.Event.KeyEvent.wVirtualKeyCode);
                        if ((vkey) && vkeymap[vkey])
                        {
                            key = vkeymap[vkey];
                        }
                        else
                        {
                            key = inputBuffer.Event.KeyEvent.uChar.AsciiChar;
                        }
                    }
                }
            }
        }

        in_exec_handler = FALSE;
    }

    else
    {
        /* wait for the user input */

        /* we cannot just wait for a key event. In Win32,
           we have to wait for an event and check if it is 
           a keyboard one 
        */
        key = 0;
        while (key == 0)
        { 
            do{
                WaitForSingleObject(hStdIn,INFINITE);
                ReadConsoleInput(hStdIn, &inputBuffer, 1, &dwInputEvents);
            }while ((inputBuffer.EventType != KEY_EVENT)  &&
		            (inputBuffer.EventType != WINDOW_BUFFER_SIZE_EVENT) &&
                    (inputBuffer.EventType != FOCUS_EVENT) );

            switch (inputBuffer.EventType)
            {
                case KEY_EVENT:
                    if (inputBuffer.Event.KeyEvent.bKeyDown)
                    {
                        int vkey = (inputBuffer.Event.KeyEvent.wVirtualKeyCode);

                        if ((vkey) && vkeymap[vkey])
                        {
                            key = vkeymap[vkey];
                        }
                        else
                        {
                            key = inputBuffer.Event.KeyEvent.uChar.AsciiChar;
                        }
                    }
                    break;

                case WINDOW_BUFFER_SIZE_EVENT:
                    {
                        SHORT xSize, ySize;

                        xSize = getConX(hConsole);
                        ySize = getConY(hConsole);
                        resizeConBufAndWindow(hConsole,xSize, ySize);
                    }
                    break;

                case FOCUS_EVENT:
        	        getConTextAttributes(hConsole);
        	        simw_refresh();
        	        break;
            }
        }
    }

#else    

    key = 0;
    if (!dv_const.nodisplay)
    {
        while (key == 0)
        {
            do{
                WaitForSingleObject(hStdIn,INFINITE);
                ReadConsoleInput(hStdIn, &inputBuffer, 1, &dwInputEvents);
            }while ((inputBuffer.EventType != KEY_EVENT) &&
                    (inputBuffer.EventType != WINDOW_BUFFER_SIZE_EVENT) &&
                    (inputBuffer.EventType != FOCUS_EVENT)
                   );

            switch (inputBuffer.EventType)
            {
                case KEY_EVENT:
                    if (inputBuffer.Event.KeyEvent.bKeyDown)
                    {
                        int vkey = (inputBuffer.Event.KeyEvent.wVirtualKeyCode);
                        if ((vkey) && vkeymap[vkey])
                        {
                            key = vkeymap[vkey];
                        }
                        else
                        {
                            key = inputBuffer.Event.KeyEvent.uChar.AsciiChar;
                        }
                    }
                    break;

                case WINDOW_BUFFER_SIZE_EVENT:
                    {
                        SHORT xSize, ySize;
                    	xSize = getConX(hConsole);
                        ySize = getConY(hConsole);
                        resizeConBufAndWindow(hConsole,xSize, ySize);
                    }
                    break;

                case FOCUS_EVENT:
                    getConTextAttributes(hConsole);
                    simw_refresh();
                    break;
            }
        }
    }

#endif /* ADSx */

    return (key);

#endif /* WIN32 */

#if   MSDOS&(!PC9801)&(!WIN32)
    /* get key scan code into AH, ascii result into AL.
       * If AL==0, map extended code to ASCII control character.
       * Otherwise return the ascii code from AL.
     */
#if ADSx
    int i;
    int executing;
    struct sev_var *sv;
    static int in_exec_handler = FALSE;
#endif    
    int key;
    static int keymap[256] =
    {
	DSP_CTRLC, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, DSP_LINEU, DSP_PAGEU, 0, DSP_CURL, 0, DSP_CURR, 0, DSP_MOVEEOL,
	DSP_LINED, DSP_PAGED, DSP_INSERT, DSP_DELF, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, DSP_TABR, DSP_DELEOL, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0
    };
#if ADSx
    executing = FALSE;
    
    for (i = 0; i < dv_const.maxdevices; i++)
    {
        sv = sv_const.sv[i];
        if (sv && sv->stat.executing)
        {
            executing = TRUE;
            break;
        }
    }

    if (executing && !in_exec_handler)
    {
        in_exec_handler = TRUE;
                    
        key = 0;
        
        while (executing && !key)
        {
            int current_device;

            current_device = sv_const.viewdev;
            
            executing = FALSE;

            for (i = 0; i < dv_const.maxdevices; i++)
            {
                sv = sv_const.sv[i];
                if (sv && sv->stat.executing && !sv->stat.poll_error)
                {
                    executing = TRUE;

                    siml_switch_to_device (i);

                    if (siml_brk (i) == DSP_ERROR)
                    {
                        /* Lost communication with the device */
                        sv->stat.poll_error = TRUE;
                    }
                }
            }

            siml_switch_to_device (current_device);
                    
            if (kbhit ())
            {
                inregs.w.ax = 0x0000;	/* direct console i/o */
                int386 (0x16, &inregs, &outregs);
            
                if (outregs.h.al != 0)
                {
                    key = outregs.w.ax & 0x007f;	/* already ascii */
                }
            
                else
                {
                    /* Map special to ascii */
                    key = keymap[(outregs.w.ax / 0x100) & 0xff];
                }
            }
            
        }

        in_exec_handler = FALSE;
    }

    else
    {
        inregs.w.ax = 0x0000;	/* direct console i/o */
        int386 (0x16, &inregs, &outregs);

        if (outregs.h.al != 0)
        {
            key = outregs.w.ax & 0x007f;	/* already ascii */
        }
            
        else
        {
            /* Map special to ascii */
            key = keymap[(outregs.w.ax / 0x100) & 0xff];
        }
    }
    
#else    
    if (!dv_const.nodisplay)
    {
#ifdef __GNUC__
        outregs.h.al = getkey ();
#else

#ifdef __WATCOMC__
        inregs.w.ax = 0x0000;	/* direct console i/o */
        int386 (0x16, &inregs, &outregs);
#else
        inregs.x.ax = 0x0000;	/* direct console i/o */
        int86 (0x16, &inregs, &outregs);
#endif /* __WATCOMC__ */

#endif /* __GNUC__ */

#ifdef __WATCOMC__
        if (outregs.h.al != 0)
            key = outregs.w.ax & 0x007f;	/* already ascii */
        else
            key = keymap[(outregs.w.ax / 0x100) & 0xff];	/* Map special to ascii */
#else
        if (outregs.h.al != 0)
            key = outregs.x.ax & 0x007f;	/* already ascii */
        else
            key = keymap[(outregs.x.ax / 0x100) & 0xff];	/* Map special to ascii */
#endif /* __WATCOMC__ */
    }
    else
    {
        key = 0;
    }
#endif /* ADSx */    
    return (key);
#endif

#if UNIX
    int key;
    char ckey;
#if ADSx
    int i;
    int executing;
    struct sev_var *sv;
#endif

    static int keymap[] =
    {
	0, 0, DSP_CTRLB, DSP_CTRLC, 0, DSP_MOVEEOL, DSP_CTRLF, 0, DSP_DELB, DSP_TABR,
	DSP_CR, DSP_DELF, DSP_CURL, DSP_CR, DSP_LINED, DSP_INSERT, 0, 0, DSP_CURR, 0,
	DSP_PAGEU, DSP_LINEU, DSP_PAGED, DSP_WINDOW, 0, 0, DSP_DELEOL, DSP_ESCAPE, 0, 0,
	0, 0, DSP_SPACE, 33, 34, 35, 36, 37, 38, 39,
	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
	70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
	80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
	90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
	100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
	110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
	120, 121, 122, 123, 124, 125, 126, DSP_DELB
    };
#if ADSx
    executing = FALSE;
    
    for (i = 0; i < dv_const.maxdevices; i++)
    {
        sv = sv_const.sv[i];
        if (sv && sv->stat.executing)
        {
            executing = TRUE;
            break;
        }
    }

    if (executing)
    {
        ckey = 0;
        
        while (executing && !ckey)
        {
            int current_device;

            current_device = sv_const.viewdev;
            
            executing = FALSE;

            for (i = 0; i < dv_const.maxdevices; i++)
            {
                sv = sv_const.sv[i];
                if (sv && sv->stat.executing && !sv->stat.poll_error)
                {
                    executing = TRUE;

                    siml_switch_to_device (i);
                    
                    if (siml_brk (i) == DSP_ERROR)
                    {
                        /* Lost communication with the device */
                        sv->stat.poll_error = TRUE;
                    }
                }
            }

            siml_switch_to_device (current_device);
            
            ckey = kbdhit ();
        }
    }

    else
    {
        ckey = getch ();
    }
    
#else
    if (!dv_const.nodisplay)
    {
        ckey = getch ();
    }
    else
    {
        ckey = 0;
    }
    
#endif    
    key = ckey & 0xff;
    if (key > 127)
        key = 0;
    else
        key = keymap[key];

    if (key == DSP_ESCAPE && kbdhit ())
    {
        switch ((key = kbdhit ()))
        {
        case 0x41:
            key = DSP_LINEU;
            break;
        case 0x42:
            key = DSP_LINED;
            break;
        case 0x43:
            key = DSP_CURR;
            break;
        case 0x44:
            key = DSP_CURL;
            break;
        default:
            break;
        }
    }

    if (resize_flg && dv_var)
    {
        resize_flg = 0;
        simw_resize ();
    }
    return (key);
#endif
#if PC9801
    int key;
    static int keymap[] =
    {
        DSP_PAGED, DSP_PAGEU, DSP_INSERT, DSP_DELF, DSP_LINEU,
        DSP_CURL, DSP_CURR, DSP_LINED, 0, '?'
    };

    inregs.w.ax = 0x0005;	/* direct console i/o */
    int386 (0x18, &inregs, &outregs);
    key = outregs.h.al;
    if (key > 0x7f)
        key = 0;
    else if (!key)
    {
        key = outregs.h.ah;
        if (key > 0x3f || key < 0x36)
            key = 0;
        else
            key = keymap[key - 0x36];
    }

    return (key);
#endif

}				/* end of sim_gkey */

#if macintosh
pascal void 
myscroll (theCtrl, thePart)
ControlHandle theCtrl;
short thePart;
{
    int line,
     column;

    line = sv_const.curline;
    column = sv_const.curclm;
    switch (thePart)
    {
    case inUpButton:
        switch (sv_var->display_mode)
        {
        case REG_DISPLAY:
	    simw_redraw (-1);
            break;
        case ASM_DISPLAY:
        case SRC_DISPLAY:
	    siml_display_source (-1);
            break;
        }
	break;
    case inDownButton:
        switch (sv_var->display_mode)
        {
        case REG_DISPLAY:
	    simw_redraw (1);
            break;
        case ASM_DISPLAY:
        case SRC_DISPLAY:
	    siml_display_source (1);
            break;
        }
	break;
    case inPageUp:
        switch (sv_var->display_mode)
        {
        case REG_DISPLAY:
	    simw_redraw (-sv_const.cmdline);
            break;
        case ASM_DISPLAY:
        case SRC_DISPLAY:
	    siml_display_source (-(sv_const.cmdline - 1));
            break;
        }
	break;
    case inPageDown:
        switch (sv_var->display_mode)
        {
        case REG_DISPLAY:
	    simw_redraw (sv_const.cmdline);
            break;
        case ASM_DISPLAY:
        case SRC_DISPLAY:
	    siml_display_source ((sv_const.cmdline - 1));
            break;
        }
	break;
    }
    sv_const.scrnest = 0;
    /* simw_refresh(); ??? */
    simw_cursor (line, column);
}

static int scount;

static
otherevents ()
{
    int key = 0;
    int y1,
     y2,
     y3,
     code,
     line,
     column,
     sbar;
    ControlHandle selControl;
    int thepart;
    GrafPtr saveport;

    if (!(scount++ & 0xffff))
	SystemTask ();
    if (GetNextEvent (everyEvent ^ (keyDownMask + autoKeyMask), &myEvent))
    {
	switch (myEvent.what)
	{
	case mouseDown:
	    code = FindWindow (myEvent.where, &whichWindow);
	    switch (code)
	    {
	    case inMenuBar:
		key = docommand (MenuSelect (myEvent.where));
		break;
	    case inSysWindow:
		SystemClick (&myEvent, whichWindow);
		break;
	    case inDrag:
		DragWindow (whichWindow, myEvent.where, &dragRect);
		break;
	    case inGoAway:
		exit (0);
		break;
	    case inGrow:
		break;
	    case inContent:
		if (whichWindow != FrontWindow ())
		    SelectWindow (whichWindow);
		else
		{
		    GetPort (&saveport);
		    SetPort (myWindow);
		    GlobalToLocal (&myEvent.where);
		    thepart = FindControl (myEvent.where, myWindow, &selControl);
		    if (selControl == scrollbar)
		    {
			if (thepart == inThumb)
			{
			    line = sv_const.curline;
			    column = sv_const.curclm;
			    y1 = GetCtlValue (scrollbar);
/*			    TrackControl (scrollbar, myEvent.where, (ProcPtr) (-1l));*/
			    TrackControl (scrollbar, myEvent.where, (ControlActionUPP) (-1l));
			    y2 = GetCtlValue (scrollbar);
			    SetCtlValue (scrollbar, y1);
			    if (sv_var->display_mode == ASM_DISPLAY ||
                                sv_var->display_mode == SRC_DISPLAY)
			    {
				sbar = (sv_const.winsz - sv_const.cmdline);
				if (!sv_var->db.max_pos)
				    sv_var->db.max_pos = 1;
				if (y2 == sbar)
				    y3 = sv_var->db.max_pos - sv_var->db.current_pos;
				else if (y2 == 0)
				    y3 = 0 - sv_var->db.current_pos;
				else
				    y3 = (y2 - y1) * (((double) sv_var->db.max_pos) / (sbar + 1));
				siml_display_source (y3);
			    }
			    else
				simw_redraw (y2 - y1);
			    sv_const.scrnest = 0;
			    /* simw_refresh(); ??? */
			    simw_cursor (line, column);
			}
			else
			    TrackControl (scrollbar, myEvent.where,
					  (ControlActionUPP)(myscroll));
		    }
		    else if (selControl == haltbutton)
			dv_const.CTRLBR = 1;
		    else if (selControl == stepbutton)
		    {
			key = DSP_MACFILE;
			(void) strcpy (macstring, "step");
		    }
		    else if (selControl == nextbutton)
		    {
			key = DSP_MACFILE;
			(void) strcpy (macstring, "next");
		    }
		    else if (selControl == viewbutton)
		    {
			key = DSP_WINDOW;
		    }
		    else if (selControl == finbutton)
		    {
			key = DSP_MACFILE;
			(void) strcpy (macstring, "finish");
		    }
		    else if (selControl == gobutton)
		    {
			key = DSP_MACFILE;
			(void) strcpy (macstring, "go");
		    }
		}
		SetPort (saveport);
		break;
	    }
	    break;
	case activateEvt:
	    break;

	case updateEvt:
	    line = sv_const.curline;
	    column = sv_const.curclm;
	    macwrefresh ();
	    /* simw_cursor(line,column);??? */
	    key = 0;
	    break;
	}
    }
    return (key);
}
#endif

/*
   * simw_getch --- non-translated input from the keyboard
   *
   * This function gets keyboard input in a non-translated mode.  It's  
   * not used much in the simulator - only when returning from a SYSTEM
   * command before the screen parameters are re-initialized.
 */

void
simw_getch (void)

{
    /* non-buffered type input */
#ifdef  __GNUC__
    (void) getchar ();
#else
#if macintosh
    (void) simw_gkey ();
#else
    if (!dv_const.nodisplay)
    {
	(void) getch ();
    }
#endif
#endif
}

/*
   * simw_refresh --- repaint the screen following screen buffering 
   *
   * Some operating systems provide screen buffering support.  The simulator
   * keeps a counter call scrnest and will refresh the screen if it decrements
   * from 1 to 0.  MSDOS really isn't supported for this - but maybe in a
   * future update?
 */

void
simw_refresh (void)

{
#if UNIX
    int i,
     j,
     prev_i,
     prev_j,
     m,
     k,
     numcols;
    char attr;
    char tchar;

    prev_i = prev_j = -1;
    if ((!dv_var) || (dv_var->devindex == sv_const.viewdev))
    {
	if (resize_flg && dv_var)
	{
	    resize_flg = 0;
	    simw_resize ();
	}
	numcols = sv_const.numcols;
	for (i = 0; i < sv_const.numlines; i++)
	{
	    if (i >= sv_const.cmdline)
		m = (DSP_LINES_MAX - 3) + (i - sv_const.cmdline);
	    else
	    {
		m = hln + i;
		if (m >= sv_const.cmdline)
		    m -= sv_const.cmdline;
	    }
	    for (j = 0; j < numcols; j++)
	    {
		if (htx[m][j] != dtx[i][j] || hhi[m][j] != dhi[i][j])
		{
		    dhi[i][j] = attr = hhi[m][j];	/* update screen */
		    dtx[i][j] = htx[m][j];

		    /* move cursor to line i, column j,print it */
		    if (!dv_const.nodisplay)
		    {
			if (j != prev_j || i != prev_i)
			move (i, j);
			if (attr == 0xf)
			standout ();
			else
			standend ();
		    }

		    for (k = j + 1; k < numcols && (hhi[m][k] == attr) && (htx[m][k] != dtx[i][k]); k++)
		    {
			dhi[i][k] = attr;	/* update screen */
			dtx[i][k] = htx[m][k];
		    }
		    tchar = dtx[i][k];
		    dtx[i][k] = 0;
		    if (!dv_const.nodisplay)
		    {
			addstr (&dtx[i][j]);
		    }
		    dtx[i][k] = tchar;
		    prev_i = i;
		    prev_j = k;
		    j = k - 1;
		}
	    }
	}
	if (!dv_const.nodisplay)
	{
	    standend ();
	    move (sv_const.curline, sv_const.curclm);
	    refresh ();
	}
    }
#endif

#if (WIN32)
    static CHAR_INFO vbuf[DSP_COLS_MAX*DSP_LINES_MAX],*gp; 
    COORD coordDest,coordBufSize;
    SMALL_RECT sr;
    int m,
     i,
     j;

    if ((!dv_var) || (dv_var->devindex == sv_const.viewdev))
    {
	gp = &vbuf[0];

	for (i = 0; i < sv_const.numlines; i++)
	{
	    if (i >= sv_const.cmdline)
		m = (DSP_LINES_MAX - 3) + (i - sv_const.cmdline);
#if 0
	    if (i >= sv_const.cmdline)
		m = i;
#endif
	    else
	    {
		m = hln + i;
		if (m >= sv_const.cmdline)
		    m -= sv_const.cmdline;
	    }

	    for (j = 0; j < sv_const.numcols; j++)
	    {
		gp->Char.AsciiChar = htx[m][j];
		gp->Attributes = (hhi[m][j] == 0xf)? BOLDATRB : NORMATRB;
		gp++;
	    }
	}
	gp = &vbuf[0];
	coordDest.X = 0;
	coordDest.Y = 0;
	coordBufSize.X = sv_const.numcols;
	coordBufSize.Y = sv_const.numlines;
	sr.Left = 0;
	sr.Top = 0;
	sr.Right = sv_const.numcols-1;
	sr.Bottom = sv_const.numlines-1; 
	WriteConsoleOutput(hConsole,gp,coordBufSize,coordDest,&sr);
    }
#endif
#if MSDOS&(!PC9801)&(!WIN32)
    static char vbuf[80*25];
    int m,
     i,
     j;
    char *gp;

    if ((!dv_var) || (dv_var->devindex == sv_const.viewdev))
    {
	if (dv_const.nodisplay)
	{
	    gp = &vbuf[0];
	}
	else
	{
	    gp = (char *) (TXTRAM);
	}
	for (i = 0; i < 24; i++)
	{
	    if (i >= sv_const.cmdline)
		m = i;
	    else
	    {
		m = hln + i;
		if (m >= sv_const.cmdline)
		    m -= sv_const.cmdline;
	    }

	    for (j = 0; j < 80; j++)
	    {
		*gp++ = htx[m][j];
		*gp++ = hhi[m][j];	/* update screen */
	    }
	}
    }
#endif
#if PC9801
    int i,
     j,
     m;
    short *txtadr,
    *atradr;

    if ((!dv_var) || (dv_var->devindex == sv_const.viewdev))
    {
	txtadr = (short *) (TXTRAM);
	atradr = (short *) (ATTRAM);
	for (i = 0; i < 24; i++)
	{
	    if (i >= sv_const.cmdline)
		m = i;
	    else
	    {
		m = hln + i;
		if (m >= sv_const.cmdline)
		    m -= sv_const.cmdline;
	    }

	    for (j = 0; j < 80; j++)
	    {
		*txtadr++ = htx[m][j];
		*atradr++ = (hhi[m][j] == 0xf) ? boldattr : NORMATRB;
	    }
	}
    }
#endif
#if macintosh
    int i,
     j,
     prev_i,
     prev_j,
     m,
     k;
    char attr;
    Point pt;
    Rect rect;
    PenState ps;
    GrafPtr saveport;

    if ((!dv_var) || (dv_var->devindex == sv_const.viewdev))
    {

	GetPort (&saveport);
	SetPort (myWindow);

	prev_i = prev_j = -1;
	MoveTo (1, font_points + 20);
	GetPenState (&ps);
	pt.h = ps.pnLoc.h;
	pt.v = ps.pnLoc.v;

	for (i = 0; i < 24; i++)
	{
	    if (i >= sv_const.cmdline)
		m = i;
	    else
	    {
		m = hln + i;
		if (m >= sv_const.cmdline)
		    m -= sv_const.cmdline;
	    }
	    for (j = 0; j < 80; j++)
	    {
		if (htx[m][j] != dtx[i][j] || hhi[m][j] != dhi[i][j])
		{
		    dhi[i][j] = attr = hhi[m][j];	/* update screen */
		    dtx[i][j] = htx[m][j];

		    /* move cursor to line i, column j,print it */
		    if (j != prev_j || i != prev_i)
			MoveTo (j * cw + 1, i * ch + font_points + 20);

		    for (k = j + 1; k < 80 && (hhi[m][k] == attr) && (htx[m][k] != dtx[i][k]); k++)
		    {
			dhi[i][k] = attr;	/* update screen */
			dtx[i][k] = htx[m][k];
		    }
		    DrawText (&dtx[i][j], 0, k - j);
		    prev_i = i;
		    prev_j = k;

		    if (attr == 0xf)
		    {
			SetRect (&rect, pt.h + (j * cw), pt.v - sf.ascent, pt.h + (k * cw), pt.v + sf.descent);
			InvertRect (&rect);
		    }
		    j = k - 1;
		}
	    }
	    pt.v += ch;
	}

	SetPort (saveport);
    }
#endif

    sv_const.scrnest = 0;
}

/*
   * simw_scrnest --- increase screen buffer counter
   *
   * This function helps implement a nested screen buffering scheme.     
 */

void
simw_scrnest (void)

{
    sv_const.scrnest++;
}

/*
   * simw_unnest --- decrease screen buffering counter one level    
   *
   * This function and sim_scrnest implement the nested screen buffering.
   * It decreases the buffering one level and calls sim_refresh if
   * the level is less than 1 ( after the decrement).
 */

void
simw_unnest (void)

{
    if (sv_const.scrnest <= 1)
	simw_refresh ();
    else
	sv_const.scrnest--;
}

/*
   * simw_endwin --- reset all the window parameters
   *
   * This function is normally called by the simulator when returning to  
   * the operating system level - either at the end of the simulation - or
   * in response to a SYSTEM command.  It clears any special terminal processing
   * that has been set up by the simulator and clears the screen.
 */

void
simw_endwin (void)

{
#if MSDOS||macintosh
    scr_erase ();
#if WIN32
    SetConsoleActiveScreenBuffer(hStdOut_saved);
    SetConsoleMode(hStdIn,hStdIn_dwMode);
    SetConsoleMode(hStdOut,hStdOut_dwMode);
#endif
#endif
#if PC9801
    cprintf ("%2s>1l", esc);	/*enable function key */
#endif
#if UNIX
    scr_erase ();
    if (!dv_const.nodisplay)
    {
	endwin ();
	(void) resetty ();
    }
#endif
}
#if macintosh
char *
siml_macfile ()
{
    return (macstring);
}
static
macwrefresh ()
{
    int line,
     tl,
     i,
     j,
     k;
    char attr;
    GrafPtr saveport;
    Point pt;
    Rect rect;
    PenState ps;
    struct sev_var *sv = sv_var;

    sv_var = sv_const.sv[sv_const.viewdev];
    GetPort (&saveport);
    SetPort (myWindow);
    BeginUpdate (myWindow);
    DrawControls (myWindow);

    for (i = 0; i < 24; i++)
    {
	/* move cursor to line i, column j,print it */
	MoveTo (1, i * ch + font_points + 20);
	DrawText (&dtx[i][0], 0, 80);
    }

    /* now go back and do the hilites */
    MoveTo (1, font_points + 20);
    GetPenState (&ps);
    pt.h = ps.pnLoc.h;
    pt.v = ps.pnLoc.v;

    for (i = 0; i < 24; i++)
    {
	for (j = 0; j < 80; j++)
	{
	    attr = dhi[i][j];	/* update screen */
	    if (attr == 0xf)
	    {
		for (k = j + 1; k < 80 && (dhi[i][k] == 0xf); k++);	/* find block to hilite */
		SetRect (&rect, pt.h + (j * cw), pt.v - sf.ascent, pt.h + (k * cw), pt.v + sf.descent);
		InvertRect (&rect);
		j = k;
	    }
	}
	pt.v += ch;
    }
    MoveTo (sv_const.curclm * cw + 1, sv_const.curline * ch + font_points + 20);
    draw_cursor ();
    EndUpdate (myWindow);
    SetPort (saveport);
    sv_var = sv;
}

static
int 
kbhit ()
{
    otherevents ();
    EventAvail (keyDownMask + autoKeyMask, &myEvent);	/* get event */
    return (myEvent.what);
}
static
setupmenu ()
{
    int i;
    const char helptop0[] =
		"Execute Macro File;Load .lod Object File;Load .cld Object File;Load State File;Quit/Q";

    const char helptop1[] =
    "asm;break;change;copy;device;disassemble;display;evaluate;go;help;history";
    const char helptop2[] =
    "input;list;load;log;next;output;path;quit;radix;reset;save;step;system;trace;until;view;wait";
    const char cmdtop1[] =
    "asm;break;device;disassemble;display;go;help;history;input;list;log;next;output;path;quit";
    const char cmdtop2[] =
    "radix;step;trace;view;wait";

    myMenus[0] = NewMenu (appleMenu, "\p\024");
    AddResMenu (myMenus[0], 'DRVR');
    myMenus[1] = NewMenu (fileMenu, "\pFile");
    appendmenu (myMenus[1], helptop0);
    myMenus[2] = NewMenu (helpMenu, "\pHelp");
    appendmenu (myMenus[2], helptop1);
    appendmenu (myMenus[2], helptop2);
    myMenus[3] = NewMenu (cmdMenu, "\pCommands");
    appendmenu (myMenus[3], cmdtop1);
    appendmenu (myMenus[3], cmdtop2);
    myMenus[4] = NewMenu (prevMenu, "\pHistory");
    appendmenu (myMenus[4], cmdtop1);
    appendmenu (myMenus[4], cmdtop2);
    for (i = 0; i < NMENUS; i++)
	InsertMenu (myMenus[i], 0);
    DrawMenuBar ();
}
pascal Boolean 
lodfilter (pb)
CInfoPBPtr pb;
{
    short rv;
    int len;
    char *cp;
    OSType filetype;

    rv = TRUE;
    cp = p2cstr (pb->hFileInfo.ioNamePtr);
    if ((len = strlen (cp)) > 4 && !strcmp (&cp[len - 4], macstring))
	rv = FALSE;
    c2pstr (cp);

    return (rv);
}

static
docommand (mResult)
long mResult;
{
    int theItem,
     theMenu;
    char name[256];
    char *cp;
    StandardFileReply freply;
    int key = 0;
    char fname2[256];
    CInfoPBRec cb;
    OSErr operr;
    static char *opstr[] =
    {"", "load ", "load ", "load s "};
    static char *flsufx[] =
    {".cmd", ".lod", ".cld", ".sim"};

    typeList[0] = 'TEXT';
    typeList[1] = 'UNKN';
    typeList[2] = 'COFF';
    theMenu = mResult >> 16;
    theItem = mResult & 0xffff;
    switch (theMenu)
    {
    case appleMenu:
	getmenuitemtext (myMenus[0], theItem, name);
	opendeskacc (name);
	break;
    case fileMenu:
	switch (theItem)
	{
	case 1:		/*macro file */
	case 2:		/*load .lod obj */
	case 3:		/*load .cld obj */
	case 4:		/*load state */
	    (void) strcpy (macstring, flsufx[theItem - 1]);
	    StandardGetFile ((FileFilterProcPtr) lodfilter, 3, typeList, &freply);
	    if (freply.sfGood)
	    {
		key = DSP_MACFILE;
		cp =  p2cstr (&freply.sfFile.name[0]);
		(void) strcpy (macstring, cp );
		c2pstr (cp);
		cb.dirInfo.ioNamePtr = (StringPtr) & freply.sfFile.name[0];
		cb.dirInfo.ioVRefNum = freply.sfFile.vRefNum;
		cb.dirInfo.ioDrParID = freply.sfFile.parID;
		do
		{
		    cb.dirInfo.ioFDirIndex = FIGNORENAME;
		    cb.dirInfo.ioDrDirID = cb.dirInfo.ioDrParID;
		    operr = PBGetCatInfo (&cb, FALSE);
		    (void) strcpy (fname2, macstring);
		    cp = p2cstr (&freply.sfFile.name[0]);	/* convert from p string to c string */
		    (void) sprintf (macstring, "%s:%s", cp, fname2);	/* insert parent directory */
		    c2pstr (cp);	/* convert back to c string */
		}
		while (operr == 0 && cb.dirInfo.ioDrDirID != ROOTDIRID);
		(void) strcpy (fname2, macstring);
		(void) sprintf (macstring, "%s\"%s\"", opstr[theItem - 1], fname2);
	    }
	    break;
	case 5:
	    exit (0);
	}
	break;
    case helpMenu:
	(void) strcpy (macstring, "help ");
	getmenuitemtext (myMenus[2], theItem, fname2);
	(void) strcat (macstring, fname2);
	key = DSP_MACFILE;
	break;
    case cmdMenu:
	getmenuitemtext (myMenus[3], theItem, macstring);
	key = DSP_MACFILE;
	break;
    case prevMenu:
	getmenuitemtext (myMenus[4], theItem, macstring);
	key = DSP_MACFILE;
	break;
    }
    HiliteMenu (0);
    return (key);
}
siml_stackcmd (cmd)		/* replace command string in prevMenu */
char *cmd;
{
    char cmdstr[256];
    int i,
     j;

    strcpy (cmdstr, cmd);
    /* check if command is already in list */
    for (i = 1; i < 17; i++)
    {
	getmenuitemtext (myMenus[4], i, macstring);
	if (!strcmp (macstring, cmdstr))
	    break;
    }
    /* push down stack */
    for (; i > 1; i--)
    {
	if (i < 17)
	{
	    getmenuitemtext (myMenus[4], i - 1, macstring);
	    setmenuitemtext (myMenus[4], i, macstring);
	}
    }
    /* add new command on stack */
    setmenuitemtext (myMenus[4], 1, cmdstr);
}

#endif
int 
simw_ctrlbr (void)		/* check for CTRLC signal */

{
#if (MSDOS||macintosh)&(!WIN32)
    if (kbhit ())
	(void) simw_gkey ();
#endif
    if (dv_const.CTRLBR)
    {
	dv_const.sv[sv_const.breakdev]->CTRLBR = 1;
	dv_const.CTRLBR = 0;
    }
#if UNIX
    if (!dv_const.nodisplay)
    {
	if (dv_var->CTRLBR)
	clearok (curscr, TRUE);
    }
#endif

    return (dv_var->CTRLBR);
}

#if macintosh
static
redraw_ctl ()
{
    int y,
     sbar;
    GrafPtr saveport;

    GetPort (&saveport);
    SetPort (myWindow);

    sbar = (sv_const.winsz - sv_const.cmdline);
    if (!sv_var->db.max_pos)
	sv_var->db.max_pos = 1;
    y = ((double) sv_var->db.current_pos / (double) sv_var->db.max_pos) * sbar;
    if (y > sbar)
	y = sbar;
    else if (y < 0)
	y = 0;
    SetCtlValue (scrollbar, y);
    SetPort (saveport);
}

simw_macstartup ()
{
    char fname1[256];
    char fname2[256];
    char *cp;
    int iFile;
    short message,
     count;
    CInfoPBRec cb;
    OSErr operr;

    CountAppFiles (&message, &count);

    for (iFile = 1; iFile <= count; iFile++)
    {
	AppFile theFile;

	GetAppFiles (iFile, &theFile);	/* get info on file # iFile */

	if (theFile.fType == 'TEXT')	/* skip unless file is of type TEXT */
	{
	    ClrAppFiles (iFile);	/* mark this one as done/processed/etc. */

	    cp = p2cstr (&theFile.fName[0]);
	    (void) strcpy (fname1, cp );
	    
	    c2pstr (cp);
	    cb.dirInfo.ioNamePtr = (StringPtr) & theFile.fName;
	    cb.dirInfo.ioVRefNum = theFile.vRefNum;
	    cb.dirInfo.ioDrParID = 0L;
	    do
	    {
		cb.dirInfo.ioFDirIndex = FIGNORENAME;
		cb.dirInfo.ioDrDirID = cb.dirInfo.ioDrParID;
		operr = PBGetCatInfo (&cb, FALSE);
		(void) strcpy (fname2, fname1);
		cp = p2cstr (&theFile.fName[0]);	/* convert from p string to c string */
		(void) sprintf (fname1, "%s:%s", cp, fname2);	/* insert parent directory */
		c2pstr (cp);	/* convert back to c string */
	    }
	    while (operr == 0 && cb.dirInfo.ioDrDirID != ROOTDIRID);

	    (void) strcpy (fname2, fname1);
	    (void) sprintf (fname1, "\"%s\"", fname2);
	    sim_docmd (0, fname1);
	    break;		/* (optional) exit loop -- process first (TEXT) file only */
	}
    }
}
#endif


/* Paints screen lines 0 to sv_const.numlines-3 with strings in bp */
/*ARGSUSED */
void
simw_paint_screen (char *bp)

{
    int line,
     numcols;
    char *linep;

    sv_const.scrnest++;

    hln = 0;
#if macintosh
    redraw_ctl ();
#endif
    linep = bp;
    numcols = sv_const.numcols;
    for (line = 0; line < sv_const.cmdline; line++)
    {

	/* Move cursor to the specified line and column */
	strncpy (&htx[line][0], linep, numcols);
	(void) memset ((char *) &hhi[line][0], 7, numcols);
	linep += DSP_COLS_MAX + 1;
    }

    simw_unnest ();
}

static int
kbdhit (void)
{
#if MSDOS && !PC9801
    int key;

    if (kbhit ())
    {
	key = getch ();
    }
    
    else
    {
	key = 0;
    }
    
    return (key & 0xff);
#endif

#if UNIX
    int flag;
    int key;

    if (!dv_const.nodisplay)
    {
	flag = fcntl (0, F_GETFL, 0);
	flag |= O_NDELAY;
	fcntl (0, F_SETFL, flag);
	key = getch ();
	flag = fcntl (0, F_GETFL, 0);
	fcntl (0, F_SETFL, (flag ^ O_NDELAY));
    }
    else
    {
	key = 0;
    }

    if (key == -1)
    {
	return (0);
    }
    else
    {
	return (key & 0xff);
    }
    
#endif

}

#if macintosh
/*
 *	The following four functions provide the UI for the console package.
 *	Users wishing to replace SIOUX with their own console package need
 *	only provide the four functions below in a library.
 */

/*
 *	extern short InstallConsole(short fd);
 *
 *	Installs the Console package, this function will be called right
 *	before any read or write to one of the standard streams.
 *
 *	short fd:		The stream which we are reading/writing to/from.
 *	returns short:	0 no error occurred, anything else error.
 */

short InstallConsole(short fd)
{
#pragma unused (fd)

	return 0;
}

/*
 *	extern void RemoveConsole(void);
 *
 *	Removes the console package.  It is called after all other streams
 *	are closed and exit functions (installed by either atexit or _atexit)
 *	have been called.  Since there is no way to recover from an error,
 *	this function doesn't need to return any.
 */

void RemoveConsole(void)
{
}

/*
 *	extern long WriteCharsToConsole(char *buffer, long n);
 *
 *	Writes a stream of output to the Console window.  This function is
 *	called by write.
 *
 *	char *buffer:	Pointer to the buffer to be written.
 *	long n:			The length of the buffer to be written.
 *	returns short:	Actual number of characters written to the stream,
 *					-1 if an error occurred.
 */

long WriteCharsToConsole(char *buffer, long n)
{
#pragma unused (buffer, n)

	return 0;
}

/*
 *	extern long ReadCharsFromConsole(char *buffer, long n);
 *
 *	Reads from the Console into a buffer.  This function is called by
 *	read.
 *
 *	char *buffer:	Pointer to the buffer which will recieve the input.
 *	long n:			The maximum amount of characters to be read (size of
 *					buffer).
 *	returns short:	Actual number of characters read from the stream,
 *					-1 if an error occurred.
 */

long ReadCharsFromConsole(char *buffer, long n)
{
#pragma unused (buffer, n)

	return 0;
}

/*
 *	return the name of the current terminal ...
 */
char *__ttyname(long fildes)
{
#pragma unused (fildes)

	static char *__devicename = "null device";
	
	return (__devicename);
}
/* for source debug, redraw the controls based on the db.current_pos
   db.max_pos values in sv_var */

#endif




