Hi,

I've been trying to pass a character vector from R to a FORTRAN subroutine. There have been several posts discussing this issue (e.g. http://tolstoy.newcastle.edu.au/R/help/98a/0547.html, http://tolstoy.newcastle.edu.au/R/help/05/10/13558.html, http://tolstoy.newcastle.edu.au/R/help/01a/2577.html, http://tolstoy.newcastle.edu.au/R/help/01c/1795.html, http://tolstoy.newcastle.edu.au/R/devel/03a/0620.html, http://tolstoy.newcastle.edu.au/R/devel/99b/0323.html). According to R-exts (section 5.2, Interface functions .C and .Fortran), there are severe limitations on this: "Only the first element of the character vector is passed in, as a fixed-length (255) character array".

I think there may be a work-around, although I'm no FORTRAN expert, and I would like to hear your thoughts about it. The basic idea is to convert the strings to integers, transfer the resulting integer vector to FORTRAN, and then convert back to characters. Here's an example:

####### start of fortran code
       subroutine readchar(intstring,stringlengths,totalnchar,nstrings)
       implicit none
C     global variables
       integer totalnchar,nstrings
       integer intstring(totalnchar),stringlengths(nstrings)
C     local variables
       integer j,count, stringLength, i1, i2
       parameter(stringLength = 1000)
       character c*(stringLength)
C     functions, etc.
       intrinsic char,min

c     convert from integer to character
       do j = 1,min(stringLength,totalnchar)
          write(c(j:j),'(A)') char(intstring(j))
       end do

       count=0
       do j = 1,nstrings
          i1 = (count+1)
          i2 = min(count+stringlengths(j),stringLength)
c     print the jth string
          write(*,*) c(i1:i2)
c     add a blank line after it
          write(*,*)
          count = count+stringlengths(j)
c     avoid reading past the bounds of the character variable
          if(count .ge. stringLength) then
             goto 10
          end if
       end do

 10    continue

       return
       end
####### end of fortran code

####### start of R code
strings <- c("donald duck",
             "When trying to express oneself, it's frankly quite absurd,
To leaf through lengthy lexicons to find the perfect word.
A little spontaniaty keeps conversation keen,
You need to find a way to say, precisely what you mean...
Supercalifragilisticexpialidocious!
Even though the sound of it is something quite atrosicous!
If you say it loud enough, you'll always sound precocious",
             " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")

system('R CMD SHLIB readchar.f')

dyn.load('readchar.so')
A <- .Fortran('readchar',
              as.integer(unlist(sapply(strings,charToRaw),use.names=FALSE)),
              as.integer(nchar(strings)),
              as.integer(sum(nchar(strings))),
              as.integer(length(strings)))

dyn.unload('readchar.so')
####### end of R code

Running this gives:

> strings <- c("donald duck",
+              "When trying to express oneself, it's frankly quite absurd,
+ To leaf through lengthy lexicons to find the perfect word.
+ A little spontaniaty keeps conversation keen,
+ You need to find a way to say, precisely what you mean...
+ Supercalifragilisticexpialidocious!
+ Even though the sound of it is something quite atrosicous!
+ If you say it loud enough, you'll always sound precocious",
+              " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
>
> system('R CMD SHLIB readchar.f')
g77   -fpic  -g -O2 -c readchar.f -o readchar.o
gcc -std=gnu99 -shared -L/usr/local/lib64 -o readchar.so readchar.o  -lg2c -lm
>
> dyn.load('readchar.so')
> A <- .Fortran('readchar',
+               as.integer(unlist(sapply(strings,charToRaw),use.names=FALSE)),
+               as.integer(nchar(strings)),
+               as.integer(sum(nchar(strings))),
+               as.integer(length(strings)))
 donald duck

 When trying to express oneself, it's frankly quite absurd,
To leaf through lengthy lexicons to find the perfect word.
A little spontaniaty keeps conversation keen,
You need to find a way to say, precisely what you mean...
Supercalifragilisticexpialidocious!
Even though the sound of it is something quite atrosicous!
If you say it loud enough, you'll always sound precocious

  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

>
> dyn.unload('readchar.so')
>

One obvious weakness is that you have to specify in advance the maximum number of characters that can be passed to the subroutine. Another possible problem is that this maximum may be also be rather limited (e.g. one fortran 77 guide says that it is system-dependent, and while 255 characters should be safe, many systems allow up to 32767 characters: http://www.star.le.ac.uk/~cgp/prof77.html#tth_sEc5.1).

Despite these weaknesses, it looks like (at least on some systems) it is possible to pass character vectors to FORTRAN subroutines, avoiding the restrictions suggested in R-Exts. In the above example, several strings are passed to the subroutine, and one of them is longer than the 255 character limit (as noted in R-Exts). It also suggests obvious ways character data can be passed back into R.

But I admit, it is a bit of a hack...

Jeremy Silver



	[[alternative HTML version deleted]]


