macro_file IDEXE;

// #define _DEBUG_

#ifdef _DEBUG_
  #include DBUG.SH
  #include SPRINTF.SH
#endif

#include IDEXE.SH
#include METOOLS.SH


int IdExe( str Program = Parse_Str( "/P=", MParm_Str ) ) Trans2 {
/******************************************************************************
                               Multi-Edit Macro
                               24-Aug-94  13:59

  Name    : IdExe

  Function: Determines the type of Executable of the program named.  Can
            detect DOS, Windows, OS/2, NT and Bound Windows and Bound OS/2
            programs.

  Syntax  : ExeType = IdExe( ExeFile );

  Entry   : str Path          - Name of executable to check (Full path neede).

  Exit    : int               - Type of EXE
              _exe_Id_Unknown     Error or unknow type.
              _exe_Id_Dos         Dos program.
              _exe_Id_Windows     Windows programs (16bit)
              _exe_Id_Os2         OS/2 programs (16 and 32bit) and Dos PMode
              _exe_Id_Nt          NT programs (Maybe 32bit Windows?)
              _exe_Id_Bound       Specified a Dos bound program with a OS/2 or
                                  Windows.

  Globals : None.

  Macros  : None.

                 Copyright (C) 1994 by Small Systems Support.
********************************************************************( ldh )***/


  int Result = _exe_Id_Unknown;

  int Hn = 0;
  int Bound = _exe_Id_Unknown;
  int Lo;
  int Hi;

  str Ts[4];
  str Ext[ 3 ];

  if ( BaseOs == _BaseOs_Unknown ) {    // Set BaseOs global if not set
    BaseOs = _BaseOs_Dos;
    if ( IsOs2( ) ) {
      BaseOs = _BaseOs_Os2;
    }
    // Need to add checks for Windows95 and NT
  }
  Ext = Caps( Get_Extension( Program ) );
  if ( Ext == "BAT" ) {
    Result = _Exe_Id_Dos;
    return( Result );
  }
  if ( Ext == "CMD" ) {
    Result = _Exe_Id_Os2;
    return( Result );
  }
  if ( S_Open_File( Program, 0, Hn ) != 0 ) {  // Open file
    goto Exit;
  }
  S_Move_File_Ptr( Hn, 0, 0x18 );
  if ( S_Read_Bytes( Ts, Hn, 2 ) != 0 ) {  // Read the relocation table offset
    goto Exit;
  }
  if( Svl( Ts ) != 2 ) {
    goto Exit;
  }
  Lo = Ascii( Str_Char( Ts, 1 ) ) + ( Ascii( Str_Char( Ts, 2 ) ) << 8 );
  if ( Lo != 0x40 ) {                   // No new header
    Result = _Exe_Id_Dos;
  }
  else {
    S_Move_File_Ptr( Hn, 0, 0x06 );
    if ( S_Read_Bytes( Ts, Hn, 2 ) != 0 ) {  // Read the number of relocations
      goto Exit;
    }
    if( Svl( Ts ) != 2 ) {
      goto Exit;
    }
    Lo = Ascii( Str_Char( Ts, 1 ) ) + ( Ascii( Str_Char( Ts, 2 ) ) << 8 );
    if ( Lo != 0 ) {                    // Bound executable when relocations > 0
      Bound = _Exe_Id_Bound;
    }

    S_Move_File_Ptr( Hn, 0, 0x3C );
    if ( S_Read_Bytes( Ts, Hn, 4 ) != 0 ) {  // Read file address of new header
      goto Exit;
    }
    if( Svl( Ts ) != 4 ) {
      goto Exit;
    }
    Lo = Ascii( Str_Char( Ts, 1 ) ) + ( Ascii( Str_Char( Ts, 2 ) ) << 8 );
    Hi = Ascii( Str_Char( Ts, 3 ) ) + ( Ascii( Str_Char( Ts, 4 ) ) << 8 );
    Lo += Hi << 16;
    if ( Lo == 0 ) {
      goto Exit;
    }
    S_Move_File_Ptr( Hn, 0, Lo );
    if ( S_Read_Bytes( Ts, Hn, 2 ) != 0 ) {  // Read new header magic number
      goto Exit;
    }
    if( Svl( Ts ) != 2 ) {
      goto Exit;
    }
    switch ( Ts ) {

      case "NE" :                       // 16bit segmented header
        S_Move_File_Ptr( Hn, 1, 0x0A );
        if ( S_Read_Bytes( Ts, Hn, 2 ) != 0 ) {  // Read new flags
          goto Exit;
        }
        if( Svl( Ts ) != 2 ) {
          goto Exit;
        }
        Hi = Ascii( Str_Char( Ts, 1 ) ) + ( Ascii( Str_Char( Ts, 2 ) ) << 8 );
        S_Move_File_Ptr( Hn, 1, 0x28 );
        if ( S_Read_Bytes( Ts, Hn, 2 ) != 0 ) {  // Read os type
          goto Exit;
        }
        if( Svl( Ts ) != 2 ) {
          goto Exit;
        }
        Lo = Ascii( Str_Char( Ts, 1 ) );
        switch ( Lo ) {

          case 1 :                      // 16bit OS/2 (PMode DOS)
            if ( Bound && ( ( Hi & 0x0808 ) == 0x08 ) ) {  // Borland PMode
              if ( !( Ascii( Str_Char( Ts, 2 ) ) & 0x01 ) ) { // Longnames?
                Bound = _Exe_Id_Unknown;
                Result = _Exe_Id_Dos;
                break;
              }
            }
            Result = _Exe_Id_Os2;
            break;

           case 2 :                     // 16bit Windows
            Result = _Exe_Id_Windows;
            break;

           case 5 :                     // Borland PMode
           case 0x81 :                  // Blinker DOS Extender
            Bound = _Exe_Id_Unknown;
            Result = _Exe_Id_Dos;
            break;
        }
        break;

      case "LX" :                       // 32bit header (OS/2)
        S_Move_File_Ptr( Hn, 1, 0x08 );
        if ( S_Read_Bytes( Ts, Hn, 1 ) != 0 ) {  // Read os type
          goto Exit;
        }
        if ( Svl( Ts ) != 1 ) {
          goto Exit;
        }
        Lo = Ascii( Str_Char( Ts, 1 ) );
        switch ( Lo ) {

          case 1 :                      // 32bit OS/2
            Result = _Exe_Id_Os2;
            break;
        }
        break;

      case "PE" :                       // NT header, maybe 32bit Windows?
        Result = _Exe_Id_Nt;
        break;
    }
    Result |= Bound;
  }
//   MessageF( "AppType=%x Program=%s", Result, Program );     // dbug

Exit:
  if ( Hn != 0 ) {
    S_Close_File( Hn );
  }
  return ( Result );

}  // IdExe

