Clicky

Fortran Wiki
f_uname

Skip the Navigation Links | Home Page | All Pages | Recently Revised | Authors | Feeds | Export |

** A simple combination of a C routine and a Fortran module bound via the ISO_C_BINDING module that allows you to call uname(3C) from Fortran. **

I have seen several forums where how to query the system type at runtime from Fortran has come up where the offered solutions often involve creating a subprocess and calling uname(1) and either returning the output via a scratch file or a pipe instead of calling the uname(3C) routine directly, which is my preference. Calling the C routine directly using the following method has worked for me with several different compiler/OS programming environments (and several initial attempts did not). This model works with many C routines that I just want to return a simple string to Fortran with.

Feel free to alter this example. I think we could all benefit from a collection of ISO_C_BINDING examples. I know I could.


/* -------------------------------------------------------------------------- */
/* f_uname -- return system information from uname(3c) to Fortran subroutine
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/utsname.h>
/* -------------------------------------------------------------------------- */
void f_uname (char *which, char *string, int *stringlen) {
/* f_uname(3c) returns one element of the structure returned by 
 uname(3c) as a string suitable for return to Fortran. 
*/
 struct utsname name;
 int i;
 int j;
 if (uname (&name) == -1) {
 fprintf (stderr, "*f_uname* cannot get system name\
");
 strncpy (string, "UNKNOWN", *stringlen);
 } else {
 switch (*which) {
 case 's': strncpy (string, name.sysname, *stringlen);
	 break;
 case 'n': strncpy (string, name.nodename, *stringlen);
	 break;
 case 'r': strncpy (string, name.release, *stringlen);
	 break;
 case 'v': strncpy (string, name.version, *stringlen);
	 break;
 case 'm': strncpy (string, name.machine, *stringlen);
	 break;
 case 'T': /* for testing */
	 fprintf (stderr, "*f_uname* sysname: %s\n", name.sysname);
	 fprintf (stderr, "*f_uname* nodename: %s\n", name.nodename);
	 fprintf (stderr, "*f_uname* release: %s\n", name.release);
	 fprintf (stderr, "*f_uname* version: %s\n", name.version);
	 fprintf (stderr, "*f_uname* machine: %s\n", name.machine);
	 strncpy (string, "", *stringlen);
	 break;
 default:
	 fprintf (stderr, "*f_uname* E-R-R-O-R: unknown switch %c \n",
		 *which);
	 fprintf (stderr, "*f_uname* f_uname:%s:%c:%d\n", string, *which,
		 *stringlen);
	 strncpy (string, "UNKNOWN", *stringlen);
 }
 }
 /* 
 remove null string terminator and fill string with blanks for Fortran 
 */
 for (j = strlen (string); j < *stringlen; j++) {
 string[j] = ' ';
 }
}
#ifdef TESTPRGC
#include <stdio.h>
#include <stdlib.h>
main(){
 char string[20];
 int ii;
 ii=20;
 f_uname("m",string,&ii);
 fprintf (stderr, "C TEST PROGRAM:f_uname:AFTER:%s\
", string);
 exit(0);
}
#endif

`

module m_os
!-------------------------------------------------------------------
! describe the C routine to Fortran
! void f_uname(char *which, char *buf, int *buflen);
 public :: f_uname_F
 interface
 subroutine f_uname_F(WHICH,BUF,BUFLEN) bind(C,NAME='f_uname')
 use ISO_C_BINDING
 implicit none
 character(KIND=C_CHAR),intent(out) :: BUF(*)
 character(KIND=C_CHAR),intent(in) :: WHICH
 integer,intent(in) :: BUFLEN
 end subroutine f_uname_F
 end interface
!-------------------------------------------------------------------
contains
!-------------------------------------------------------------------
subroutine f_uname(WHICH,NAME)
 use ISO_C_BINDING
 implicit none
 character(KIND=C_CHAR),intent(in) :: WHICH
 character(len=*) :: NAME
 NAME='unknown'
 call f_uname_F(WHICH,NAME,LEN(NAME))
end subroutine f_uname
!-------------------------------------------------------------------
end module m_os
!-------------------------------------------------------------------
#ifdef TESTPRG90
program testit
 use m_os
 implicit none
 integer,parameter :: is=100
 integer :: i
 character(len=:),parameter :: letters='srvnmxT'
 character(len=is) :: string=' '
 do i=1,len(letters)
 write(*,'(80("="))')
 call f_uname(letters(i:i),string)
 write(*,*)'=====> TESTING f_uname('//letters(i:i)//')--->'//trim(string)
 enddo
end program testit
!-------------------------------------------------------------------
#endif

The compiler switches vary depending on the Programming Environment, but in mine (where f90(1) is a script that takes such differences into account) the routine can be tested using

 cc -c f_uname.c 
 f90 -DTESTPRG90 m_os.F90 f_uname.o -o _testit
 `./_testit # execute test Fortran program

category: code

Revised on March 1, 2023 13:12:09 by Jason Blevins (23.245.217.121) (5122 characters / 2.0 pages)
Edit | Back in time (3 revisions) | See changes | History | Views: Print | TeX | Source | Linked from: Code

AltStyle によって変換されたページ (->オリジナル) /