Source file: /~heha/hsn/borg.zip/DISIO.CPP

/************************************************************************
*		 disio.cpp						*
* This is a fairly big class, and yet it was originally part of the	*
* larger disasm class. I finally got around to splitting off some of	*
* 3500 lines of code from that class into here. This represents the	*
* disasm I/O functions for window I/O and file I/O. Version 2.11 was	*
* when this was split. There are still a huge number of confusing	*
* functions and code in here which probably needs more work to clean it *
* up, and better split/define the classes. Some of the functions are	*
* friends of disasm because it has been difficult to split the classes	*
* effectively and both access the complex main disassembly structures	*
************************************************************************/

#include <windows.h>
#include <stdio.h>	      // for sprintf, for float printing

#include "disio.h"
#include "disasm.h"
#include "data.h"
#include "dasm.h"
#include "schedule.h"
#include "gname.h"
#include "xref.h"
#include "range.h"
#include "debug.h"

/************************************************************************
* globals								*
* - actually some constants used in file i/o as a header		*
************************************************************************/
char hdr[] =";\t      Created by Borg Disassembler\r\n";
char hdr2[]=";\t      written by Cronos + h#s\r\n";
disio *cvd;	// pointer to data of focused view

/************************************************************************
* constructor function							*
* - this just enables window updates and sets the subline to null	*
* - the subline (subitem) is basically the line in the disassembly that *
*   you see for any given loc. As a loc may refer to many lines (like	*
*   segheader, comments, xref, actual instruction are all separate	*
*   line, and subline says which of these it is)			*
************************************************************************/
disio::disio(HWND w) {
 wnd=w;
 subitem=dsmnull;
// bufferbusy=false;   
}

/************************************************************************
* destructor function							*
* - currently null							*
* - note that disio has no particular structs the same way most of the	*
*   other classes in Borg do						*
************************************************************************/
disio::~disio()
{
}

/************************************************************************
* argoverdec								*
* - disio also acts as a go between for the user and the disasm engine	*
* - here we translate the users current line of the disassembly and	*
*   their request for a decimal override into a call to the disasm	*
*   engine to add the override to the instruction that is there		*
* - note that these kind of calls come from the scheduler and are part	*
*   of the secondary thread						*
************************************************************************/
void disio::argoverdec(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  dsm->disargoverdec(outhere);
}

/************************************************************************
* argoversingle								*
* - very similar to argoverdec, for a single (float) override		*
************************************************************************/
void disio::argoversingle(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  dsm->disargoversingle(outhere);
}

/************************************************************************
* argovernegate								*
* - very similar to argoverdec, for an argument negation override	*
************************************************************************/
void disio::arg_negate(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  dsm->disargnegate(outhere);
}

/************************************************************************
* argoverhex								*
* - very similar to argoverdec, for a hex override			*
************************************************************************/
void disio::argoverhex(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  dsm->disargoverhex(outhere);
}

/************************************************************************
* argoveroffsetdseg							*
* - very similar to argoverdec, for a dseg override			*
************************************************************************/
void disio::argoveroffsetdseg(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  dsm->disargoveroffsetdseg(outhere);
}

/************************************************************************
* argoverchar								*
* - very similar to argoverdec, for a char override			*
************************************************************************/
void disio::argoverchar(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  dsm->disargoverchar(outhere);
}

/************************************************************************
* makedword								*
* - disio acts as a go between for the user and the disasm engine	*
* - here we translate the users current line of the disassembly and	*
*   their request for a dword into a call to the disasm engine to	*
*   disassemble a dword at the current point				*
* - note that these kind of calls come from the scheduler and are part	*
*   of the secondary thread						*
************************************************************************/
void disio::makedword(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatadword(outhere);
}

/************************************************************************
* makesingle								*
* - very similar to makedword, this time to disassemble a single	*
*   (float)								*
************************************************************************/
void disio::makesingle(void) {
 lptr outhere;
 findcurrentaddr(&outhere);
 if (outhere==curraddr) subitem=dsmnull;
 dsm->disdatasingle(outhere);
}

/************************************************************************
* makedouble								*
* - very similar to makedword, this time to disassemble a double	*
*   (double float)							*
************************************************************************/
void disio::makedouble(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatadouble(outhere);
}

/************************************************************************
* makelongdouble							*
* - very similar to makedword, this time to disassemble a long double	*
*   (long double)							*
************************************************************************/
void disio::makelongdouble(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatalongdouble(outhere);
}

/************************************************************************
* makeword								*
* - very similar to makedword, this time to disassemble a word		*
************************************************************************/
void disio::makeword(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdataword(outhere);
}

/************************************************************************
* makestring								*
* - very similar to makedword, this time to disassemble a string	*
*   (standard C string)							*
************************************************************************/
void disio::makestring(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatastring(outhere);
}

/************************************************************************
* pascalstring								*
* - very similar to makedword, this time to disassemble a string	*
*   (standard pascal string)						*
************************************************************************/
void disio::pascalstring(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatapstring(outhere);
}

/************************************************************************
* ucstring								*
* - very similar to makedword, this time to disassemble a string	*
*   (unicode C string)							*
************************************************************************/
void disio::ucstring(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdataucstring(outhere);
}

/************************************************************************
* upstring								*
* - very similar to makedword, this time to disassemble a string	*
*   (unicode pascal string)						*
************************************************************************/
void disio::upstring(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdataupstring(outhere);
}

/************************************************************************
* dosstring								*
* - very similar to makedword, this time to disassemble a string	*
*   (dos style string)							*
************************************************************************/
void disio::dosstring(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatadosstring(outhere);
}

/************************************************************************
* generalstring								*
* - very similar to makedword, this time to disassemble a string	*
*   (general string)							*
************************************************************************/
void disio::generalstring(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disdatageneralstring(outhere);
}

/************************************************************************
* makecode								*
* - very similar to makedword, but this time to disassemble as code	*
*   from the current location, and continue disassembling		*
************************************************************************/
void disio::makecode(void)
{ lptr outhere;
  findcurrentaddr(&outhere);
  if(outhere==curraddr)
    subitem=dsmnull;
  dsm->disblock(outhere);
}

/************************************************************************
* vertsetpos								*
* - this function takes a position of the vertical scroll bar, from 0	*
*   to the VERTSCROLLRANGE and it sets the current address to that	*
*   point								*
************************************************************************/
void disio::vertsetpos(int pos) {
 unsigned long location;
#ifdef WIN32
 location=(unsigned)MulDiv(pos,(int)total_data_size,VERTSCROLLRANGE);
#else
 location=(unsigned long)((float)pos/VERTSCROLLRANGE*total_data_size);
#endif
 setcuraddr(dta->getlocpos(location));	// linear to seg:ofs
}