int GetDosVersion( ) {
/******************************************************************************
                               Multi-Edit Macro
                               24-Aug-94  14:08

  Name    : GetDosVersion

  Function: Returns the version number of the running OS. (Major, Minor).

  Syntax  : Version = GetDosVersion( );

  Entry   : None


  Exit    : int     - Version of running OS.
                        (Major in High byte, Minor in Low byte)

  Globals : None.

  Macros  : None.

                 Copyright (C) 1994 by Small Systems Support.
**********************************************************************(ldh)***/


  int Result;

  R_AX = 0x3000;
  Intr( 0x21 );
  Result = ( ( R_AX >> 8 ) & 0xFF ) | ( ( R_AX & 0xFF ) << 8 );
  //MessageF( "%x DOS %d.%d", Result, R_AX & 0xFF, ( R_AX >> 8 ) & 0xFF ); //dbug
  return ( Result );

}  // GetDosVersion

int IsOs2 {
/******************************************************************************
                               Multi-Edit Macro
                               24-Aug-94  14:08

  Name    : IsOs2

  Function: Returns True if OS/2 is running.

  Syntax  : Os2Running = IsOs2( );

  Entry   : None.

  Exit    : int
              True  - OS/2 is running.
              False - OS/2 in NOT running.

  Globals : None.

  Macros  : int GetDosVersion

                 Copyright (C) 1994 by Small Systems Support.
**********************************************************************(ldh)***/

  int Result = GetDosVersion( );
  if ( Result > 0x140A ) {
    //MessageF( "OS/2 %d.%d is running.", ( R_AX & 0xFF ) / 10, R_AX >> 8 ); //dbug
    Result = True;
  }
  else {
   // Make_Message( "OS/2 is not running." );  // dbug
    Result = False;
  }
  return ( Result );

}  // IsOs2

