From: John on 23 Mar 2010 23:09 I have seen the topic of how to use the GNU readline(3c) procedure from Fortran come up several times. I tried it using the ISO_C_BINDINGS module from the (recent) g95(1) and gfortran(1) compilers. I had several surprises; I also succeeded in making a module for the entire VOGLE graphics library using the ISO_C_BINDINGS module; which lets me eliminate a good deal of C/ Fortran interface code that was always running into porting issues. The bindings work on at least the Intel, GNU, and G95 compilers. But it seemed more complex to pass strings around than I expected. 1) Hopefully, others will find this (albeit unpolished) version useful. 2) If anyone can try this with other compilers I would be interested in the results 3) Is there something I missed that would make this simpler? When I started, I thought it was going to take about 10 lines of coding to do this. If it builds for you, it prompts for a regular line of input read with a Fortran READ(), then it prompts for a line of input read with readline(3c). You can edit the line being read with readline(3c) per it's documentation. At a minimum, you can probably move around the line with the left and right arrow keys, and insert characters by typing them whereever you moved the cursor to, and use the DEL/ RUBOUT key to delete characters and such. If you use a GNU/Linux shell with command line editing, you are probably familiar with readline(3c)'s function. It quits if you enter 'q' on an input line, and it dumps the characters it sees in the read line with a little old routine called PDEC after a read so you can get a better idea of what you actually sent to the program; because if you start using the arrow keys and delete key and such on a regular READ(3F), what you see is very likely not what you get. For me, something like cc -c Freadline.c g95 rl.f90 Freadline.o -l readline -o rl ../rl works. After any feedback is incorporated and I clean it up a bit, I'll put this on the Fortran Wiki for anyone interested. # @(#) Call readline(3c) from Fortran using ISO_C_BINDING ################################################################################ # # The C routine Fcreadline.c # #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <readline/readline.h> #include <readline/history.h> FCreadline(int *len, char *myline, char *prompt){ /* @(#)FCreadline.sh return line from readline(3c) to Fortran. John S. Urban, 20100323 len -- number of characters in argument "myline" myline -- Fortran CHARACTER variable to recieve the line read by readline(3c) */ char *line; /* readline(3c) will return the read line to this pointer */ int i; /* counter for padding returned line with spaces */ /* use readline(3c) to read a line of input in edit mode */ line=readline(prompt); /* copy line returned by readline(3c) to MYLINE up to length of MYLINE */ strncpy(myline,line,(int)len); /* starting with null, pad with spaces to end */ for(i=strlen(line);i<(int)len;i++){ myline[i]=' '; } /* free memory used to return line from readline(3c) */ free(line); } ################################################################################ # # Fortran module # !------------------------------------------------------------------------------- module JSU_READLINE use ISO_C_BINDING implicit none private public iso_readline !------------------------------------------------------------------------------- ! define the call to the C routine ! extern char *Freadline(int ilen, char *buf, char *prompt); public :: Freadline interface subroutine Freadline(ILEN,BUF,PROMPT) bind(C,NAME='FCreadline') use ISO_C_BINDING implicit none integer(KIND=C_INT),intent(in),value :: ILEN character(KIND=C_CHAR),intent(out) :: BUF(*) character(KIND=C_CHAR),intent(in) :: PROMPT(*) end subroutine Freadline end interface !------------------------------------------------------------------------------- contains ! the routine that calls the C routine subroutine iso_readline(LINE,PROMPT) use ISO_C_BINDING implicit none !character(KIND=C_CHAR),intent(in) :: LINE(*) character*(*) LINE character*(*) PROMPT ! trim to last non-blank character and append null for C call Freadline(len(LINE),LINE,PROMPT(:len_trim(PROMPT))//achar(0)) end subroutine iso_readline !------------------------------------------------------------------------------- end module JSU_READLINE !------------------------------------------------------------------------------- ############################################################ # Fortran test program program testit use JSU_READLINE character(len=90):: line ilen=len(line) do ! regular fortran read write(*,'(a)',advance='no')'READ>' read(*,'(a)')line write(*,*) call pdec(line) ! show what Fortran got if(line.eq.'q') stop ! readline(3c) read call iso_readline(line,'READLINE>') ! read editable input line call pdec(line) ! show what Fortran got if(line.eq.'q') stop !call system(line) enddo ! =======================================================================-------- contains ! =======================================================================-------- ! @(#) write out a string with ASCII Decimal Equivalent (ADE) numbers under it subroutine pdec(string) character*(*) string ilen=len(string) ilen=len_trim(string(:ilen)) write(*,'(a)')string ! print line as-is ! replace lower unprintable characters with spaces write(*,101)(char(max(32,ichar(string(i:i)))),i=1,ilen) ! print ADE value of character underneath it write(*,202)(ichar(string(i:i))/100,i=1,ilen) write(*,202)(mod(ichar(string(i:i)),100)/10,i=1,ilen) write(*,202)(mod((ichar(string(i:i))),10),i=1,ilen) 101 format(9999a1:) 202 format(9999i1:) return end subroutine pdec ! =======================================================================-------- end program testit
From: Arjen Markus on 25 Mar 2010 05:30 On 24 mrt, 04:09, John <urbanj...(a)comcast.net> wrote: > I have seen the topic of how to use the GNU readline(3c) procedure > from Fortran come up several times. > I tried it using the ISO_C_BINDINGS module from the (recent) g95(1) > and gfortran(1) compilers. I had > several surprises; I also succeeded in making a module for the entire > VOGLE graphics library using the > ISO_C_BINDINGS module; which lets me eliminate a good deal of C/ > Fortran interface code that was always > running into porting issues. The bindings work on at least the Intel, > GNU, and G95 compilers. But it seemed > more complex to pass strings around than I expected. > 1) Hopefully, others will find this (albeit unpolished) version > useful. > 2) If anyone can try this with other compilers I would be > interested in the results > 3) Is there something I missed that would make this simpler? When I > started, I thought it was going to > take about 10 lines of coding to do this. > > If it builds for you, it prompts for a regular line of input read with > a Fortran READ(), then it prompts for a line > of input read with readline(3c). You can edit the line being read with > readline(3c) per it's documentation. At > a minimum, you can probably move around the line with the left and > right arrow keys, and insert characters > by typing them whereever you moved the cursor to, and use the DEL/ > RUBOUT key to delete characters and > such. If you use a GNU/Linux shell with command line editing, you are > probably familiar with readline(3c)'s > function. > > It quits if you enter 'q' on an input line, and it dumps the > characters it sees in the read line with a little old > routine called PDEC after a read so you can get a better idea of what > you actually sent to the program; because if you > start using the arrow keys and delete key and such on a regular > READ(3F), what you see is very likely not > what you get. > > For me, something like > cc -c Freadline.c > g95 rl.f90 Freadline.o -l readline -o rl > ./rl > > works. After any feedback is incorporated and I clean it up a bit, > I'll put this on the Fortran Wiki for anyone > interested. > > # @(#) Call readline(3c) from Fortran using ISO_C_BINDING > ################################################################################ > # > # The C routine Fcreadline.c > # > > #include <stdlib.h> > #include <unistd.h> > #include <stdio.h> > #include <string.h> > #include <readline/readline.h> > #include <readline/history.h> > FCreadline(int *len, char *myline, char *prompt){ > /* > @(#)FCreadline.sh return line from readline(3c) to Fortran. John S. > Urban, 20100323 > > len -- number of characters in argument "myline" > myline -- Fortran CHARACTER variable to recieve the line read by > readline(3c) > > */ > char *line; /* readline(3c) will return the read line to this > pointer */ > int i; /* counter for padding returned line with spaces */ > > /* use readline(3c) to read a line of input in edit mode */ > line=readline(prompt); > /* copy line returned by readline(3c) to MYLINE up to length of > MYLINE */ > strncpy(myline,line,(int)len); > > /* starting with null, pad with spaces to end */ > for(i=strlen(line);i<(int)len;i++){ > myline[i]=' '; > } > > /* free memory used to return line from readline(3c) */ > free(line); > > } > > ################################################################################ > # > # Fortran module > # > > !------------------------------------------------------------------------------- > module JSU_READLINE > use ISO_C_BINDING > implicit none > private > public iso_readline > !------------------------------------------------------------------------------- > ! define the call to the C routine > ! extern char *Freadline(int ilen, char *buf, char *prompt); > public :: Freadline > interface > subroutine Freadline(ILEN,BUF,PROMPT) bind(C,NAME='FCreadline') > use ISO_C_BINDING > implicit none > integer(KIND=C_INT),intent(in),value :: ILEN > character(KIND=C_CHAR),intent(out) :: BUF(*) > character(KIND=C_CHAR),intent(in) :: PROMPT(*) > end subroutine Freadline > end interface > !------------------------------------------------------------------------------- > contains > ! the routine that calls the C routine > subroutine iso_readline(LINE,PROMPT) > use ISO_C_BINDING > implicit none > !character(KIND=C_CHAR),intent(in) :: LINE(*) > character*(*) LINE > character*(*) PROMPT > ! trim to last non-blank character and append null for C > call Freadline(len(LINE),LINE,PROMPT(:len_trim(PROMPT))//achar(0)) > end subroutine iso_readline > !------------------------------------------------------------------------------- > end module JSU_READLINE > !------------------------------------------------------------------------------- > > ############################################################ > # Fortran test program > > program testit > > use JSU_READLINE > character(len=90):: line > > ilen=len(line) > > do > ! regular fortran read > write(*,'(a)',advance='no')'READ>' > read(*,'(a)')line > write(*,*) > call pdec(line) ! show what Fortran got > if(line.eq.'q') stop > > ! readline(3c) read > call iso_readline(line,'READLINE>') ! read editable input line > call pdec(line) ! show what Fortran got > if(line.eq.'q') stop > > !call system(line) > enddo > ! > =======================================================================-------- > contains > ! > =======================================================================-------- > ! @(#) write out a string with ASCII Decimal Equivalent (ADE) numbers > under it > subroutine pdec(string) > character*(*) string > ilen=len(string) > ilen=len_trim(string(:ilen)) > > write(*,'(a)')string ! print line as-is > ! replace lower unprintable characters with spaces > write(*,101)(char(max(32,ichar(string(i:i)))),i=1,ilen) > > ! print ADE value of character underneath it > write(*,202)(ichar(string(i:i))/100,i=1,ilen) > write(*,202)(mod(ichar(string(i:i)),100)/10,i=1,ilen) > write(*,202)(mod((ichar(string(i:i))),10),i=1,ilen) > 101 format(9999a1:) > 202 format(9999i1:) > return > end subroutine pdec > ! > =======================================================================-------- > end program testit It is a nice example of calling a less than trivial C function, but when you put it on the Fortran Wiki be sure to mention the licence for the readline library - it is GPL, if I am not mistaken and not everybody likes that. With a bit more work it should be possible to implement the functionality in pure Fortran, by the way (with a bit of help from the Linux/UNIX/... stty program) - see http://wiki.tcl.tk/20215 for an implementation in Tcl. Regards, Arjen
From: Julien Rioux on 25 Mar 2010 10:39 Hi John, It works really nicely over here. I tried the TAB completion feature and found that it lists the files in the current directory. So it seems to emulate a shell prompt somehow. How hard would it be to use the input history and autocompletion features of readline from Fortran? Cheers, Julien
From: John on 28 Mar 2010 02:00 On Mar 25, 10:39 am, Julien Rioux <julien.ri...(a)gmail.com> wrote: > Hi John, > > It works really nicely over here. I tried the TAB completion feature > and found that it lists the files in the current directory. So it > seems to emulate a shell prompt somehow. How hard would it be to use > the input history and autocompletion features of readline from > Fortran? > > Cheers, > Julien The readline(3c) does auto-completion and history vi and emacs mode and most of the other command-line "editing" options the GNU shells provide by default. I made a simple stab at activating the history mode and made the example a little cleaner and added the note/warning about readline(3c) being bound by the GPL license, and a "SEE ALSO" section pointing to the Tcl implementation, and some other links like rlwrap(1) and such and put it on the Fortran wiki at: http://fortranwiki.org/fortran/show/iso_readline(3f) The history mechanism setup I added is rudimentary, but should work. readline(3c) is a Tour de Force on CLI completion, history, and editing. I admit to using but a subset of what it does, but it's nice to use where I can live with the licensing. I have just begun using the ISO_C_BINDING module, so anyone that can improve the Wiki entry should feel quite free to do so. I use my own routines (JUCMD) quite frequently instead, but it pales in comparison, I suppose. In some cases, I actually use both, as they can co-exist. I "learned a few things" (hopefully correct things) about passing strings with the ISO_C_BINDING interface, so I hope the example is useful.
|
Pages: 1 Prev: Select a subset of equations at runtime Next: Vista available libraries |