Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
235 Views

Ignoring windows Win32 APIs in linux

Jump to solution

I'm using ifwin in my program to control the position of the cursor in the console window in Windows.

How can I run the same program in Linux but force it to ignore all the calls in windows APIs, without me having to comment out all the relevant lines? Or is there even a more general way to accurately control the cursor position that would work in both Windows and Linux/

 

Thank you

Labels (2)
0 Kudos

Accepted Solutions
Highlighted
New Contributor II
157 Views

You can put Intel Fortran preprocessor directives anywhere in your program:

program test
    !dec$ if defined(__linux)
        print*, 'Hello from Linux'
    !dec$ else
        print*, 'Hello from Windows?'
    !dec$ end if
end program

Using them to set a Fortran variable, as you do with os (= "w"  or "l"), won't stop the compiler from attempting to compile subsequent lines that only get invoked for a particular value of os.  What you want to do is enclose any platform specific code in a conditionally compiled block, i.e.

    !dec$ if defined(__linux)
        ! Don't do anything here
    !dec$ else
        ! Windows specific code
    !dec$ end if

Note that our suggestion to use fpp directives rather than Intel specific pre-processor directives is in case you want to use a different compiler, say gfortran.

 

View solution in original post

0 Kudos
11 Replies
Highlighted
New Contributor II
204 Views