void IdExeGetHdr( str Program = Parse_Str( "/P=", MParm_Str ) ) {
/******************************************************************************
                               Multi-Edit Macro
                               02-Feb-95  15:55

  Function: Read the header information from Program and write it to the
            IDEXE.BIN file.  This is used to help us identify programs that fail
            the IdExe classification tests and allow us to fix the macro to
            correctly identify Program.

  Entry   : str Program - The name of a program with full path.

               Copyright (C) 1995 by American Cybernectics, Inc.
********************************************************************( ldh )***/

  int OrgWin = Window_Id;
  int TRefresh = Refresh;
  int HdrFileWin = 0;
  int Hn = 0;
  int Jx;
  int NewHdrAddr = 0;
  int FirstLine;

  str HdrFileName = TempFileName( "IDEXE.BIN" );
  str Buffer = "";

  Refresh = False;
  if ( !Switch_File( HdrFileName ) ) {
    Create_Window;
  }
  Fixed_Line_Length = 16;
  if ( File_Exists( HdrFileName ) ) {
    Error_Level = 0;
    Load_File( HdrFileName );
    if ( Error_Level != 0 ) {
      Error_Level = 0;
      Goto Exit;
    }
  }
  HdrFileWin = Window_Id;
  File_Name = HdrFileName;
  Eof;
  if ( C_Col != 1 ) {
    Cr;
  }
  FirstLine = C_Line;
  if ( S_Open_File( Program, 0, Hn ) == 0 ) {  // Open file
    Buffer = '--' + Caps( Truncate_Path( Program ) );
    Pad_Str( Buffer, 0x10, '-' );
    Put_Line( Buffer );
    Down;
    if ( S_Read_Bytes( Buffer, Hn, 0x40 ) != 0 ) {
      goto Exit;
    }
    if( Svl( Buffer ) != 0x40 ) {
      goto Exit;
    }
    Put_Line( Buffer );
    Down;
    Buffer = '';
    Pad_Str( Buffer, 0x10, '-' );
    Put_Line( Buffer );
    Down;
    Mark_Pos;
    Goto_Line( FirstLine + 1 );
    Goto_Col( 0x18 + 1 );
    if ( Cur_Char == "\x40" ) {
      Goto_Col( 0x3C + 1 );
      for ( Jx = 0; Jx < 4; ++Jx ) {
        NewHdrAddr += Ascii( Cur_Char ) << ( Jx * 8 );
        Right;
      }
    }
    Goto_Mark;
    if ( NewHdrAddr != 0 ) {
//       MessageF( "Addr=%x", NewHdrAddr );
      if ( S_Move_File_Ptr( Hn, 0, NewHdrAddr ) == 0 ) {
        if ( S_Read_Bytes( Buffer, Hn, 0x40 ) == 0 ) {
          if( Svl( Buffer ) == 0x40 ) {
            Put_Line( Buffer );
            Down;
            Buffer = '';
            Pad_Str( Buffer, 0x10, '-' );
            Put_Line( Buffer );
            Down;
          }
        }
      }
    }
  }

Exit:
  if ( File_Changed ) {
    Save_File;
  }
  if ( Hn != 0 ) {
    S_Close_File( Hn );
  }
  if ( Window_Id != OrgWin ) {
    Delete_Window;
  }
  Switch_Win_Id( OrgWin );
  Refresh = TRefresh;

}  // IdExeGetHdr
