- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If I have a character*72 Name
and Name is all blank characters coming in from a file from another program - how do I test for blankness --
Ta
John
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The rules of Fortran provide truncation or blank padding, as needed, when a character variable is assigned a value from a character expression and the lengths do not match.
Try
program blank character(len=72) :: bl1, bl2 bl1 = repeat(' ',72) bl2 = ' ' print *, bl1 == bl2 end program
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello
name.eq." "
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
!---------------------------------------------------------- ! St7APIDemo.f90 !---------------------------------------------------------- ! This example demonstrates the Visual Fortran link to ! the Strand7/Straus7 API. The program loads St7API.DLL, ! opens a requested file and then runs the linear static ! solver. ! ! To successfully run this program, the location of ! the dynamic link library "ST7API.DLL" must be added to ! the Windows PATH environment variable. ! ! This program was successully compiled and run using: ! - Intel Visual Fortran 10.0 ! - Compaq Visual Fortran 6.6.0 !---------------------------------------------------------- PROGRAM St7ApiDemo ! Use the API interface and constants modules USE St7APICall USE St7APIConst IMPLICIT NONE ! Declaration of local variables INTEGER(4) :: iNode,nNode,nBeam,nPlate,nBrick,nMax,iErr,i integer(4) :: NewNode,nBricks, iBrick, BrickID,iConn(9),propNum, iPlate,nPlates integer(4) :: iConnPL(5) REAL(8) :: XYZ(3) LOGICAL :: Loaded Logical :: Exists CHARACTER(72) :: fName character(len=72) :: sAuthor,sTitle character(len=72) :: bl1, bl2 ! Load the API write(*,1000) 1000 Format(/"------------------------------------------------------------------------------------------------------"/) Write(*,100) 100 Format(//" Program to make Strand 7 Changes",//) CALL LoadSt7API(Loaded) IF (Loaded) then Write(*,300) 300 Format(" ST7API.DLL loaded successfully.") ELSE TYPE *, "Cannot load ST7API.DLL." TYPE *, "Press <Enter>" READ(*,*) STOP ENDIF ! Initialise the API iErr = St7Init() IF (iErr == ERR7_NoError) THEN Write(*,500) 500 Format(" API initialisation successful.") ELSE TYPE *, "Error initialising the API." TYPE *, "Press <Enter>" READ(*,*) STOP ENDIF WRITE(*,10) 10 FORMAT(1X,/,' Name of the input file please : ',\) READ(*,20)fName 20 format(a12) Inquire(FILE = fName, Exist=Exists) if(Exists .eq. .FALSE.) then Stop " File does not exist" endif ! Open a user-selected ST7 file iErr = St7OpenFile(1,fName,"c:\\temp"C) IF (iErr /= ERR7_NoError) THEN write(*, 200) iErr 200 Format(" St7OpenFile returned error #",3x, I4) TYPE *, " Requested file cannot be opened." TYPE *, " Press <Enter>\" READ(*,*) STOP ELSE Write(*,400) 400 Format(/" File successfully opened.") ENDIF ! Obtain and display the entity totals CALL ChkErr(St7GetTotal(1,tyNODE,nNode)) CALL ChkErr(St7GetTotal(1,tyBEAM,nBeam)) CALL ChkErr(St7GetTotal(1,tyPLATE,nPlate)) CALL ChkErr(St7GetTotal(1,tyBRICK,nBrick)) write(*,1000) Write(*,600) 600 Format(" FILE ENTITY TOTALS:") Write(*,700)nNode 700 Format(" Total Nodes :: ", I8) Write(*,800)nBeam 800 Format(" Total Beams :: ", I8) Write(*,900)nPlate 900 Format(" Total Plates :: ",I8) Write(*,1100)nBrick 1100 Format(" Total Bricks :: ",I8) ! Obtain and display some string titles CALL ChkErr(St7GetTitle(1,TITLEAuthor,sAuthor,72)) CALL ChkErr(St7GetTitle(1,TITLEModel,sTitle,72)) write(*,1000) Write(*,1500) bl1 = repeat(' ',72) bl2 = ' ' 1500 Format(" File Author Details") print *, sAuthor == bl1 if(sAuthor == bl1)then print *, sAuthor == bl1 stop " No Author" endif Write(*,1600)sAuthor 1600 Format(" File author :: ",(A)) Write(*,1700)sTitle 1700 Format(" File title :: ",(A)) write(*,1000) ! Display the coordinates of a few nodes IF (nNode.gt.0) THEN nMax = nNode Write(*,1800) 1800 format(" POSITION OF FIRST NODE") DO iNode = 1, 1 iErr = St7GetNodeXYZ(1,iNode,XYZ) Write(*,1900)XYZ(1),XYZ(2),XYZ(3) 1900 Format(" X :: ",F10.3,/," Y :: ",F10.3,/," Z :: ",F10.3) end do Write(*,2000) 2000 format(" Position of First Copied Node") DO iNode = 1, nMax iErr = St7GetNodeXYZ(1,iNode,XYZ) NewNode = iNode + nMax XYZ(1) = XYZ(1) - 9.590 XYZ(2) = XYZ(2) + 0.548 XYZ(3) = XYZ(3) + 23.09 iErr = St7SetNodeXYZ(1,NewNode,XYZ) if(iNode .eq. 1) then Write(*,2100)XYZ(1),XYZ(2),XYZ(3) endif 2100 Format(" X :: ",F10.3,/," Y :: ",F10.3,/," Z :: ",F10.3) end do ENDIF If(nBrick .gt. 0) then Write(*,2200) 2200 format(" Copy the Brick Element Details.") nBricks = nBrick do iBrick = 1, nBricks iErr = St7GetBrickID(1,iBrick,BrickID) iErr = St7GetElementConnection(1,tyBRICK,iBrick,iConn) iErr = St7GetElementProperty(1,tyBrick,iBrick,propNum) do i = 2,9 iConn(i) = IConn(i) + nMax end do iErr = St7SetElementConnection(1, tyBrick, iBrick + NBricks, propNum, iConn) !write(*,*)iBrick,BrickID end do Write(*,2400) 2400 format(" Add the Brick Element Details.") nBricks = nBrick do iBrick = 1, nBricks iErr = St7GetBrickID(1,iBrick,BrickID) iErr = St7GetElementConnection(1,tyBRICK,iBrick,iConn) iErr = St7GetElementProperty(1,tyBrick,iBrick,propNum) do i = 2,9 iConn(i) = IConn(i) + nMax if(iConn(i) .eq. 46781) then if(i .eq. 2 .or. i .eq. 3 .or. i .eq. 4 .or. i .eq. 5) then Call NewBox(iConn(2), iConn(3), iConn(4),iConn(5),nMax) stop else endif endif end do end do endif if(nPlate .gt. 0) then Write(*,2300) 2300 Format(" Copy the Plate Element Details") nPlates = nPlate do iPlate =1,nPlates iErr = St7GetPlateID(1,iPlate,BrickID) iErr = St7GetElementProperty(1,tyPlate,iPlate,propNum) iErr = St7GetElementConnection(1,tyPlate,iPlate,iConnPL) do i = 2,5 iConnPL(i) = IConnPL(i) + nMax end do iErr = St7SetElementConnection(1, tyPlate, iPlate + nPlates, propNum, iConnPL) write(*,*)iPlate,BrickID,propNum end do endif ! Run the Linear Static Solver !iErr = St7RunSolver(1,stLinearStaticSolver,smNormalRun,1) !IF (iErr == ERR7_NoError) THEN ! TYPE *, "Linear Static Solver successfully run." ! E!LSE ! TYPE *, "Solver returned error #",iErr ! ENDIF ! TYPE *, "Press <Enter>" ! READ(*,*) ! Close the ST7 file iErr = St7SaveFile(1) iErr = St7CloseFile(1) ! Unload the API CALL FreeSt7API write(*,3000) 3000 Format( " End of Program.") END PROGRAM St7ApiDemo Subroutine NewBox(i1,i2,i3,i4,NodeMax) implicit none Integer(4) :: i1,i2,i3,i4,NodeMax Write(*,*)i1,i2,i3,i4,NodeMax return end subroutine Does not work - although your examples does -- here is the code it has a lock dongle so I cannot send all . ! This routine uses St7GetAPIErrorString to return the ! error message associated with any errors found. ! All St7API.DLL function calls return an integer to ! signify whether the function was successful. ! If the return is zero, the function was successful. SUBROUTINE ChkErr(iErr) USE St7APICall USE St7APIConst INTEGER(4), INTENT(IN) :: iErr INTEGER(4) :: iTemp CHARACTER(128) :: ErrorString IF (iErr /= ERR7_NoError) THEN ErrorString = "" iTemp = St7GetAPIErrorString(iErr, ErrorString, kMaxStrLen) TYPE *, TRIM(ErrorString) ENDIF END SUBROUTINE ChkErr
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Without having the modules USEd in your source, we cannot run the compiler on your program. A specific question: if the vendor library is written in C, does it expect null-terminated strings, or does it know how to handle Fortran strings and the semi-hidden Fortran string length arguments? Without that awareness, the API C routines may go looking for those non-existing null characters. On the Fortran side, an embedded null character has no special significance, and a string with all blanks will not match a string with all blanks except for a null somewhere in the middle. Embedded white-space characters (tab, form-feed, space, CR, LF,..) will pose similar problems.
Note also that CVF and Intel Fortran have default conventions on how to pass those hidden arguments. See https://software.intel.com/en-us/node/679043 .
Try this to see the effect of nulls:
program blank character(len=72) :: bl1, bl2 bl1 = repeat(' ',72) bl2 = ' ' print *, bl1 == bl2 bl1(36:36) = char(0) print *, bl1 == bl2 end program
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello
I agree with mecje4
St7GetAPIErrorString(iErr, ErrorString, kMaxStrLen)
The kMaxStrlen argument lets suppose that the function returns a C string (null terminated). You can try to use ErrorString[1:1]==char(0) or strlen(ErrorString)==0 to test if the returned C string is empty.
When you ask for help, it's better to give the context of your question in the first post. Answers will be more pertinent.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear mecej4 and Giles:
Thank you for the answers. The program is called STRAND7 and is written in Australia as a FEM Analysis package. As far back as I can remember it was written in Fortran or so the legend goes. I have continued to assume that it is written in Fortran but it appears I am wrong. I cannot send the APIDLL's as a Strand DLL supported program will not run without the dongle, I have had this problem before the Strand people are paranoid about unlicensed use of their stuff. I had typed comments into the last post, but they appear to have got lost in the translation.
I should have thought of the null terminated string, never crossed my mind. I need to test the string for individual characters - thanks for the help.
PS: If any of you live in London, there is now a simple device monitoring one of the London bridges, it should be running in Linux on a NUC, but it is running on Windows on a HP Pavilion. You should always write code late on a Sunday night onto a computer in London to be deployed the following morning, that is to be locked away for three months, and has to function completely stand alone. Gotta love it.
John
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
An empty C string has its first character set to 0. So testing only the first character will detect an empty string:
if (string(1:1)==char(0)) then ! empty string
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Don't need a dongle just to read the API manual, which we can find at http://www.strand7.com/downloads/Strand7%20R246%20API%20Manual%20TOC.pdf .
In that manual, it clearly says, on page 11,
API Strings and Visual Fortran
The Strand7 API uses null-terminated strings. These are always declared as
CHARACTER(LEN=*) in the interface section (St7APICall.f90), and are passed by
reference. Strings will be declared in your program as CHARACTER(LEN=255) (for
example). An API call returning the string will null-terminate the string with CHAR=0 at
some point. All character values beyond this point will be undefined.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quite true. I should not have missed that -- thank you.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John Nichols wrote:
.. how do I test for blankness ..
@John Nichols,
I suggest string length of zero be your test for "blankness". And this: if you're dealing with CHARACTER variables in Fortran that are interfacing with C type of APIs, meaning null-termination in C can be involved, then you should use strnlen function from C runtime library to get the string length. Otherwise, use the LEN_TRIM intrinsic function in Fortran:
module m use, intrinsic :: iso_c_binding, only : c_char, c_null_char implicit none private public :: Some_C_API contains subroutine Some_C_API( s ) bind(C, name="Some_C_API") character(kind=c_char,len=1), intent(inout) :: s(*) s(1) = c_null_char return end subroutine Some_C_API end module m
program p use, intrinsic :: iso_c_binding, only : c_char, c_size_t use m, only : Some_C_API implicit none interface function strnlen( s, maxlens ) result( lens ) bind(C, name="strnlen") import :: c_char, c_size_t implicit none !.. Argument list character(kind=c_char,len=1), intent(in) :: s(*) integer(c_size_t), intent(in) :: maxlens !.. Function result integer(c_size_t) :: lens end function strnlen end interface integer(kind=c_size_t), parameter :: MAXLEN = 255 character(len=MAXLEN) :: bl1 character(len=MAXLEN) :: bl2 character(kind=c_char,len=MAXLEN) :: bl3 bl1 = repeat( " ", MAXLEN ) bl2 = " " call Some_C_API( bl3 ) print *, "len_trim(bl1) = ", len_trim(bl1) print *, "len_trim(bl2) = ", len_trim(bl2) print *, "strnlen(bl3) = ", strnlen(bl3, MAXLEN) stop end program p
Upon execution with Intel Fortran,
len_trim(bl1) = 0 len_trim(bl2) = 0 strnlen(bl3) = 0
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John,
Also note in FortranFan's example, if you add at line 38
print *, "len_trim(bl3) = ", len_trim(bl3) ! length of empty "C" string with NULL
That the result with show 1
IOW, if you intend to use the string in the Fortran portion, you might want to inspect the len_trim'th character for NULL and take that into consideration. As to what action you want to take, it is up to you. Also, do not overwrite the C original string null with ' ' as this may corrupt the C visible string. You can overwrite the null in any copy you make in the Fortran space.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim and FF:
Thank you for the code. The original code is a very basic example in Fortran for interfacing with the Strand7 API. Strand7 is an FEM modeller.
I had tried to use this once before but the dongle issues got in the road. However a young scientist and I have been modelling an interesting structure using two different FEM codes to make sure the answers match as closely as possible our real data. It is a challenge as the structure is interconnected in weird ways that make simple models impossible and block models challenging. I needed to copy elements of the model involving plates and blocks, but the STRAND7 GUI left some elements behind in the copy -- a real pain. I thought I would try the API and it turned out to be quite good and for the simple copies we want easy to code.
The code include the example to print out the titles etc, but I kept getting two lines printed even though the string appeared empty in VS Studio debug mode. Hence my question about blanks as the debug showed a string about 20 characters long with nothing in it, I had heard many years ago that Strand was written in Fortran - I was quite slow in not picking up the notes in the API manual as I had looked at this manual to see the C String.
My code to check for zero length looks for the Char(0) called ASC in the code as a variable name. This is quick and dirty code to solve a simple problem, so I used a simple method, really should clean it up.
Thanks for all the help -- I am not sure how I would survive without this forum.
Code I used - very dirty and very simple
do i = 1, 72 if(sAuthor(i:i) == ASC) then Flag(1) = Flag(1) + 1 endif if(sTitle(i:i) == ASC) then Flag(2) = Flag(2) + 1 endif if(sProject(i:i) == ASC) then Flag(3) = Flag(3) + 1 endif if(sCreate(i:i) == ASC) then Flag(4) = Flag(4) + 1 endif end do write(*,1000) Write(*,1500) 1500 Format(" File Author Details", i5) if(Flag(1) .eq. 72) then sAuthor = "Project Author not provided for file." Write(*,2800)(72-Flag(1)),sAuthor 2800 Format(" File Author :: ","[",I2,"] ",(A)) else Write(*,1600)(72-Flag(1)),sAuthor 1600 Format(" File author :: ","[",I2,"] ",(A)) endif if(Flag(2) .eq. 72) then sTitle = "Project Title not provided for file." Write(*,1700)(72-Flag(1)),sTitle else Write(*,1700)(72-Flag(2)),sTitle 1700 Format(" File title :: ","[",I2,"] ",(A)) endif if(Flag(3) .eq. 72) then sProject = "Project Title not provided for file." Write(*,2700)(72-Flag(3)),sProject 2700 Format(" File project :: ","[",I2,"] ",(A)) else Write(*,2500)(72-Flag(3)),sProject 2500 Format(" File project :: ","[",I2,"] ",(A)) endif Write(*,2600)(72-Flag(4)),sCreate 2600 Format(" File created :: ","[",I2,"] ",(A))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Why do you expect 72 NULLs for an empty field? An empty field is presumably a field with a NULL in position (1) .OR. the pointer/reference being NULL. The C program might not zero-fill the transfer buffer prior to inserting the text.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
jimdempseyatthecove wrote:
Why do you expect 72 NULLs for an empty field? An empty field is presumably a field with a NULL in position (1) .OR. the pointer/reference being NULL. The C program might not zero-fill the transfer buffer prior to inserting the text.
Jim Dempsey
True -- I could have just checked the first place, I did in the beginning, but I got carried away.
No one said you could not have fun --
Merry Christmas
John
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Vautier, Gilles wrote:
An empty C string has its first character set to 0. So testing only the first character will detect an empty string:
if (string(1:1)==char(0)) then ! empty string
Exactly what I said earlier.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just out of interest could a Fortran String include a chr(0) as a legal entity - but not be the end?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John Nichols wrote:
Just out of interest could a Fortran String include a chr(0) as a legal entity - but not be the end?
Yes
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sure
A character(n) Fortran string is an array of n bytes whose values range from 0 to 255.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A little bit of delving into history should explain why the ASCII null character has no special significance in Fortran. Fortran was in use for several years before the ASCII character set was devised. Take, for example, the CDC "display" character set, https://en.wikipedia.org/wiki/CDC_display_code . The very first 6-bit code, octal 00, stands for ':'. The very last 6-bit code, octal 77, stands for ';', and octal 55 stands for 'blank' or 'space'. No tabs, carriage-returns line-feeds or form-feeds to be found in that character set. All characters can be displayed and printed, and only 'blank' is 'white-space'.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ancient history! I coded my first Fortran (FORTRAN) on a CDC Cyber using a teletype terminal and looking back it is amazing that the experience didn't give me an aversion to computers for life. Despite all our whinges the performance and features in the current products is truly fantastic!
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page