You could use the Fortran preprocessor, fpp (https://software.intel.com/content/www/us/en/develop/documentation/fortran-compiler-developer-guide-...) to conditionally compile Win32 API code on Windows only.

0 Kudos
Highlighted
195 Views
0 Kudos
Highlighted
Black Belt
183 Views

Recent versions of the windows console can support ansi escape sequences, which will also be supported on linux terminals.  Activating ansi support on the console requires a single console API call, which makes it very easy to isolate the operating system dependency.  Some of the alternative windows terminals support those sequences for all programs without the need for the console api call.

0 Kudos
Highlighted
Beginner
168 Views
Thanks for the answer, but how do I use them? I already use a preprocessor command to detect if I am in Linux or Windows but those are of no use in what I want to do, at least not the way I'm using them: !DEC$ IF DEFINED(__linux) os='l' !DEC$ ELSE os='w' !DEC$ ENDIF by the way, the commands I want to be ignored when run in linux are these: implicit none Type(T_COORD):: wpos Type(T_CONSOLE_SCREEN_BUFFER_INFO):: conbuf integer(8):: fhandle logical:: lstat (and the places where I use those variables in the program of course)
0 Kudos
Highlighted
New Contributor II
158 Views

You can put Intel Fortran preprocessor directives anywhere in your program:

program test
    !dec$ if defined(__linux)
        print*, 'Hello from Linux'
    !dec$ else
        print*, 'Hello from Windows?'
    !dec$ end if
end program

Using them to set a Fortran variable, as you do with os (= "w"  or "l"), won't stop the compiler from attempting to compile subsequent lines that only get invoked for a particular value of os.  What you want to do is enclose any platform specific code in a conditionally compiled block, i.e.

    !dec$ if defined(__linux)
        ! Don't do anything here
    !dec$ else
        ! Windows specific code
    !dec$ end if

Note that our suggestion to use fpp directives rather than Intel specific pre-processor directives is in case you want to use a different compiler, say gfortran.

 

View solution in original post

0 Kudos
Highlighted
Valued Contributor II
154 Views

The syntax for preprocessing with the option /fpp is illustrated below:

program fpp
#ifdef X
    write(*,*) 'Hello, X'
#else
    write(*,*) 'Hello, someone else'
#endif
end program fpp

You can define the macro  X via /D. For instance : ifort /DX /fpp fpp.f90 would define the macro X and the program will print the first line.

0 Kudos
Highlighted
Valued Contributor III
146 Views

You could also consider encapsulating the API calls inside specific routines that are in a specific source file and have a file with different of dummy routines for linux.

0 Kudos
Highlighted
Black Belt
134 Views

I very much prefer the approach of abstraction to a set of procedures in a set of platform specific files approach, mentioned by andrew_4619.  Put the logic operating system specific decisions into whatever build system you are using - build systems have to know what sort of operating system they are running on.  This can obviate use of the pre-processor entirely.

A simple example using that approach, also with an example of using ansi escape sequences, because I'm not sure what "them" refers to in "how do I use them?"

Operating system independent:

! In ansi.f90
PROGRAM Ansi
  USE ansi_support
  USE ansi_common
  IMPLICIT NONE
  
  CALL set_ansi
  
  PRINT "(A)",  &
      go_red()                    // 'H' //  &
      go_green()                  // 'e' //  &
      go_yellow()                 // 'l' //  &
      go_blue()                   // 'l' //  &
      go_magenta()  // go_down()  // 'o' //  &
      go_reset()
END PROGRAM WriteAnsi

! In ansi_common.f90
MODULE ansi_common
  IMPLICIT NONE
CONTAINS
  FUNCTION go_reset() RESULT(seq)
    CHARACTER(4) :: seq
    seq = ACHAR(27) // '[0m'
  END FUNCTION go_reset
  
  FUNCTION go_black() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[30m'
  END FUNCTION go_black
  FUNCTION go_red() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[31m'
  END FUNCTION go_red
  FUNCTION go_green() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[32m'
  END FUNCTION go_green
  FUNCTION go_yellow() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[33m'
  END FUNCTION go_yellow
  FUNCTION go_blue() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[34m'
  END FUNCTION go_blue
  FUNCTION go_magenta() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[35m'
  END FUNCTION go_magenta
  FUNCTION go_cyan() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[36m'
  END FUNCTION go_cyan
  FUNCTION go_white() RESULT(seq)
    CHARACTER(5) :: seq
    seq = ACHAR(27) // '[37m'
  END FUNCTION go_white
  
  FUNCTION go_up() RESULT(seq)
    CHARACTER(4) :: seq
    seq = ACHAR(27) // '[1A'
  END FUNCTION go_up
  FUNCTION go_down() RESULT(seq)
    CHARACTER(4) :: seq
    seq = ACHAR(27) // '[1B'
  END FUNCTION go_down
  FUNCTION go_forward() RESULT(seq)
    CHARACTER(4) :: seq
    seq = ACHAR(27) // '[1C'
  END FUNCTION go_forward
  FUNCTION go_back() RESULT(seq)
    CHARACTER(4) :: seq
    seq = ACHAR(27) // '[1D'
  END FUNCTION go_back
END MODULE ansi_common

(See one of the plethora  of online sources for details on the escape sequences.)

For windows, ansi_support looks like (should also be compilable by gfortran - if you used the ifort provided modules such as IFWIN, this would be shorter):

! In ansi_support-win.f90
MODULE ansi_support
  IMPLICIT NONE
CONTAINS
  SUBROUTINE set_ansi
    USE, INTRINSIC :: ISO_C_BINDING, ONLY:  &
        DWORD => C_LONG,  &    ! C_INT32_T really, but this is per the docs
        HANDLE => C_INTPTR_T,  &
        BOOL => C_INT
    
    INTEGER(HANDLE), PARAMETER :: INVALID_HANDLE_VALUE = -1_HANDLE
    
    INTERFACE
      FUNCTION GetStdHandle(nStdHandle) BIND(C, NAME='GetStdHandle')
        IMPORT :: DWORD
        IMPORT :: HANDLE
        IMPLICIT NONE
        INTEGER(DWORD), INTENT(IN), VALUE :: nStdHandle
        INTEGER(HANDLE) :: GetStdHandle
        !DEC$ ATTRIBUTES STDCALL :: GetStdHandle
        !GCC$ ATTRIBUTES STDCALL :: GetStdHandle
      END FUNCTION GetStdHandle
    END INTERFACE
    INTEGER(DWORD), PARAMETER :: STD_INPUT_HANDLE = -10_DWORD
    INTEGER(DWORD), PARAMETER :: STD_OUTPUT_HANDLE = -11_DWORD
    INTEGER(DWORD), PARAMETER :: STD_ERROR_HANDLE = -12_DWORD
    
    INTERFACE
      FUNCTION GetConsoleMode(hConsoleHandle, lpMode) BIND(C, NAME='GetConsoleMode')
        IMPORT :: HANDLE
        IMPORT :: DWORD
        IMPORT :: BOOL
        IMPLICIT NONE
        INTEGER(HANDLE), INTENT(IN), VALUE :: hConsoleHandle
        INTEGER(DWORD), INTENT(OUT) :: lpMode
        !DEC$ ATTRIBUTES REFERENCE :: lpMode
        INTEGER(BOOL) :: GetConsoleMode
        !DEC$ ATTRIBUTES STDCALL :: GetConsoleMode
        !GCC$ ATTRIBUTES STDCALL :: GetConsoleMode
      END FUNCTION GetConsoleMode
    END INTERFACE
    INTEGER(DWORD), PARAMETER :: ENABLE_ECHO_INPUT = INT(Z'0004', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_INSERT_MODE = INT(Z'0020', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_LINE_INPUT = INT(Z'0002', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_MOUSE_INPUT = INT(Z'0010', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_PROCESSED_INPUT = INT(Z'0001', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_QUICK_EDIT_MODE = INT(Z'0040', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_WINDOW_INPUT = INT(Z'0008', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_VIRTUAL_TERMINAL_INPUT = INT(Z'0200', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_PROCESSED_OUTPUT = INT(Z'0001', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_WRAP_AT_EOL_OUTPUT = INT(Z'0002', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_VIRTUAL_TERMINAL_PROCESSING = INT(Z'0004', DWORD)
    INTEGER(DWORD), PARAMETER :: DISABLE_NEWLINE_AUTO_RETURN = INT(Z'00008', DWORD)
    INTEGER(DWORD), PARAMETER :: ENABLE_LVB_GRID_WORLDWIDE = INT(Z'0010', DWORD)
    
    INTERFACE
      FUNCTION SetConsoleMode(hConsoleHandle, dwMode) BIND(C, NAME='SetConsoleMode')
        IMPORT :: HANDLE
        IMPORT :: DWORD
        IMPORT :: BOOL
        IMPLICIT NONE
        INTEGER(HANDLE), INTENT(IN), VALUE :: hConsoleHandle
        INTEGER(DWORD), INTENT(IN), VALUE :: dwMode
        INTEGER(BOOL) :: SetConsoleMode
        !DEC$ ATTRIBUTES STDCALL :: SetConsoleMode
        !GCC$ ATTRIBUTES STDCALL :: SetConsoleMode
      END FUNCTION SetConsoleMode
    END INTERFACE
    INTEGER(DWORD), PARAMETER :: ENABLE_EXTENDED_FLAGS = INT(Z'0080', DWORD)
    
    INTEGER(HANDLE) :: output_handle
    INTEGER(BOOL) :: api_result
    INTEGER(DWORD) :: mode
    
    output_handle = GetStdHandle(STD_OUTPUT_HANDLE)
    IF (output_handle == INVALID_HANDLE_VALUE) THEN
      ERROR STOP 'GetStdHandle failed'
    END IF
    
    api_result = GetConsoleMode(output_handle, mode)
    IF (api_result == 0_BOOL) THEN
      ERROR STOP 'GetConsoleMode failed'
    END IF
    
    api_result = SetConsoleMode(  &
        output_handle,  &
        IOR(mode, ENABLE_VIRTUAL_TERMINAL_PROCESSING) )
    IF (api_result == 0_BOOL) THEN
      ERROR STOP 'SetConsoleMode failed'
    END IF
  END SUBROUTINE set_ansi
END MODULE ansi_support

 

On linux, the corresponding module is a bit shorter....

! In ansi_support-other.f90
MODULE ansi_support
  IMPLICIT NONE
CONTAINS
  SUBROUTINE set_ansi
    ! Does nothing.
  END SUBROUTINE set_ansi
END MODULE ansi_support

 

Compile on windows (using my advanced build system - the command prompt):

ifort /exe:ansi.exe ansi_common.f90 ansi_support-win.f90 ansi.f90

 

On linux substitute ansi_support-other.f90 for ansi_support-win.f90.

 

Highlighted
Black Belt Retired Employee
126 Views

Every time I see references to ANSI escape sequences, I fondly remember the DEC VT100 terminal, the first to support them and so popular that people referred to "VT100 escape sequences".

--
Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
Valued Contributor II
98 Views

This library does not seem to provide cursor control, but it might be useful for other features of ANSI escape sequences - http://foul.sourceforge.net/

0 Kudos
Highlighted
Beginner
60 Views

@Mark_Lewy 

Thank you. I didn't know you could put those everywhere in the program, even before implicit none.

I understand it will not be compatible with other compilers other than Intel Fortran but it will do for now until I eventually use the fpp directives

0 Kudos