unit imports;
interface
uses sysutils,windows,gname,common,menus,schedule;

// This is the imports class extension of the generic names class gname  *
// Imports were implemented as a separate class to normal names because  *
// this allowed a slightly different treatment of them                   *
// Also exports and imports have been given different dialogs, and can   *
// be treated differently in disassembly and display. I suppose this     *
// could have been implemented as a property of the names class but I    *
// decided early on to separate the classes out                          *
type
  timports=class(tgname)
  public
    procedure importsviewer;
    procedure demangle(nme:pchar);
    function importaddr(nm:pchar):dword;
  end;

var
 import:timports;

implementation

//function strnicmp(a,b:pchar;n:integer):boolean; external 'shell32.dll' name 'lstrncmpi';
function strnicmp(a,b:pchar;n:integer):boolean;
var i:integer;
begin
  result:=false; if (a=nil) or (b=nil) then exit;
  for i:=0 to n-1 do begin
    if (a[i]=#0) or (b[i]=#0) then exit;
    if upcase(a[i])<>upcase(b[i]) then exit;
  end; result:=true;
end;

// importaddr                                                            *
// - this checks to see if a name is an import, and if it is then it     *
//   returns the offset of its loc otherwise it returns 0. This function *
//   is used in generating the segment for imports in an NE file.        *
function timports.importaddr(nm:pchar):dword;
var t:pgnameitem;
begin
  resetiterator;
  t:=pgnameitem(nextiterator);
  while t<>nil do begin
    if strcomp(t.nam,nm)=0 then begin
      result:=t.addr.o; exit;
    end;
    t:=pgnameitem(nextiterator);
  end;
  result:=0;
end;

// importsbox                                                            *
// - this is the imports viewer dialog box, it is similar to the exports *
//   and names dialog, although simpler since there is only an ok button *
//   Most of the code is for filling the list box and displaying info    *
//   when an item is selected                                            *
function importsbox(hdwnd:HWND; msg,wParam,lParam:dword):dword;stdcall;
const
  brush:hbrush=0;
  nseg:string='';
  noff:string='';
  t:pgnameitem=nil;
var
  i:dword;
  drect:trect;
begin
  result:=0;
  case msg of
   WM_COMMAND:
     begin
       case wParam of
        IDC_OKBUTTON:
          begin
             EndDialog(hdwnd,0);
             result:=1;
             exit;
           end;
        end;
        case HIWORD(wParam) of
          LBN_SELCHANGE:
            begin
              i:=SendDlgItemMessage(hdwnd,IDC_IMPORTSLISTBOX,LB_GETCURSEL,0,0);
              import.resetiterator;
              t:=pgnameitem(import.nextiterator);
              while i<>0 do begin
                t:=pgnameitem(import.nextiterator);
                dec(i);
              end;
              fmtstr(nseg,'0x%4.4x',[t.addr.s]);
              fmtstr(noff,'0x%8.8x',[t.addr.o]);
              SendDlgItemMessage(hdwnd,IMPORTS_TEXTSTART,WM_SETTEXT,0,dword(pchar(nseg)));
              SendDlgItemMessage(hdwnd,IMPORTS_TEXTEND,WM_SETTEXT,0,dword(pchar(noff)));
             end;
         end;
       end;
    WM_INITDIALOG:
      begin
        GetWindowRect(hdwnd,drect);
        MoveWindow(hdwnd,((mainwnd.right+mainwnd.left)-(drect.right-drect.left)) div 2,
          ((mainwnd.bottom+mainwnd.top)-(drect.bottom-drect.top)) div 2,drect.right-drect.left,drect.bottom-drect.top,TRUE);
        import.resetiterator;
        for i:=0 to import.numlistitems-1 do begin
          t:=pgnameitem(import.nextiterator);
          SendDlgItemMessage(hdwnd,IDC_IMPORTSLISTBOX,LB_ADDSTRING,0,dword(@t.nam^));
        end;
        SendDlgItemMessage(hdwnd,IDC_IMPORTSLISTBOX,LB_SETCURSEL,0,0);
        import.resetiterator;
        t:=pgnameitem(import.nextiterator);
        fmtstr(nseg,'0x%4.4x',[t.addr.s]);
        fmtstr(noff,'0x%8.8x',[t.addr.o]);
        SendDlgItemMessage(hdwnd,IMPORTS_TEXTSTART,WM_SETTEXT,0,dword(pchar(nseg)));
        SendDlgItemMessage(hdwnd,IMPORTS_TEXTEND,WM_SETTEXT,0,dword(pchar(noff)));
        brush:=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
        SetFocus(GetDlgItem(hdwnd,IDC_OKBUTTON));
        exit;
      end;
    WM_DESTROY:
      begin
        DeleteObject(brush); exit;
      end;
    WM_CTLCOLORSTATIC,
    WM_CTLCOLORBTN,
    WM_CTLCOLORDLG,
    WM_SYSCOLORCHANGE:
      begin
       SetBkColor(HDC(wParam),GetSysColor(COLOR_BTNFACE));
       result:=brush;
       exit;
      end;
  end;
end;

// importsviewer                                                         *
// - stops the thread and displays the imports viewer dialog. Although   *
//   this supports the repeater variable, as for the names class, it is  *
//   currently unused                                                    *
procedure timports.importsviewer;
begin
  repeater:=TRUE;
  while repeater do begin
    if numlistitems=0 then begin
      MessageBox(0,'There are no imports in the list','Borg Message',MB_OK);
      exit;
    end;
    scheduler.stopthread;
    repeater:=FALSE;
    DialogBox(Inst,MAKEINTRESOURCE(Imports_Viewer),mainwindow,@importsbox);
    scheduler.continuethread;
  end;
end;

// demangle                                                              *
// - this is a gname function, overridden for the imports class. Name    *
//   damangling is currently not very good, and I have some old Borland  *
//   source code which could improve this greatly......... just need to  *
//   dig it out, rework it for Borg, and put it in here now......        *
procedure timports.demangle(nme:pchar);
var
  buff :array[0..255] of char;
  buff2:array[0..255] of char;
  nam:pchar;
  namelen,i,j,k,atcount,bpoint:integer;
  brac,pointer,rpointer:boolean;
begin
  if not options.demangle then exit;
  atcount:=0; i:=0; j:=0;
  brac:=FALSE;
  nam:=nme;
  while nam[i]<>#0 do begin
    if nam[i]='@' then begin
      inc(atcount);
      if atcount>1 then begin
        buff[j]:=':'; buff[j+1]:=':'; inc(j,2);
      end;
    end else if (nam[i]='$')and(nam[i+1]='q')and(not brac) then begin
      brac:=TRUE;
      bpoint:=j;
      buff[j]:='('; inc(j);
      inc(i);
    end else if (nam[i]='$')and(nam[i+1]='x')and(nam[i+2]='q')and( not brac) then begin
      brac:=TRUE;
      bpoint:=j;
      buff[j]:='('; inc(j);
      inc(i,2);
    end else if not strnicmp(@nam[i],'$bctr',5) then begin
      k:=0;
      while (buff[k]<>':')and(k<20) do begin
        buff[j]:=buff[k]; inc(j); inc(k);
      end;
      inc(i,4);
    end else if not strnicmp(@nam[i],'$bdtr',5) then begin
      k:=0;
      buff[j]:='~'; inc(j);
      while (buff[k]<>':')and(k<20) do begin
        buff[j]:=buff[k]; inc(j); inc(k);
      end;
      inc(i,4);
    end else if not strnicmp(@nam[i],'$bdla',5) then begin
      strcopy(@buff[j],'delete');
      inc(j,6); inc(i,4);
    end else if not strnicmp(@nam[i],'$bnwa',5) then begin
      strcopy(@buff[j],'new');
      inc(j,3); inc(i,4);
    end else if not strnicmp(@nam[i],'$bdele',6) then begin
      strcopy(@buff[j],'delete');
      inc(j,6); inc(i,5);
    end else if not strnicmp(@nam[i],'$bnew',5) then begin
      strcopy(@buff[j],'new');
      inc(j,5); inc(i,4);
    end else begin buff[j]:=nam[i]; inc(j); end;
    inc(i);
  end;
  if brac then begin buff[j]:=')'; inc(j); end;
  buff[j]:=#0;
  strcopy(@buff2,@buff);
  if brac then begin
    j:=bpoint;
    k:=bpoint;
    i:=0;
    pointer :=FALSE;
    rpointer:=FALSE;
    while buff[j]<>#0 do begin
      if (buff[j]='p')and(i=0) then begin
        pointer:=TRUE;
        inc(j);
      end;
      if (buff[j]='r')and(i=0) then begin
        rpointer:=TRUE;
        inc(j);
      end else if (buff[j]='i')and(i=0) then begin
        i:=1;
        strcopy(@buff2[k],'int');
        inc(k,3);
        inc(j);
      end else if (buff[j]='c')and(i=0) then begin
        i:=1;
        strcopy(@buff2[k],'char');
        inc(k,4);
        inc(j);
      end else if (buff[j]='v')and(i=0) then begin
        i:=1;
        strcopy(@buff2[k],'void');
        inc(k,4);
        inc(j);
      end else if (buff[j]='l')and(i=0) then begin
        i:=1;
        strcopy(@buff2[k],'long');
        inc(k,4);
        inc(j);
      end else if (buff[j]='u')and(buff[j+1]='i')and(i=0) then begin
        i:=1;
        strcopy(@buff2[k],'uint');
        inc(k,4);
        inc(j,2);
      end else if (buff[j]=':')and(buff[j+1]=':')and(i<>0) then begin
        strcopy(@buff2[k],'::');
        inc(k,2); inc(j,2);
      end else if (buff[j]='t')and((buff[j+1]>='0')and(buff[j+1]<='9'))and(i=0) then begin
        buff2[k]:=buff[j]; inc(k); inc(j);
        buff2[k]:=buff[j]; inc(k); inc(j);
        i:=1;
      end else if ((buff[j]>='0')and(buff[j]<='9'))and(i=0) then begin
        i:=byte(buff[j])-byte('0');
        inc(j);
        if (buff[j]>='0')and(buff[j]<='9') then begin
          i:=i*10+byte(buff[j])-byte('0'); inc(j);
        end;
        inc(i);
      end else begin buff2[k]:=buff[j]; inc(k); inc(j); end;
      if i<>0 then begin
        dec(i);
        if i=0 then begin
          if (pointer)and(buff2[k-1]<>')') then begin buff2[k]:='*'; inc(k); end;
          if (rpointer)and(buff2[k-1]<>')') then begin buff2[k]:='&'; inc(k); end;
          if (buff[j]<>')')and(buff2[k-1]<>')') then begin buff2[k]:=','; inc(k); end;
          pointer:=FALSE;
          rpointer:=FALSE;
        end;
      end;
    end;
    buff2[k]:=#0;
  end;
  namelen:=strlen(@buff2);
  //BugFix Build 15 nme-> *nme.
  dispose(nme);
  getmem(nam,namelen+1);
  strcopy(@nam,@buff2);
  nme:=@nam^;
end;

initialization
  import:=timports.create;
finalization
  import.free;
end.