// reverse function, sets scroll bar to seg:ofs given
// Vertical scroll bar has no PAGESIZE feedback yet
void disio::setscrollpos(lptr loc) {
 DWORD current_data_pos=dta->datagetpos(loc);	// seg:ofs to linear
#ifdef WIN32
 int sbarpos=MulDiv((int)current_data_pos,VERTSCROLLRANGE,(int)total_data_size+1);
#else
 int sbarpos=(int)((float)current_data_pos/(total_data_size+1)*VERTSCROLLRANGE;
#endif
 SetScrollPos(wnd,SB_VERT,sbarpos,true);
}

/************************************************************************
* setcuraddr								*
* - sets the address as a location for the screen output to start at	*
* - also sets the scroll bar position for the vertical scroll bar	*
* - also ensures that its not set to a mid-instruction address and	*
*   sets the subline							*
* - called from many places in the source code				*
************************************************************************/
void disio::setcuraddr(lptr loc) {
 dsmitem titem,*tblock;
 dsegitem *l_ds;
  // check for non-existant address added v2.20
 l_ds=dta->findseg(loc);
 if (!l_ds) return;
 curraddr=loc;		// set top line address
 titem.addr=curraddr;
 titem.type=dsmnull;
 dsm->findnext(&titem);
 tblock=dsm->nextiterator();
 if (tblock) subitem=tblock->type;
 else subitem=dsmnull;
 tblock=dsm->nextiter_code(tblock);
 if (tblock && loc.between(tblock->addr,tblock->addr+tblock->length-1))
   curraddr=tblock->addr;
 outend=loc+50;
 sel=0;
 updatewindow();
 setscrollpos(loc);
}

// calculates the rectangle for item at line <item> using CharBox.y
void disio::GetItemRect(int item, PRECT R) {
 GetClientRect(wnd,R);
 R->top=item*CharBox.y;
 R->bottom=R->top+CharBox.y;
}

/************************************************************************
* setpos								*
* - when the left mouse button is pressed the line is changed to the	*
*   line the mouse points at. This routine sets the line, and asks for	*
*   a screen update if needed (the screen update method here is a	*
*   primary thread request that simply invalidates the window rather	*
*   than requesting through the scheduler...				*
************************************************************************/
void disio::setpos(int ypos) {
 if (ypos!=sel) {
  RECT R;
  GetItemRect(sel,&R);
  sel=ypos;
  InvalidateRect(wnd,&R,TRUE);	// let remove marker
  GetItemRect(sel,&R);
  InvalidateRect(wnd,&R,TRUE);	// let set marker
 }
}

/************************************************************************
* printlineheader							*
* - prints an appropriate line header with the address if needed and	*
*   sets the cursor position for the next LastPrintBuff call		*
************************************************************************/
void disio::printlineheader(lptr loc,bool printaddrs) {
 if (options.mode32) {
  if (printaddrs) PrintBuff(/*"%04lx:"*/"%08lx",/*loc.segm,*/loc.offs);
  else PrintBuff("");
  LastPrintBuffEpos(BYTEPOS-5);
 }else{
  if (printaddrs) PrintBuff("%04lx:%04lx",loc.segm,loc.offs);
  else PrintBuff("");
  LastPrintBuffEpos(BYTEPOS-4);
 }
}

/************************************************************************
* outinst								*
* - this is the routine which results in the output of an address, hex	*
*   bytes, instruction and arguments					*
************************************************************************/
void disio::outinst(dsmitem *inst,bool printaddrs) {
 dsegitem *dblock;
 int i;
 int prefixptr;
 byte pbyte;
 printlineheader(inst->addr,printaddrs);
 dblock=dta->findseg(inst->addr);      // find segment item.
 switch (inst->type) {
  case dsmcode: {
   i=inst->length;
   if (printaddrs) {
    while (i) {
     if (dblock) {
      if (dblock->typ==uninitdata) LastPrintBuff("??");
      else LastPrintBuff("%02x",inst->data[inst->length-i]);
     }else LastPrintBuff("%02x",inst->data[inst->length-i]);
     i--;
     if (i+8<inst->length && inst->length>10) {
      LastPrintBuff("..");
      break;
     }
    }
   }
   if (options.mode32) LastPrintBuffEpos(ASMPOS+4);
   else	LastPrintBuffEpos(ASMPOS);
   if (inst->flags&FLAGS_PREFIX) {
    prefixptr=0;
    while (!isprefix(inst->data[prefixptr]) && prefixptr<15) prefixptr++;
    pbyte=inst->data[prefixptr];
    outprefix(pbyte);
   }
   LastPrintBuff(DSMITEM_NAME(inst));
   LastPrintBuff(" ");
   if (options.mode32) LastPrintBuffEpos(ARGPOS+4);
   else	LastPrintBuffEpos(ARGPOS);
   if (dblock) {
    if (dblock->typ==uninitdata) LastPrintBuff("?");
    else{
     outargs(inst,DSMITEM_ARG1(inst));
     if (DSMITEM_ARG2(inst)!=ARG_NONE) {
      LastPrintBuff(", ");
      outargs(inst,DSMITEM_ARG2(inst));
     }
     if (DSMITEM_ARG3(inst)!=ARG_NONE) {
      LastPrintBuff(", ");
      outargs(inst,DSMITEM_ARG3(inst));
     }
    }
   }else{
    outargs(inst,DSMITEM_ARG1(inst));
    if (DSMITEM_ARG2(inst)!=ARG_NONE) {
     LastPrintBuff(", ");
     outargs(inst,DSMITEM_ARG2(inst));
    }
    if (DSMITEM_ARG3(inst)!=ARG_NONE) {
     LastPrintBuff(", ");
     outargs(inst,DSMITEM_ARG3(inst));
    }
   }
  }break;
 }
}

/************************************************************************
* outdb									*
* - this is similar to outinst, but when there is no disassembly for a	*
*   loc we call this to output a db xxh or a db ? if its uninitdata    *
************************************************************************/
void disio::outdb(lptr *lp,bool printaddrs) {
 dsegitem *dblock;
 dword aaddr;
 byte *mcode;
 printlineheader(*lp,printaddrs);
 dblock=dta->findseg(*lp);	// find segment item.
 if (!dblock) {
  if (printaddrs) LastPrintBuff("??");
 }else if (dblock->typ==uninitdata) {
  if (printaddrs) LastPrintBuff("??");
 }else{
  aaddr=(*lp-dblock->addr);
  mcode=dblock->data+aaddr;
  if (printaddrs) LastPrintBuff("%02x",mcode[0]);
 }
 if (options.mode32) LastPrintBuffEpos(ASMPOS+4);
 else LastPrintBuffEpos(ASMPOS);

 LastPrintBuff("db");

 if (options.mode32) LastPrintBuffEpos(ARGPOS+4);
 else LastPrintBuffEpos(ARGPOS);
  // changed to single ? - 2.25
 if (!dblock) LastPrintBuff("?");
 else if (dblock->typ==uninitdata) {
  LastPrintBuff("?");
 }else{
  LastPrintBuffHexValue(mcode[0]);
  if (isprint(mcode[0])) {
   LastPrintBuffEpos(COMMENTPOS);
   LastPrintBuff(";'%c'",mcode[0]);
  }
 }
}

/************************************************************************
* issegprefix								*
* - returns true if byte is a segment prefix valid value		*
************************************************************************/
bool disio::issegprefix(byte byt) {
 switch (byt) {
  case 0x2e:
  case 0x36:
  case 0x3e:
  case 0x26:
  case 0x64:
  case 0x65: return true;
 }
 return false;
}

/************************************************************************
* isprefix								*
* - returns true if byte is a prefix valid value (rep/repne/lock)	*
************************************************************************/
bool disio::isprefix(byte byt) {
 switch (byt) {
  case 0xf0:
  case 0xf2:
  case 0xf3: return true;
 }
 return false;
}

/************************************************************************
* outprefix								*
* - here we output a prefix segment override				*
************************************************************************/
void disio::outprefix(byte prefixbyte) {
 char *s;
 switch (prefixbyte) {
  case 0x2e: s="cs:";	break;
  case 0x36: s="ss:";	break;
  case 0x3e: s="ds:";	break;
  case 0x26: s="es:";	break;
  case 0x64: s="fs:";	break;
  case 0x65: s="gs:";	break;
  case 0xf0: s="lock ";	break;
  case 0xf2: s="repne ";break;
  case 0xf3: s="repe ";	break;
  default: s="err:";
 }
 LastPrintBuff(s);
}

/************************************************************************
* jumpback								*
* - when the user presses ESC, or selects jump back we get the last	*
*   address from the top of the address stack and call setcuraddr and	*
*   update the window and so the disassembly listing flicks back	*
************************************************************************/
void disio::jumpback(void) {
 if (!retstack.stacktop) return;
 setcuraddr(retstack.pop());
 sel=selstack[retstack.stacktop];
 if ((unsigned)sel>=(unsigned)size.y) sel=0;	// for invalid values
 updatewindow();
}

/************************************************************************
* jumpto								*
* - more complex than the jumpback is the jumpto. The complexity lies	*
*   in deciding where we are jumping to and what the arguments value is *
*   and if the location exists. Actually making the jump consists of	*
*   saving the current location to the address stack and then changing	*
*   the curraddr for output, and updating the window			*
* - most of this routine is a complex decipherment of a modrm address	*
*   to jump to								*
* NB I need to stick this in a function of its own at some point, as it *
* would be quite useful to just get an argument address in several	*
* places in the code							*
************************************************************************/
void disio::jumpto(bool arg1) {
 dsmitem *tblock;
 lptr outhere;
 byte *data;
 bool madejump;
 byte modrm,sib;
 word rm;
 tblock=findcurrentline();
 outhere.assign(0,0);
 if (tblock && tblock->type!=dsmcode) return;
 madejump=false;
 if (tblock) {
  if (arg1) {
   switch (DSMITEM_ARG1(tblock)) {
    case ARG_FADDR: {
     data=tblock->data+tblock->length;
     if (tblock->mode32) {
      data-=6;
      outhere.assign(((word *)(&data[4]))[0],((dword *)(&data[0]))[0]);
     }else{
      data-=4;
      outhere.assign(((word *)(&data[2]))[0],((word *)(&data[0]))[0]);
     }
     if (follow(outhere)) madejump=true;
    }break;
    case ARG_IMM32: {
     if (tblock->override!=over_dsoffset) break;
     data=tblock->data+tblock->length;
     data-=4;
     outhere.assign(options.dseg,((dword *)(&data[0]))[0]);
     if (follow(outhere)) madejump=true;
    }break;
    case ARG_MEMLOC: {
     data=tblock->data+tblock->length;
     if (options.mode32) {
      data-=4;
      outhere.assign(tblock->addr.segm,((dword *)data)[0]);
     }else{
      data-=2;
      outhere.assign(tblock->addr.segm,((word *)data)[0]);
     }
     if (follow(outhere)) madejump=true;
    }break;
    case ARG_IMM: {
     if (tblock->override!=over_dsoffset) break;
     if (options.mode32) {
      data=tblock->data+tblock->length;
      data-=4;
      outhere.assign(options.dseg,((dword *)(&data[0]))[0]);
      if (follow(outhere)) madejump=true;
     }
    }break;
    case ARG_RELIMM: {
     data=tblock->data+tblock->length;
     outhere=tblock->addr;
     if (tblock->mode32) {
      data-=4;
      outhere+=((dword *)data)[0]+tblock->length;
     }else{
      data-=2;
      outhere+=(word)(((word *)data)[0]+tblock->length);
     }
     if (follow(outhere)) madejump=true;
    }break;
    case ARG_RELIMM8: {
     data=tblock->data+tblock->length-1;
     outhere=tblock->addr;
     if (tblock->mode32) {
      if (data[0]&0x80) outhere+=(dword)(data[0]+0xffffff00+tblock->length);
      else		outhere+=(dword)(data[0]+tblock->length);
     }else{
      if (data[0]&0x80) outhere+=(word)(data[0]+0xff00+tblock->length);
      else		outhere+=(word)(data[0]+tblock->length);
     }
     if (follow(outhere)) madejump=true;
    }break;
    case ARG_MMXMODRM:
    case ARG_XMMMODRM:
    case ARG_MODRM_S:
    case ARG_MODRMM512:
    case ARG_MODRMQ:
    case ARG_MODRM_SREAL:
    case ARG_MODRM_PTR:
    case ARG_MODRM_WORD:
    case ARG_MODRM_SINT:
    case ARG_MODRM_EREAL:
    case ARG_MODRM_DREAL:
    case ARG_MODRM_WINT:
    case ARG_MODRM_LINT:
    case ARG_MODRM_BCD:
    case ARG_MODRM_FPTR:
    case ARG_MODRM: {
     data=tblock->data+tblock->modrm;
     rm=(byte)((data[0]&0xc0)>>6);
     modrm=(byte)(data[0]&0x07);
     switch (rm) {
      case 0: {
       if (options.mode32) {
        if (modrm==5) {
         outhere.assign(tblock->addr.segm,((dword *)(&data[1]))[0]);
        }else if (modrm==4) {	 // case 4=sib
 	 sib=data[1];
	 if ((sib&0x07)==5) { // disp32
	  outhere.assign(tblock->addr.segm,((dword *)(&data[2]))[0]);
	 }
        }
       }else{
        if (modrm==6) {
         outhere.assign(tblock->addr.segm,((word *)(&data[1]))[0]);
        }
       }
      }break;
      case 1: break;
      case 2: {
       if (options.mode32) {
        outhere.assign(tblock->addr.segm,((dword *)(&data[1]))[0]);
	if (modrm==4) {	    // case 4=sib
	 outhere.assign(tblock->addr.segm,((dword *)(&data[2]))[0]);
	}
       }else{
        outhere.assign(tblock->addr.segm,((word *)(&data[1]))[0]);
       }
      }break;
      case 3: break;
     }/*switch(rm)*/
     if (follow(outhere)) madejump=true;
    }break;
   }/*switch(DSM_ITEM...)*/
  }/*if(arg1)*/
  if (!madejump) {
   switch (DSMITEM_ARG2(tblock)) {
    case ARG_IMM32: {
     if (tblock->override!=over_dsoffset) break;
     data=tblock->data+tblock->length;
     data-=4;
     outhere.assign(options.dseg,((dword *)(&data[0]))[0]);
     follow(outhere);
    }break;
    case ARG_IMM: {
     if (tblock->override!=over_dsoffset) break;
     if (options.mode32) {
      data=tblock->data+tblock->length;
      data-=4;
      outhere.assign(options.dseg,((dword *)(&data[0]))[0]);
      follow(outhere);
     }
    }break;
    case ARG_MEMLOC: {
     data=tblock->data+tblock->length;
     if (options.mode32) {
      data-=4;
      outhere.assign(tblock->addr.segm,((dword *)data)[0]);
     }else{
      data-=2;
      outhere.assign(tblock->addr.segm,((word *)data)[0]);
     }
     follow(outhere);
    }break;
    case ARG_MMXMODRM:
    case ARG_XMMMODRM:
    case ARG_MODRM_S:
    case ARG_MODRMM512:
    case ARG_MODRMQ:
    case ARG_MODRM_SREAL:
    case ARG_MODRM_PTR:
    case ARG_MODRM_WORD:
    case ARG_MODRM_SINT:
    case ARG_MODRM_EREAL:
    case ARG_MODRM_DREAL:
    case ARG_MODRM_WINT:
    case ARG_MODRM_LINT:
    case ARG_MODRM_BCD:
    case ARG_MODRM_FPTR:
    case ARG_MODRM: {
     data=tblock->data+tblock->modrm;
     rm=(byte)((data[0]&0xc0)>>6);
     modrm=(byte)(data[0]&0x07);
     switch (rm) {
      case 0:
	      if(options.mode32)
	      { if(modrm==5)
		{ outhere.assign(tblock->addr.segm,((dword *)(&data[1]))[0]);
		}
		else if(modrm==4)	 // case 4=sib
		{ sib=data[1];
		  if((sib&0x07)==5) // disp32
		  { outhere.assign(tblock->addr.segm,((dword *)(&data[2]))[0]);
		  }
		}
	      }
	      else
	      { if(modrm==6)
		{ outhere.assign(tblock->addr.segm,((word *)(&data[1]))[0]);
		}
	      }
	      break;
      case 1:
	      break;
      case 2:
	      if(options.mode32)
	      { outhere.assign(tblock->addr.segm,((dword *)(&data[1]))[0]);
		if(modrm==4)	    // case 4=sib
		{ outhere.assign(tblock->addr.segm,((dword *)(&data[2]))[0]);
		}
	      }
	      else
	      { outhere.assign(tblock->addr.segm,((word *)(&data[1]))[0]);
	      }
	      break;
      case 3:
	      break;
     }/*switch(rm)*/
     follow(outhere);
    }break;
   }/*switch(DSMITEM...)*/
  }
 }
}

/************************************************************************
* findcurrentline							*
* - this routine finds the current screen address and output line in	*
*   the disassembly database and from there works out the disassembly	*
*   item on the currently selected line.				*
* - it is used by jumpto, when the user presses return to follow a jump *
* - comments added to the procedure, it is a useful one to follow and	*
*   see the strategy employed, which is a fairly common Borg strategy	*
************************************************************************/
dsmitem *disio::findcurrentline(void) {
 dsmitem titem,*tblock;
 lptr outhere;
 int i;
  // strategy
  // - use pointer to first item if available (so comments,etc included in list
  // - otherwise use address.
 titem.addr=curraddr;
 titem.type=subitem;
  // hunt for current addr and subitem
 tblock=dsm->find(&titem);
 if (tblock) tblock=dsm->nextiterator();
  // on overlap - reset the curraddr.
  // [on the spot error correction]
 if (tblock) {
  if(curraddr.between(tblock->addr,tblock->addr+tblock->length-1))
     curraddr.offs=tblock->addr.offs;
 }
  // ensure we point to the right item, or the next one
 if (tblock) {
  if((tblock->addr<curraddr)||((tblock->addr==curraddr)&&(tblock->type<subitem)))
      tblock=dsm->nextiterator();
 }
  // now at the top of the screen, the next loop moves down to the user selection line
 outhere=curraddr;
 for (i=0;i<sel;i++) {
  if (tblock) {
   if (outhere==tblock->addr) {
    outhere+=tblock->length;
    tblock=dsm->nextiterator();
   }else outhere++;
  }else outhere++;
    // check if gone beyond seg, get next seg.
  if (dta->beyondseg(outhere)) {
   outhere.offs--;
   dta->nextseg(&outhere);
  }
  if (!outhere.segm) break;
 }
  // now we either have the line we are pointing to, in the database
  // or we have moved beyond the database and have a null
  // or we have an address which would be a db
 if (tblock && outhere!=tblock->addr) return NULL;
 return tblock;
}

/************************************************************************
* findcurrentaddr							*
* - this is very similar to findcurrentline, but it instead finds just	*
*   the location. the search strategy is the same			*
************************************************************************/
void disio::findcurrentaddr(lptr *loc) {
 dsmitem titem,*tblock;
 lptr outhere;
 int i;
  // strategy
  // - use pointer to first item if available (so comments,etc included in list
  // - otherwise use address.
 titem.addr=curraddr;
 titem.type=subitem;
 tblock=dsm->find(&titem);
 if (tblock) tblock=dsm->nextiterator();
 if (tblock && curraddr.between(tblock->addr,tblock->addr+tblock->length-1))
   curraddr.offs=tblock->addr.offs;
 if (tblock && tblock->addr<curraddr) tblock=dsm->nextiterator();
  // added 2.25 - bugfix
  // - wasnt finding correct lines when in mid-line......
 if (tblock) {
  while (tblock->addr==curraddr && tblock->type<subitem) {
   tblock=dsm->nextiterator();
   if (!tblock)	break;
  }
 }
 outhere=curraddr;
 for (i=0;i<sel;i++) {
  if (tblock && outhere==tblock->addr) {
   outhere+=tblock->length;
   tblock=dsm->nextiterator();
  }else outhere++;
    // check if gone beyond seg, get next seg.
  if (dta->beyondseg(outhere)) {
   outhere.offs--;
   dta->nextseg(&outhere);
  }
  if (!outhere.segm) break;
 }
 if (outhere.segm) *loc=outhere;
 else *loc=curraddr;
}

/************************************************************************
* findaddr								*
* Ich verstehe diesen Quelltext nicht, aber hier versuche ich eine
* Zeile im Bildschirm zu finden, die die angegebene Adresse enthält	*
************************************************************************/
int disio::findaddr(const lptr &loc) {
 dsmitem titem,*tblock;
 lptr outhere;
 int i;
  // strategy
  // - use pointer to first item if available (so comments,etc included in list
  // - otherwise use address.
 titem.addr=curraddr;
 titem.type=subitem;
 tblock=dsm->find(&titem);
 if (tblock) tblock=dsm->nextiterator();
 if (tblock && curraddr.between(tblock->addr,tblock->addr+tblock->length-1))
   curraddr.offs=tblock->addr.offs;
 if (tblock && tblock->addr<curraddr) tblock=dsm->nextiterator();
  // added 2.25 - bugfix
  // - wasnt finding correct lines when in mid-line......
 if (tblock) {
  while (tblock->addr==curraddr && tblock->type<subitem) {
   tblock=dsm->nextiterator();
   if (!tblock)	break;
  }
 }
 outhere=curraddr;
 for (i=0;i<size.y;i++) {
  if (tblock && outhere==tblock->addr) {
   outhere+=tblock->length;
   tblock=dsm->nextiterator();
  }else outhere++;
    // check if gone beyond seg, get next seg.
  if (dta->beyondseg(outhere)) {
   outhere.offs--;
   dta->nextseg(&outhere);
  }
  if (outhere==loc) return i+1;		// weiß nicht warum das +1 ...
  if (!outhere.segm) break;
 }
 return -1;
}

/************************************************************************
* savecuraddr								*
* - this simply saves the window top line location to the return stack	*
* - this is called when the user selects to jump somewhere (like to a	*
*   named location) rather than the 'jumpto' routine used to jump to a	*
*   location specified by a disassembly argument			*
************************************************************************/
void disio::savecuraddr(void) {
 if (retstack.stacktop==CALLSTACKSIZE) {
	// if stack is full, move down its content (damn, no STL)
  memmove(selstack,selstack+1,sizeof(selstack)-sizeof(selstack[0]));
 }
 retstack.push(curraddr);
 selstack[retstack.stacktop-1]=sel;
}

// same as ^F in Turbo Debugger
bool disio::follow(const lptr &loc) {
 if (!dta->findseg(loc)) return false;
 savecuraddr();
 int i=findaddr(loc);
 if (i>=0) sel=i;	// NICHT ROLLEN wenn im Bildschirm!!!
 else setcuraddr(loc);
 updatewindow();
 return true;
}

/************************************************************************
* updatewindowifwithinrange						*
* - adds a scheduler task for a window update if the current window	*
*   overlaps with the specified range					*
************************************************************************/
void disio::updatewindowifwithinrange(lptr loc_start,lptr loc_end) {
 if (loc_end>=curraddr && loc_start<=outend)
   scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
* updatewindowifinrange							*
* - adds a scheduler task for a window update if the current window	*
*   contains the loc specified						*
************************************************************************/
void disio::updatewindowifinrange(lptr loc) {
 if (loc.between(curraddr,outend))
   scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
* updatewindow								*
* - this function rewrites the buffers for the disassembly output to	*
*   the window, and then requests a screen refresh which will paint the *
*   buffers into the window. The ClearBuff and DoneBuff functions	*
*   when the buffers are full and it is safe to refresh the screen with *
*   a repaint								*
************************************************************************/
// this functions job to output a window
// of disassembly to the buffer.
void disio::updatewindow(void) {
 dsmitem titem,*tblock;
 lptr outhere;
 int i;
  // find current position.
 titem.addr=curraddr;
 titem.type=subitem;
 tblock=dsm->find(&titem);
 if (tblock) tblock=dsm->nextiterator();
  // now tblock= current position, or previous one.
  // check if in middle of instruction
 if (tblock) {
 // bugfix 2.27
  if (tblock->length>1 
  && curraddr.between(tblock->addr,tblock->addr+tblock->length-1)) {
   curraddr.offs=tblock->addr.offs;
   subitem=tblock->type;
  }
 }
  // check if previous one. get next
 if (tblock) {
  if (tblock->addr<curraddr
  || tblock->addr==curraddr && tblock->type<subitem)
    tblock=dsm->nextiterator();
 }
  // tblock is now top of the page.
 outhere=curraddr;
 ClearBuff();			      // start again
 for (i=0; i<size.y;i++) {
  if (tblock) {
   if (outhere==tblock->addr) {
    switch (tblock->type) {
     case dsmcode: {
      outinst(tblock,true);
     }break;
     case dsmnameloc: {
      printlineheader(tblock->addr,true);
      LastPrintBuff("%s:",tblock->data);
     }break;
     case dsmxref: {
      printlineheader(tblock->addr,true);
      LastPrintBuff(";");
      LastPrintBuffEpos(COMMENTPOS);
      LastPrintBuff("XREFS First: ");
      xrefs->printfirst(tblock->addr);
     }break;
     default: {
      printlineheader(tblock->addr,true);
      outcomment(tblock);
     }
    }
    outhere+=tblock->length;
    tblock=dsm->nextiterator();
   }else{
    outdb(&outhere,true);
    outhere++;
   }
  }else{
   outdb(&outhere,true);
   outhere++;
  }
    // check if gone beyond seg, get next seg.
  if (dta->beyondseg(outhere)) {
   outhere.offs--;
   dta->nextseg(&outhere);
  }
  if (!outhere.segm) break;
  else outend=outhere;
 }
 DoneBuff();			      // mark as done
 InvalidateRect(wnd,NULL,true);
}

/************************************************************************
* scroller								*
* - this routine controls simple vertical scrolls. A vertical scroll is *
*   a movement of the currently selected line. Only if this line moves	*
*   beyond the boundaries of the window do we need to move the windowed *
*   disassembly output itself. Simple moves are handled quickly, and if *
*   we need to regenerate the buffers then we first recalculate the top *
*   position and then we call windowupdate to handle the rest.		*
************************************************************************/
void disio::scroller(int amount) {
 dsmitem titem,*tblock;
 int newpos=sel+amount;
  // simple move bar on screen
 if ((unsigned)newpos<(unsigned)(size.y-1)) {
  setpos(newpos);
  return;
 }
  // find top of page
 titem.addr=curraddr;
 titem.type=subitem;
 tblock=dsm->find(&titem);
 // tblock is now top of page or previous item.
 // if moving up find previous inst
 if ((unsigned)amount<100 && tblock) tblock=dsm->nextiterator();
 if ((unsigned)amount>100 && tblock 
 && tblock->addr==titem.addr && tblock->type==subitem)
   tblock=dsm->lastiterator();
 // move up - tblock=previous inst.
 // if moving down, check if tblock=previous item.
 if (tblock && (unsigned)amount<100) {
  if (tblock->addr<curraddr
  || tblock->addr==curraddr && tblock->type<subitem)
    tblock=dsm->nextiterator();
 }
 // moving down - tblock=current top.
 if ((unsigned)amount<100) while (amount) {
  if (sel<=size.y-3) sel++;
  else{
   if (tblock) {
    if (curraddr==tblock->addr) {
     curraddr+=tblock->length;
     tblock=dsm->nextiterator();
     if (tblock && curraddr==tblock->addr) subitem=tblock->type;
     else subitem=dsmcode;
    }else{
     subitem=dsmnull;
     curraddr++;
    }
   }else{
    subitem=dsmnull;
    curraddr++;
   }
// check if gone beyond seg, get next seg.
   if (dta->beyondseg(curraddr)) {
    curraddr.offs--;
    dta->nextseg(&curraddr);
    subitem=dsmnull;
   }
   if (!curraddr.segm) break;
   titem.addr=curraddr;
  }
  amount--;
 }else{
  while (amount) {
   if (sel) sel--;
   else{
    if (tblock) {
     if (curraddr==tblock->addr+tblock->length) {
      curraddr.offs-=tblock->length;
      subitem=tblock->type;
      tblock=dsm->lastiterator();
     }else{
      subitem=dsmcode;
      curraddr.offs--;
     }
    }else{
     subitem=dsmnull;
     curraddr.offs--;
    }
// check if gone beyond seg, get previous seg.
    if (dta->beyondseg(curraddr)) {
     curraddr++;
     dta->lastseg(&curraddr);
    }
    if (!curraddr.segm) break;
    titem.addr=curraddr;
   }
   amount++;
  }
 }
 if (!curraddr.segm) curraddr=titem.addr;
 updatewindow();
 setscrollpos(curraddr);
//  current_data_pos=dta->datagetpos();
//  sbarpos=((float)current_data_pos)/((float)total_data_size+(float)1.0)*(float)VERTSCROLLRANGE;
//  SetScrollPos(MainWnd,SB_VERT,(int)sbarpos,true);
}

BOOL PrintFoundName(lptr loc) {
 if (name->isname(loc))		name->printname(loc);
 else if (import->isname(loc))	import->printname(loc);
 else if(expt->isname(loc))	expt->printname(loc);
 else return FALSE;
 return TRUE;
}

void PrintLongHex(lptr loc) {
 if (!PrintFoundName(loc)) cvd->LastPrintBuffLongHexValue(loc.offs);
}

void PrintOffset(lptr loc) {
 cvd->LastPrintBuff("offset ");
 PrintLongHex(loc);
}

void PrintMemVar(lptr loc) {
 cvd->LastPrintBuff("[");
 PrintLongHex(loc);
 cvd->LastPrintBuff("]");
}

/************************************************************************
* outargs								*
* - this is a very long routine which handles every kind of argument	*
*   that we have set up in the processor tables. It outputs the ascii	*
*   form of the instructions arguments to the buffer. It handles	*
*   complex modrm and sib encodings, the display of names and locations *
*   which must be decoded, etc.						*
************************************************************************/
void disio::outargs(dsmitem *inst,argtype a) {
 byte *dta,modrm,sib;
  // rm extended to word. build 15. re M Ogden and VC++ warnings.
 word rm;
 argtype a1,a2;
 dword targetd;
 dword targetw;
 lptr loc;
 char fbuff[40];
 int i,sp;	      // sp= string printed
 byte pbyte; // prefix byte.
 int prefixptr;
 if(inst->flags&FLAGS_SEGPREFIX) {
  prefixptr=0;
  while (!issegprefix(inst->data[prefixptr]) && prefixptr<15)
    prefixptr++;
  pbyte=inst->data[prefixptr];
 }
 if (inst->flags&FLAGS_ADDRPREFIX) options.mode32=!options.mode32;
 switch (a) {
  case ARG_REG_AX: {
   if (inst->mode32) LastPrintBuff("eax");
   else		     LastPrintBuff("ax");
  }break;
  case ARG_REG_BX: {
   if (inst->mode32) LastPrintBuff("ebx");
   else		     LastPrintBuff("bx");
  }break;
  case ARG_REG_CX: {
   if (inst->mode32) LastPrintBuff("ecx");
   else		     LastPrintBuff("cx");
  }break;
  case ARG_REG_DX: {
   if(inst->mode32)  LastPrintBuff("edx");
   else		     LastPrintBuff("dx");
  }break;
  case ARG_16REG_DX: LastPrintBuff("dx"); break;
  case ARG_REG_SP: {
   if (inst->mode32) LastPrintBuff("esp");
   else		     LastPrintBuff("sp");
  }break;
  case ARG_REG_BP: {
   if (inst->mode32) LastPrintBuff("ebp");
   else		     LastPrintBuff("bp");
  }break;
  case ARG_REG_SI: {
   if (inst->mode32) LastPrintBuff("esi");
   else		     LastPrintBuff("si");
  }break;
  case ARG_REG_DI: {
   if (inst->mode32) LastPrintBuff("edi");
   else		     LastPrintBuff("di");
  }break;
  case ARG_REG_AL:   LastPrintBuff("al"); break;
  case ARG_REG_AH:   LastPrintBuff("ah"); break;
  case ARG_REG_BL:   LastPrintBuff("bl"); break;
  case ARG_REG_BH:   LastPrintBuff("bh"); break;
  case ARG_REG_CL:   LastPrintBuff("cl"); break;
  case ARG_REG_CH:   LastPrintBuff("ch"); break;
  case ARG_REG_DL:   LastPrintBuff("dl"); break;
  case ARG_REG_DH:   LastPrintBuff("dh"); break;
  case ARG_REG_ST0:  LastPrintBuff("st(0)"); break;
  case ARG_REG_ES:   LastPrintBuff("es"); break;
  case ARG_REG_CS:   LastPrintBuff("cs"); break;
  case ARG_REG_DS:   LastPrintBuff("ds"); break;
  case ARG_REG_SS:   LastPrintBuff("ss"); break;
  case ARG_REG_FS:   LastPrintBuff("fs"); break;
  case ARG_REG_GS:   LastPrintBuff("gs"); break;
  case ARG_REG_A:    LastPrintBuff("a"); break;
  case ARG_REG_B:    LastPrintBuff("b"); break;
  case ARG_REG_C:    LastPrintBuff("c"); break;
  case ARG_REG_D:    LastPrintBuff("d"); break;
  case ARG_REG_E:    LastPrintBuff("e"); break;
  case ARG_REG_H:    LastPrintBuff("h"); break;
  case ARG_REG_L:    LastPrintBuff("l"); break;
  case ARG_REG_I:    LastPrintBuff("i"); break;
  case ARG_REG_R:    LastPrintBuff("r"); break;
  case ARG_REG_HL_IND: LastPrintBuff("(hl)"); break;
  case ARG_REG_BC:   LastPrintBuff("bc"); break;
  case ARG_REG_DE:   LastPrintBuff("de"); break;
  case ARG_REG_HL:   LastPrintBuff("hl"); break;
  case ARG_REG_BC_IND: LastPrintBuff("(bc)"); break;
  case ARG_REG_DE_IND: LastPrintBuff("(de)"); break;
  case ARG_REG_SP_IND: LastPrintBuff("(sp)"); break;
  case ARG_REG_IX:   LastPrintBuff("ix"); break;
  case ARG_REG_IX_IND: {
   LastPrintBuff("(ix");
   if (inst->flags&FLAGS_INDEXREG) {
    dta=inst->data+2;
    LastPrintBuff("+");
    LastPrintBuffLongHexValue((word)(dta[0]));
   }LastPrintBuff(")");
  }break;
  case ARG_REG_IY:   LastPrintBuff("iy"); break;
  case ARG_REG_IY_IND: {
   LastPrintBuff("(iy");
   if (inst->flags&FLAGS_INDEXREG) {
    dta=inst->data+2;
    LastPrintBuff("+");
    LastPrintBuffLongHexValue((word)(dta[0]));
   }
   LastPrintBuff(")");
  }break;
  case ARG_REG_C_IND:LastPrintBuff("(c)"); break;
  case ARG_REG_AF:   LastPrintBuff("af"); break;
  case ARG_REG_AF2:  LastPrintBuff("af'"); break;
  case ARG_IMM: {
   dta=inst->data+inst->length;
   if (inst->mode32) {
    dta-=4;
    switch (inst->override) {
     case over_decimal: {
      if (inst->displayflags&DISPFLAG_NEGATE) LastPrintBuff("-%02lu",0-*(dword *)dta);
      else				      LastPrintBuff("%02lu",*(dword *)dta);
     }break;
     case over_char: {
      LastPrintBuff("'");
      for (i=3;i>=0;i--) if (dta[i]) LastPrintBuff("%c",dta[i]);
      LastPrintBuff("'");
     }break;
     case over_dsoffset: {
      loc.assign(inst->addr.segm,*(dword *)dta);
      PrintOffset(loc);
     }break;
     case over_single: {
      sprintf(fbuff,"(float)%g",*(float *)dta);
      LastPrintBuff(fbuff);
     }break;
     default: {
      if (inst->displayflags&DISPFLAG_NEGATE) {
       LastPrintBuff("-");
       LastPrintBuffLongHexValue(0-*(dword *)dta);
      }else LastPrintBuffLongHexValue(*(dword *)dta);
     }break;
    }/*switch*/
   }else{ dta-=2;
    if (inst->override==over_decimal) {
     if (inst->displayflags&DISPFLAG_NEGATE)
      LastPrintBuff("-%02lu",0x10000-((word *)dta)[0]);
     else LastPrintBuff("%02lu",((word *)dta)[0]);
    }else if(inst->override==over_char)	{
     LastPrintBuff("\"");
     for (i=1;i>=0;i--) if (dta[i]) LastPrintBuff("%c",dta[i]);
     LastPrintBuff("\"");
    }else{
     if (inst->displayflags&DISPFLAG_NEGATE) {
      LastPrintBuff("-");
      LastPrintBuffLongHexValue(0x10000-((word *)dta)[0]);
     }else LastPrintBuffLongHexValue(((word *)dta)[0]);
    }
   }
  }break;
  case ARG_IMM_SINGLE:
   dta=inst->data+inst->length-4;
   sprintf(fbuff,"%g",*(float *)dta);
   LastPrintBuff(fbuff);
   break;
  case ARG_IMM_DOUBLE:
   dta=inst->data+inst->length-8;
   sprintf(fbuff,"%g",*(double *)dta);
   LastPrintBuff(fbuff);
   break;
  case ARG_IMM_LONGDOUBLE:
   dta=inst->data+inst->length-10;
   sprintf(fbuff,"%Lg",*(long double *)dta);
   LastPrintBuff(fbuff);
   break;
  case ARG_IMM32: {
   dta=inst->data+inst->length-4;
   switch (inst->override) {
    case over_decimal:
     if (inst->displayflags&DISPFLAG_NEGATE) LastPrintBuff("-%02lu",0-((dword *)dta)[0]);
     else				     LastPrintBuff( "%02lu",((dword *)dta)[0]);
     break;
    case over_char:
     LastPrintBuff("\'");
     for(i=3;i>=0;i--) if(dta[i]) LastPrintBuff("%c",dta[i]);
     LastPrintBuff("\'");
     break;
    case over_dsoffset:
     loc.assign(inst->addr.segm,*(dword *)dta);
     PrintOffset(loc);
     break;
    case over_single:
     sprintf(fbuff,"(float)%g",*(float *)dta);
     LastPrintBuff(fbuff);
     break;
    default:
     if (inst->displayflags&DISPFLAG_NEGATE) {
      LastPrintBuff("-");
      LastPrintBuffLongHexValue(0-((dword *)dta)[0]);
     }else LastPrintBuffLongHexValue(((dword *)dta)[0]);
     break;
   }/*switch*/
  }break;
  case ARG_STRING: {
   rm=0;
   LastPrintBuff("\"");
   sp=0;
   while (inst->data[rm]) {
    if (inst->data[rm]<32) {
     LastPrintBuff("\",");
     LastPrintBuffHexValue(inst->data[rm]);
     LastPrintBuff(",\"");
    }else LastPrintBuff("%c",inst->data[rm]);
    rm++;
    sp++;
    if (sp>MAX_STRINGPRINT) break;
   }
   LastPrintBuff("\",00h");
  }break;
  case ARG_PSTRING: {
   dta=inst->data;
   rm=dta[0];
   dta++;
   LastPrintBuffHexValue((byte)rm);
   LastPrintBuff(",\"");
   sp=0;
   while (rm) {
    if (dta[0]<32) {
     LastPrintBuff("\",");
     LastPrintBuffHexValue(*dta);
     LastPrintBuff(",\"");
    }else LastPrintBuff("%c",*dta);
    dta++;
    rm--;
    sp++;
    if (sp>MAX_STRINGPRINT) break;
   }
   LastPrintBuff("\"");
  }break;
  case ARG_DOSSTRING: {
   dta=inst->data;
   rm=inst->length;
   rm--;
   LastPrintBuff("\"");
   sp=0;
   while (rm) {
    if (dta[0]<32) {
     LastPrintBuff("\",");
     LastPrintBuffHexValue(dta[0]);
     LastPrintBuff(",\"");
    }else LastPrintBuff("%c",dta[0]);
    dta++;
    rm--;
    sp++;
    if (sp>MAX_STRINGPRINT) break;
   }
   LastPrintBuff("\"");
  }break;
  case ARG_CUNICODESTRING:	// missing DW instead DB (?)
   dta=inst->data;
   rm=inst->length;
   rm-=(byte)2;
   LastPrintBuff("\"");
   sp=0;
   while (rm) {
    if (dta[0]<32) {
     LastPrintBuff("\",");
     LastPrintBuffHexValue(dta[0]);
     LastPrintBuff(",\"");
    }else LastPrintBuff("%c",dta[0]);
    dta+=2;
    rm-=(byte)2;
    sp++;
    if (sp>MAX_STRINGPRINT) break;
   }
   LastPrintBuff("\"");
   break;
  case ARG_PUNICODESTRING:
   dta=inst->data+2;
   rm=inst->length;
   rm-=(byte)2;
   sp=0;
   LastPrintBuffHexValue((byte)(rm/2));
   LastPrintBuff(",\"");
   while (rm) {
    if (dta[0]<32) {
     LastPrintBuff("\",");
     LastPrintBuffHexValue(dta[0]);
     LastPrintBuff(",\"");
    }else LastPrintBuff("%c",dta[0]);
    dta+=2;
    rm-=(byte)2;
    sp++;
    if (sp>MAX_STRINGPRINT) break;
   }
   LastPrintBuff("\"");
   break;
  case ARG_MEMLOC:
   if (inst->flags&FLAGS_SEGPREFIX) outprefix(pbyte);
   dta=inst->data+inst->length;
   if (options.mode32) {
    dta-=4;
    loc.assign(inst->addr.segm,*(dword *)dta);
    if (inst->flags&FLAGS_8BIT) LastPrintBuff("byte ptr");
    else if (inst->flags&FLAGS_ADDRPREFIX) LastPrintBuff("word ptr");
    else LastPrintBuff("dword ptr");
    PrintMemVar(loc);
   }else{
    dta-=2;
    loc.assign(inst->addr.segm,((word *)dta)[0]);
    if (inst->flags&FLAGS_8BIT) LastPrintBuff("byte ptr");
    if (inst->flags&FLAGS_ADDRPREFIX) LastPrintBuff("dword ptr");
    else LastPrintBuff("word ptr");
    PrintMemVar(loc);
   }
   break;
  case ARG_MEMLOC16:
   if (inst->flags&FLAGS_SEGPREFIX) outprefix(pbyte);
   dta=inst->data+inst->length-2;
   if (options.processor==PROC_Z80) {
    loc.assign(inst->addr.segm,*(dword *)dta);
    PrintMemVar(loc);
   }else{
    loc.assign(inst->addr.segm,*(word *)dta);
    PrintMemVar(loc);
   }
   break;
  case ARG_SIMM8:
   dta=inst->data+inst->length-1;
   if (inst->override==over_char) {
    LastPrintBuff("\"");
    for(i=0;i>=0;i--) if(dta[i]) LastPrintBuff("%c",dta[i]);
    LastPrintBuff("\"");
   }else if (dta[0]&0x80) {
    if (inst->override==over_decimal) LastPrintBuff("%02lu",(word)(0x100-dta[0]));
    else{
     LastPrintBuff("-");
     LastPrintBuffLongHexValue((word)(0x100-dta[0]));
    }
   }else{
    if (inst->override==over_decimal) LastPrintBuff("%02lu",(word)(dta[0]));
    else LastPrintBuffLongHexValue((word)(dta[0]));
   }
   break;
  case ARG_IMM8:
      dta=inst->data+inst->length-1;
      if(inst->override==over_decimal)
      { if(inst->displayflags&DISPFLAG_NEGATE)
	  LastPrintBuff("-%02lu",0x100-(word)(dta[0]));
	else
	  LastPrintBuff("%02lu",(word)(dta[0]));
      }
      else if(inst->override==over_char)
      { LastPrintBuff("\"");
	for(i=0;i>=0;i--)
	  if(dta[i])
	    LastPrintBuff("%c",dta[i]);
	LastPrintBuff("\"");
      }
      else
      { if(inst->displayflags&DISPFLAG_NEGATE)
	{  LastPrintBuff("-");
	   LastPrintBuffLongHexValue(0x100-(word)(dta[0]));
	}
	else
	  LastPrintBuffLongHexValue((word)(dta[0]));
      }
      break;
  case ARG_IMM8_IND:
      dta=inst->data+inst->length-1;
      LastPrintBuff("(");
      LastPrintBuffLongHexValue((word)(dta[0]));
      LastPrintBuff(")");
      break;
  case ARG_IMM16:
      dta=inst->data+inst->length-2;
      if(inst->override==over_decimal)
      { if(inst->displayflags&DISPFLAG_NEGATE)
	  LastPrintBuff("-%02lu",0x10000-((word *)dta)[0]);
	else
	  LastPrintBuff("%02lu",((word *)dta)[0]);
      }
      else if(inst->override==over_char)
      { LastPrintBuff("\"");
	for(i=1;i>=0;i--)
	  if(dta[i])
	    LastPrintBuff("%c",dta[i]);
	LastPrintBuff("\"");
      }
      else
      { if(inst->displayflags&DISPFLAG_NEGATE)
	{  LastPrintBuff("-");
	   LastPrintBuffLongHexValue(0x10000-((word *)dta)[0]);
	}
	else
	  LastPrintBuffLongHexValue(((word *)dta)[0]);
      }
      break;
  case ARG_IMM16_A:
      dta=inst->data+inst->length-3;
      LastPrintBuffLongHexValue(((word *)dta)[0]);
      break;
  case ARG_RELIMM8:
      dta=inst->data+inst->length-1;
      if(inst->mode32) {
       targetd=(dword)((signed char)dta[0]+inst->addr.offs+inst->length);
       loc.assign(inst->addr.segm,targetd);
       PrintLongHex(loc);
      }else{
       targetw=(word)((signed char)dta[0]+inst->addr.offs+inst->length);
       loc.assign(inst->addr.segm,targetw);
       PrintLongHex(loc);
      }
      break;
  case ARG_RELIMM:
      dta=inst->data+inst->length;
      if(inst->mode32)
      { dta-=4;
	targetd=((dword *)dta)[0]+inst->addr.offs+inst->length;
	loc.assign(inst->addr.segm,targetd);
        PrintLongHex(loc);
      }
      else
      { dta-=2;
	targetw=(word)(((word *)dta)[0]+inst->addr.offs+inst->length);
	loc.assign(inst->addr.segm,targetw);
        PrintLongHex(loc);
      }
      break;
  case ARG_REG:
      dta=inst->data+inst->modrm;
      if(options.processor==PROC_Z80)
	LastPrintBuff(regzascii[dta[0]&0x07]);
      else if(((asminstdata *)(inst->tptr))->flags&FLAGS_8BIT)
	LastPrintBuff(reg8ascii[(dta[0]>>3)&0x07]);
      else if(inst->mode32)
	LastPrintBuff(reg32ascii[(dta[0]>>3)&0x07]);
      else
	LastPrintBuff(reg16ascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_MREG:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regmascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_XREG:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regxascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_FREG:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regfascii[dta[0]&0x07]);
      break;
  case ARG_SREG:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regsascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_CREG:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regcascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_DREG:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regdascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_TREG:
    case ARG_TREG_67:
      dta=inst->data+inst->modrm;
      LastPrintBuff(regtascii[(dta[0]>>3)&0x07]);
      break;
  case ARG_MODREG:
  case ARG_MMXMODRM:
  case ARG_XMMMODRM:
  case ARG_MODRM8:
  case ARG_MODRM16:
  case ARG_MODRM_S:
  case ARG_MODRMM512:
  case ARG_MODRMQ:
  case ARG_MODRM_SREAL:
  case ARG_MODRM_PTR:
  case ARG_MODRM_WORD:
  case ARG_MODRM_BCD:
  case ARG_MODRM_SINT:
  case ARG_MODRM_EREAL:
  case ARG_MODRM_DREAL:
  case ARG_MODRM_WINT:
  case ARG_MODRM_LINT:
  case ARG_MODRM_FPTR:
  case ARG_MODRM: {
   dta=inst->data+inst->modrm;
   rm=(byte)((dta[0]&0xc0)>>6);
   modrm=(byte)(dta[0]&0x07);
   a1=DSMITEM_ARG1(inst);
   a2=DSMITEM_ARG2(inst);
   sib=dta[1];
   if (a1==ARG_IMM || a2==ARG_IMM || a1==ARG_IMM8 || a2==ARG_IMM8 || a2==ARG_NONE
   ||a1==ARG_SIMM8 || a2==ARG_SIMM8 || modrm==5 && rm==0
   || modrm==4 && rm==2 && sib&0x07==5
   || modrm==4 && rm==0 && sib&0x07==5) {
    if (rm<3) {
     switch (a) {
      case ARG_MODRM8:		LastPrintBuff("byte ptr ");	break;
      case ARG_MODRM16:
      case ARG_MODRM_WORD:	LastPrintBuff("word ptr ");	break;
      case ARG_MMXMODRM:
      case ARG_XMMMODRM:	LastPrintBuff("dword ptr ");	break;
      case ARG_MODRMQ:		LastPrintBuff("qword ptr ");	break;
      case ARG_MODRM_S:		LastPrintBuff("fword ptr ");	break;	// 6 bytes=fword
      case ARG_MODRM_SREAL:	LastPrintBuff("dword ptr ");	break;	// single real=4 bytes=dword
      case ARG_MODRM_BCD:	LastPrintBuff("tbyte ptr ");	break;	// packed bcd=10 bytes=tbyte
      case ARG_MODRM_SINT:	LastPrintBuff("dword ptr ");	break;	// short int=4 bytes
      case ARG_MODRM_WINT:	LastPrintBuff("word ptr ");	break;	// word int =2 bytes
      case ARG_MODRM_LINT:	LastPrintBuff("qword ptr ");	break;	// long int = 8 bytes
      case ARG_MODRMM512:	LastPrintBuff("byte ptr ");	break;	// points to 512 bits=64 bytes of memory......
      case ARG_MODRM_EREAL:	LastPrintBuff("tbyte ptr ");	break;	// extended real=10 bytes
      case ARG_MODRM_DREAL:	LastPrintBuff("qword ptr ");	break;	// double real=8 bytes
      case ARG_MODRM:
       if (inst->flags&FLAGS_8BIT)	LastPrintBuff("byte ptr ");
       else if (inst->mode32)		LastPrintBuff("dword ptr ");
       else				LastPrintBuff("word ptr ");
       break;
     }/*switch(a)*/
    }
   }else if (a1==ARG_REG || a2==ARG_REG) {
    if (rm<3) {
     switch (a) {		    // re movzx, movsx type instructions
      case ARG_MODRM8:		LastPrintBuff("byte ptr ");	break;
      case ARG_MODRM16:		LastPrintBuff("word ptr ");	break;
     }/*switch(a)*/
    }
   }
   switch (rm) {
    case 0:
	  if(inst->flags&FLAGS_SEGPREFIX)
	    outprefix(pbyte);
	  if(options.mode32)
	  { if(modrm==5)
	    { loc.assign(inst->addr.segm,((dword *)(&dta[1]))[0]);
	      PrintMemVar(loc);
	    }
	    else if(modrm==4)	     // case 4=sib
	    { sib=dta[1];
	      if((sib&0x07)==5) // disp32
	      { loc.assign(inst->addr.segm,((dword *)(&dta[2]))[0]);
	        PrintMemVar(loc);
	      }
	      else
	      { LastPrintBuff("[%s]",reg32ascii[sib&0x07]);
	      }
	      if(((sib>>3)&0x07)==4) // no scaled index reg
	      {
	      }
	      else
	      { LastPrintBuff("[%s",reg32ascii[(sib>>3)&0x07]);
		switch(sib>>6)
		{ case 0:
		    LastPrintBuff("]");
		    break;
		  case 1:
		    LastPrintBuff("*2]");
		    break;
		  case 2:
		    LastPrintBuff("*4]");
		    break;
		  case 3:
		    LastPrintBuff("*8]");
		    break;
		}
	      }
	    }
	    else
	      LastPrintBuff("[%s]",reg32ascii[dta[0]&0x07]);
	  }
	  else
	  { if(modrm==6)
	    { loc.assign(inst->addr.segm,((word *)(&dta[1]))[0]);
	      PrintMemVar(loc);
	    }
	    else
	      LastPrintBuff("[%s]",regind16ascii[dta[0]&0x07]);
	  }
	  break;
    case 1:
	  if(inst->flags&FLAGS_SEGPREFIX)
	    outprefix(pbyte);
	  if(options.mode32)
	  { if(modrm==4)	// case 4=sib
	    { sib=dta[1];
	      if(dta[2]&0x80)
	      { LastPrintBuff("[%s-",reg32ascii[dta[1]&0x07]);
		LastPrintBuffHexValue((byte)(-dta[2]));
	      }
	      else
	      { LastPrintBuff("[%s+",reg32ascii[dta[1]&0x07]);
		LastPrintBuffHexValue(dta[2]);
	      }
	      if(((sib>>3)&0x07)==4) // no scaled index reg
		LastPrintBuff("]");
	      else
	      { LastPrintBuff("][%s",reg32ascii[(sib>>3)&0x07]);
		switch(sib>>6)
		{ case 0:
		    LastPrintBuff("]");
		    break;
		  case 1:
		    LastPrintBuff("*2]");
		    break;
		  case 2:
		    LastPrintBuff("*4]");
		    break;
		  case 3:
		    LastPrintBuff("*8]");
		    break;
		}
	      }
	    }
	    else if(dta[1]&0x80)
	    { LastPrintBuff("[%s-",reg32ascii[dta[0]&0x07]);
	      LastPrintBuffHexValue((byte)(-dta[1]));
	      LastPrintBuff("]");
	    }
	    else
	    { LastPrintBuff("[%s+",reg32ascii[dta[0]&0x07]);
	      LastPrintBuffHexValue(dta[1]);
	      LastPrintBuff("]");
	    }
	  }
	  else
	  { if(dta[1]&0x80)
	    { LastPrintBuff("[%s-",regind16ascii[dta[0]&0x07]);
	      LastPrintBuffHexValue((byte)(-dta[1]));
	      LastPrintBuff("]");
	    }
	    else
	    { LastPrintBuff("[%s+",regind16ascii[dta[0]&0x07]);
	      LastPrintBuffHexValue(dta[1]);
	      LastPrintBuff("]");
	    }
	  }
	  break;
    case 2:
     if (inst->flags&FLAGS_SEGPREFIX) outprefix(pbyte);
     if (options.mode32) {
      loc.assign(inst->addr.segm,((dword *)(&dta[1]))[0]);
      if (modrm==4) {	// case 4=sib
       sib=dta[1];
       loc.assign(inst->addr.segm,((dword *)(&dta[2]))[0]);
       LastPrintBuff("[");
       if (name->isname(loc)) {
        LastPrintBuff("%s+",reg32ascii[sib&0x07]);
	name->printname(loc);
       }else if (import->isname(loc)) {
        LastPrintBuff("%s+",reg32ascii[sib&0x07]);
	import->printname(loc);
       }else if(expt->isname(loc)) {
        LastPrintBuff("%s+",reg32ascii[sib&0x07]);
	expt->printname(loc);
       }else if(dta[5]&0x80) {
        LastPrintBuff("%s-",reg32ascii[sib&0x07]);
	LastPrintBuffLongHexValue(0-((dword *)(&dta[2]))[0]);
       }else{
        LastPrintBuff("%s+",reg32ascii[sib&0x07]);
	LastPrintBuffLongHexValue(((dword *)(&dta[2]))[0]);
       }
       if (((sib>>3)&0x07)==4) // no scaled index reg
	 LastPrintBuff("]");
       else{
        LastPrintBuff("][%s",reg32ascii[(sib>>3)&0x07]);
	switch (sib>>6)	{
	 case 0: LastPrintBuff("]");	break;
	 case 1: LastPrintBuff("*2]");	break;
	 case 2: LastPrintBuff("*4]");	break;
	 case 3: LastPrintBuff("*8]");	break;
	}
       }
      }else if (name->isname(loc)) {
       name->printname(loc);
       LastPrintBuff("[%s]",reg32ascii[dta[0]&0x07]);
      }else if (import->isname(loc)) {
       import->printname(loc);
       LastPrintBuff("[%s]",reg32ascii[dta[0]&0x07]);
      }else if (expt->isname(loc)) {
       expt->printname(loc);
       LastPrintBuff("[%s]",reg32ascii[dta[0]&0x07]);
      }else if (dta[4]&0x80) {
       LastPrintBuff("[%s-",reg32ascii[dta[0]&0x07]);
       LastPrintBuffLongHexValue(0-*(dword*)(dta+1));
       LastPrintBuff("]");
      }else{
       LastPrintBuff("[%s+",reg32ascii[dta[0]&0x07]);
       LastPrintBuffLongHexValue(*(dword*)(dta+1));
       LastPrintBuff("]");
      }
     }else{
      loc.assign(inst->addr.segm,((word *)(&dta[1]))[0]);
      if (name->isname(loc)) {
       name->printname(loc);
       LastPrintBuff("[%s]",regind16ascii[*dta&0x07]);
      }else if (import->isname(loc)) {
       import->printname(loc);
       LastPrintBuff("[%s]",regind16ascii[*dta&0x07]);
      }else if (expt->isname(loc)) {
       expt->printname(loc);
       LastPrintBuff("[%s]",regind16ascii[*dta&0x07]);
      }else if (dta[2]&0x80) {
       LastPrintBuff("[%s-",regind16ascii[*dta&0x07]);
       LastPrintBuffLongHexValue(0x10000-((word *)(&dta[1]))[0]);
       LastPrintBuff("]");
      }else{
       LastPrintBuff("[%s+",regind16ascii[dta[0]&0x07]);
       LastPrintBuffLongHexValue(((word *)(&dta[1]))[0]);
       LastPrintBuff("]");
      }
     }
    break;
    case 3:
     if (a==ARG_MMXMODRM) LastPrintBuff(regmascii[dta[0]&0x07]);
     else if(a==ARG_XMMMODRM)
       LastPrintBuff(regxascii[dta[0]&0x07]);
     else if((((asminstdata *)(inst->tptr))->flags&FLAGS_8BIT)||(a==ARG_MODRM8))
       LastPrintBuff(reg8ascii[dta[0]&0x07]);
     else if((inst->mode32)&&(a!=ARG_MODRM16))
       LastPrintBuff(reg32ascii[dta[0]&0x07]);
     else LastPrintBuff(reg16ascii[dta[0]&0x07]);
   }/*switch(rm)*/
  }break;
  case ARG_IMM_1:
      if(inst->override==over_decimal)
	LastPrintBuff("1");
      else
	LastPrintBuff("1h");
      break;
  case ARG_FADDR:
      dta=inst->data+inst->length;
      if(options.mode32)
      { dta-=6;
	loc.assign(((word *)(&dta[4]))[0],((dword *)(&dta[0]))[0]);
        if (!PrintFoundName(loc)) LastPrintBuff("%04x:%08lxh",loc.segm,loc.offs);
      }
      else
      { dta-=4;
	loc.assign(((word *)(&dta[2]))[0],((word *)(&dta[0]))[0]);
        if (!PrintFoundName(loc)) LastPrintBuff("%04x:%04xh",loc.segm,loc.offs);
      }
      break;
  case ARG_BIT:
      dta=inst->data+inst->length-1;
      LastPrintBuff("%x",(dta[0]>>3)&7);
      break;
  case ARG_NONE:
      if(inst->flags&FLAGS_SEGPREFIX)
	outprefix(pbyte);
      break;
  case ARG_NONEBYTE: break;
 }
 if (inst->flags&FLAGS_ADDRPREFIX)
   options.mode32=!options.mode32;
}

/************************************************************************
* outcomment								*
* - prints a disassembly comment to the buffer				*
************************************************************************/
void disio::outcomment(dsmitem *inst) {
 LastPrintBuff(";%s",inst->tptr);
}

/************************************************************************
* dumpblocktofile							*
* - this is the text and asm output routine. It needs a lot more work	*
*   doing to it and is presently a fairly simple dump of a block of	*
*   code.								*
* - this routine was a quick hack and complete rip of the dumptofile	*
*   routine which follows. the two routines need the common workings	*
*   put together and both need rewriting				*
************************************************************************/
void disio::dumpblocktofile(char *fname,bool printaddrs) {
 HANDLE efile;
 dword num;
 dsmitem *tblock,fdsm;
 dsegitem *dblock,*nxtblock;
 lptr outhere,nptr;
 int i;
 char ehdr[300];
 if (!blk.checkblock()) return;
 efile=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_NEW,0,NULL);
 if(efile==INVALID_HANDLE_VALUE) {
  MessageBox(MainWnd,"File Creation Failed","Borg Disassembler Alert",MB_OK);
  return;
 }
// scheduler.stopthread();
 WriteFile(efile,"; ",2,&num,NULL);
 WriteFile(efile,winname,lstrlen(winname),&num,NULL);
 WriteFile(efile,"\r\n;\r\n",5,&num,NULL);
 WriteFile(efile,hdr,lstrlen(hdr),&num,NULL);
 WriteFile(efile,hdr2,lstrlen(hdr2),&num,NULL);
 WriteFile(efile,";\r\n",3,&num,NULL);
 wsprintf(ehdr,"; block dump from: %04x:%08lxh to %04x:%08lxh",blk.top.segm,blk.top.offs,blk.bottom.segm,blk.bottom.offs);
 WriteFile(efile,ehdr,lstrlen(ehdr),&num,NULL);
 WriteFile(efile,"\r\n",2,&num,NULL);
 WriteFile(efile,"\r\n",2,&num,NULL);
  // find current position.
 fdsm.addr=blk.top;
 fdsm.type=dsmnull;
 tblock=dsm->find(&fdsm);
 while (tblock) {
  if (tblock->addr<blk.top) tblock=dsm->nextiterator();
  else break;
 }
  // now tblock= first position
 dblock=dta->findseg(blk.top);
 outhere=blk.top;
 while (dblock && (outhere<=blk.bottom)) {
  ClearBuff(); // clear buffer - ready to start
  for (i=0;i<size.y;i++) {
   if (tblock) {
    if(outhere==tblock->addr)	{
     switch(tblock->type) {
      case dsmcode:
      outinst(tblock,printaddrs);
      break;
      case dsmnameloc:
      printlineheader(tblock->addr,printaddrs);
      LastPrintBuff("%s:",tblock->data);
      break;
      case dsmxref:
      // temp measure - print first (build 17)
      printlineheader(tblock->addr,printaddrs);
      LastPrintBuff(";");
      LastPrintBuffEpos(COMMENTPOS);
      LastPrintBuff("XREFS First: ");
      xrefs->printfirst(tblock->addr);
      break;
      default:
      printlineheader(tblock->addr,printaddrs);
      outcomment(tblock);
     }
     outhere+=tblock->length;
     tblock=dsm->nextiterator();
    }else{
     outdb(&outhere,printaddrs);
     outhere++;
    }
   }else{
    outdb(&outhere,printaddrs);
    outhere++;
   }
     // check if gone beyond seg, get next seg.
     /*if(dta->beyondseg(outhere))*/	 // changed build 14
     // rewritten build 17. seeks dseg from start, and finds next now.
   if (outhere>=(dblock->addr+dblock->size)) {
    dta->resetiterator();
    nxtblock=dta->nextiterator();
    while (nxtblock) {
     if (nxtblock->addr==dblock->addr) {
      dblock=dta->nextiterator();
      break;
     }
     nxtblock=dta->nextiterator();
     if (!nxtblock) dblock=NULL;
    }
    if (!dblock) break;
    outhere=dblock->addr;
   }
   if (outhere>blk.bottom) break;
   if (!outhere.segm) break;
  }
  DumpBuff(efile);
 }
 DoneBuff();
 CloseHandle(efile);
// scheduler.continuethread();
 scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
* dumptofile								*
* - this is the text and asm output routine. It needs a lot more work	*
*   doing to it and is presently a fairly simple dump of the code.	*
************************************************************************/
void disio::dumptofile(char *fname,bool printaddrs)
{ SECURITY_ATTRIBUTES securityatt;
  HANDLE efile;
  dword num;
  dsmitem *tblock;
  dsegitem *dblock,*nxtblock;
  lptr outhere,nptr;
  int i;
  securityatt.nLength=sizeof(SECURITY_ATTRIBUTES);
  securityatt.lpSecurityDescriptor=NULL;
  securityatt.bInheritHandle=false;
  efile=CreateFile(fname,GENERIC_WRITE,0,&securityatt,CREATE_NEW,0,NULL);
  if(efile==INVALID_HANDLE_VALUE)
  { MessageBox(MainWnd,"File Creation Failed","Borg Disassembler Alert",MB_OK);
    return;
  }
//  scheduler.stopthread();
  WriteFile(efile,"; ",2,&num,NULL);
  WriteFile(efile,winname,lstrlen(winname),&num,NULL);
  WriteFile(efile,"\r\n;\r\n",5,&num,NULL);
  WriteFile(efile,hdr,lstrlen(hdr),&num,NULL);
  WriteFile(efile,hdr2,lstrlen(hdr2),&num,NULL);
  WriteFile(efile,"\r\n",2,&num,NULL);
  // find current position.
  dsm->resetiterator();
  tblock=dsm->nextiterator();
  // now tblock= first position
  dta->resetiterator();
  dblock=dta->nextiterator();
  outhere=dblock->addr;
 while (dblock) {
  ClearBuff(); // clear buffer - ready to start
  for (i=0;i<size.y;i++) {
   if (tblock) {
    if (outhere==tblock->addr) {
     switch (tblock->type) {
      case dsmcode:
	      outinst(tblock,printaddrs);
	      break;
      case dsmnameloc:
	      printlineheader(tblock->addr,printaddrs);
	      LastPrintBuff("%s:",tblock->data);
	      break;
      case dsmxref:
	      // temp measure - print first (build 17)
	      printlineheader(tblock->addr,printaddrs);
	      LastPrintBuff(";");
	      LastPrintBuffEpos(COMMENTPOS);
	      LastPrintBuff("XREFS First: ");
	      xrefs->printfirst(tblock->addr);
	      break;
      default:
	      printlineheader(tblock->addr,printaddrs);
	      outcomment(tblock);
     }
     outhere+=tblock->length;
     tblock=dsm->nextiterator();
    }else{
     outdb(&outhere,printaddrs);
     outhere++;
    }
   }else{
    outdb(&outhere,printaddrs);
    outhere++;
   }
      // check if gone beyond seg, get next seg.
      /*if(dta->beyondseg(outhere))*/	 // changed build 14
      // rewritten build 17. seeks dseg from start, and finds next now.
   if (outhere>=(dblock->addr+dblock->size)) {
    dta->resetiterator();
    nxtblock=dta->nextiterator();
    while (nxtblock!=NULL) {
     if (nxtblock->addr==dblock->addr) {
      dblock=dta->nextiterator();
      break;
     }
     nxtblock=dta->nextiterator();
     if (!nxtblock) dblock=NULL;
    }
    if (!dblock) break;
    outhere=dblock->addr;
   }
   if (!outhere.segm) break;
  }
  DumpBuff(efile);
 }
 DoneBuff();
 CloseHandle(efile);
// scheduler.continuethread();
 scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
}

/************************************************************************
*		  mainwind.cpp						*
* This is one of a few files which contain some old code, a lot of	*
* hacks, a lot of hastily stuffed lines and variables, etc, and is in	*
* in need of an overhaul. Its also why I left commenting it until the	*
* last four files (disasm,fileload,dasm and this one!). Whilst making	*
* these comments I have taken a small opportunity to tidy it a little.	*
* This file controls output to the main window. It keeps a small buffer *
* of disassembled lines, and it uses this buffer to repaint the main	*
* window when WM_PAINT requests are received.				*
* Whenever the disassembly is changed or the user scrolls there is a	*
* windowupdate request sent to the scheduler with a high priority.	*
* When the windowupdate is processed it is passed to the windowupdate	*
* or scroller function in disio. disio will regenerate the buffer as	*
* required and then invalidate the main window so that a repaint is	*
* done.									*
* The functions here include basic formatted output to the buffer as	*
* well as the window repaints. Repaints will not be done while the	*
* buffer is being updated, but will wait for the buffer update to	*
* finish and then do the repaint.					*
* The functions also use extensive critical sections which ensure that	*
* we do not start clearing the buffer during a window update, etc	*
************************************************************************/

/************************************************************************
* DoPaint								*
* - This is the main painting routine. If the program is quitting then	*
*   it returns (we dont want thread clashes due to critical sections	*
*   here and theres no point to repainting when we're exitting).	*
* - If the buffer is not ready then we wait, and go to sleep.		*
* - Otherwise the routine paints the screen from the buffer, using the	*
*   selected font and colours						*
************************************************************************/
void disio::DoPaint(void) {
 PAINTSTRUCT ps;    // holds PAINT information
 int i;

// while (bufferbusy) Sleep(0);	// wait if filling buffer
// if (KillThread) return;

// EnterCriticalSection(&cs);
 BeginPaint(wnd,&ps);
 SelectObject(ps.hdc,Font);
 SetTextColor(ps.hdc,options.textcolor);
 for (i=0;i<size.y;i++) {
  RECT R;
  SetBkColor(ps.hdc,
    i==sel ? options.highcolor : options.bgcolor);
  GetItemRect(i,&R);
  ExtTextOut(ps.hdc,-hpos*CharBox.x,R.top,ETO_OPAQUE,&R,
    MainBuff[i],i<lastline?lstrlen(MainBuff[i]):0,NULL);
 }
 EndPaint(wnd,&ps);
// LeaveCriticalSection(&cs);
}

/************************************************************************
* ClearBuff								*
* - This should be called before each reworking of the buffer. It	*
*   clears the buffer and stops any repainting from taking place.	*
* - It also resets the line pointer to the start of the buffer.		*
************************************************************************/
void disio::ClearBuff(void) {
// int i;
// EnterCriticalSection(&cs);
// for (i=0;i<size.y;i++) {
//  MainBuff[i][0]='\0';
// }
 lastline=0;
// bufferbusy=true;
// LeaveCriticalSection(&cs);
}

/************************************************************************
* DoneBuff								*
* - This should be called after a reworking of the buffer. It reenables *
*   window repainting.							*
************************************************************************/
void disio::DoneBuff(void) {
// EnterCriticalSection(&cs);
// bufferbusy=false;
// LeaveCriticalSection(&cs);
}

/************************************************************************
* PrintBuff								*
* - This is the printf of the buffer and is similar to wvsprintf but	*
*   output is to the main buffer. Note that the line pointer is moved	*
*   on after a call, so we move to the next line automatically.		*
************************************************************************/
// adds next line to the buffer.
void disio::PrintBuff(char *szFormat,...) {
// EnterCriticalSection(&cs);
 va_list vaArgs;
 va_start(vaArgs,szFormat);
 if (lastline<size.y) {
  wvsprintf(MainBuff[lastline++],szFormat,vaArgs);
 }
 va_end(vaArgs);
  // just zero end of buffer.....in case.
//  MainBuff[BUFFER_LINES*max_length]=0;
//  LeaveCriticalSection(&cs);
}

/************************************************************************
* LastPrintBuffEpos							*
* - Often we use PrintBuff followed by LastPrintBuff to construct a	*
*   line of output a piece at a time. This function provides basic	*
*   formatting by allowing us to set the cursor position on the last	*
*   line printed, by adding spaces until the position.			*
************************************************************************/
// adds blanks to previous line to set position
void disio::LastPrintBuffEpos(int xpos) {
 int i;
 int spos;
 if (!lastline) return;
// EnterCriticalSection(&cs);
 spos=lastline-1;
 i=lstrlen(MainBuff[spos]);
 while (i<xpos) {
  MainBuff[spos][i]=' ';
  i++;
  MainBuff[spos][i]='\0';
 }
// LeaveCriticalSection(&cs);
}

/************************************************************************
* LastPrintBuffHexValue							*
* - Same as LastPrintBuff, but prints num only, in hex. It prints a	*
*   leading zero where the leading char is alpha.			*
************************************************************************/
void disio::LastPrintBuffHexValue(byte num)
{ char tstr[20];
  wsprintf(tstr,"%02xh",num);
  if((tstr[0]>='a')&&(tstr[0]<='f'))
    LastPrintBuff("0");
  LastPrintBuff("%02xh",num);
}

/************************************************************************
* LastPrintBuffHexValue							*
* - Same as LastPrintBuff, but prints num only, in hex. It prints a	*
*   leading zero where the leading char is alpha.			*
************************************************************************/
void disio::LastPrintBuffLongHexValue(dword num) {
 char tstr[20];
 wsprintf(tstr,"%02lxh",num);
 if (tstr[0]>='a' && tstr[0]<='f') LastPrintBuff("0");
 LastPrintBuff(tstr);	// doesn't contain "%"
}

/************************************************************************
* LastPrintBuff								*
* - This is the same as PrintBuff except that instead of printing a new *
*   line it goes back to the last line and adds more to the end of it	*
* - So a set of calls tends to look like PrintBuff, LastPrintBuffEPos,	*
*   LastPrintBuff, LastPrintBuffEPos, LastPrintBuff, PrintBuff, etc	*
************************************************************************/
void disio::LastPrintBuff(char *szFormat,...) {
 int spos,len;
 char s[MAX_LENGTH];

 if (!lastline) return;
 spos=lastline-1;
// EnterCriticalSection(&cs);
 va_list vaArgs;
 va_start(vaArgs,szFormat);
 wvsprintf(s,szFormat,vaArgs);
 va_end(vaArgs);
 len=lstrlen(MainBuff[spos]);
 lstrcpyn(MainBuff[spos]+len,s,MAX_LENGTH-len);	// append and watch size
// LeaveCriticalSection(&cs);
}

/************************************************************************
* DumpBuff								*
* - Now this is a real hack. Instead of writing proper file IO routines *
*   I simply write a buffer full at a time, and dump each to a file.... *
*   Then when I've written the file out I regenerate the buffer for the *
*   display again....... to be rewritten......				*
************************************************************************/
void disio::DumpBuff(HANDLE efile) {
 DWORD num;
 int i;
 for (i=0;i<lastline;i++) {
  WriteFile(efile,MainBuff[i],lstrlen(MainBuff[i]),&num,NULL);
  WriteFile(efile,"\r\n",2,&num,NULL);
 }
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded