View previous topic :: View next topic |
Author |
Message |
PaulHolden
Joined: 08 Jan 2018 Posts: 6
|
Posted: Mon Jan 08, 2018 2:49 pm Post subject: Using centre@ function |
|
|
Is there a "correct" way to wrap the Centre@ function in another function using Fortran 90/95? Centre@ returns a string of length determined by the assignment statement which cannot easily be replicated in code (at least I can't find an obvious way). Many years ago I vaguely remember a newsgroup question on a similar topic in which one of the elder statesmen of Fortran said that this sort of this was not within the scope (or desirability) of the F90 standard.
Before anyone asks, I am trying to create a portability wrapper so the main code can be compiled in various compilers including FTN95. |
|
Back to top |
|
 |
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2402 Location: Yateley, Hants, UK
|
Posted: Mon Jan 08, 2018 3:39 pm Post subject: |
|
|
One lives and learns - I never knew such a function existed.
Surely it is a matter of positioning the input string STRING in a character variable of length LW (as in FTN95.CHM) by (LW-LEN_TRIM(STRING))/2 from the start of the output string? (and therefore not difficult).
Eddie |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Mon Jan 08, 2018 4:01 pm Post subject: |
|
|
Also I suspect that the length of the result is determined by the declaration of CENTRE@ and not by an assignment statement. For example
Code: | CHARACTER (LEN=80) CENTRE@ |
|
|
Back to top |
|
 |
PaulHolden
Joined: 08 Jan 2018 Posts: 6
|
Posted: Mon Jan 08, 2018 5:44 pm Post subject: Re: |
|
|
LitusSaxonicum wrote: | One lives and learns - I never knew such a function existed.
Surely it is a matter of positioning the input string STRING in a character variable of length LW (as in FTN95.CHM) by (LW-LEN_TRIM(STRING))/2 from the start of the output string? (and therefore not difficult).
Eddie |
All very well, but how do you define the return type of the function if you don't know the length of the string being assigned to? |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Mon Jan 08, 2018 5:49 pm Post subject: |
|
|
I am assuming that somewhere in your code there is a declaration of the form
Code: | CHARACTER (LEN=80) CENTRE@ |
|
|
Back to top |
|
 |
PaulHolden
Joined: 08 Jan 2018 Posts: 6
|
Posted: Mon Jan 08, 2018 5:52 pm Post subject: Re: |
|
|
PaulLaidler wrote: | I am assuming that somewhere in your code there is a declaration of the form
Code: | CHARACTER (LEN=80) CENTRE@ |
|
No. I am writing a wrapper function which doesn't know the length of the string being passed to Centre@. That is the problem. |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Mon Jan 08, 2018 6:19 pm Post subject: |
|
|
Perhaps the easiest solution is to use Eddie's approach. |
|
Back to top |
|
 |
PaulHolden
Joined: 08 Jan 2018 Posts: 6
|
Posted: Mon Jan 08, 2018 7:05 pm Post subject: Re: |
|
|
PaulLaidler wrote: | Perhaps the easiest solution is to use Eddie's approach. |
"Eddie's approach" didn't seem to answer the problem of not knowing the length of the input string at compile time. I tried several different ways to copy the runtime length of the input string dummy argument to the function return length, but none of them worked. I was hoping someone could come up with a solution.
My current "easiest" solution is to replace Centre@ function with a F90/F95 portable subroutine that does in code what Centre@ does intrinsically. It is a bit messier to call as you need 2 lines of code where the function does the same in one line, but it does at least do what I want. I guess the Centre@ function is a bit "too good to be true" and can't be replicated in a portable way.
Last edited by PaulHolden on Thu Jan 11, 2018 11:58 pm; edited 1 time in total |
|
Back to top |
|
 |
wahorger

Joined: 13 Oct 2014 Posts: 1257 Location: Morrison, CO, USA
|
Posted: Tue Jan 09, 2018 12:37 am Post subject: |
|
|
Is the single statement use of a function *REQUIRED* to happen, or can you use a subroutine call?
Something of the form of:
Code: |
CALL CENTRE_CALL(OLD_STRING,NEW_CENTERED_STRING)
|
should work just fine, and can easily be made size independent in the subroutine.
Code: |
USE MSWIN
CHARACTER*20:: ABCD="THIS IS A TEST"
CHARACTER(LEN=LEN(ABCD)*2) DEFG
CHARACTER(LEN=LEN(DEFG)),EXTERNAL:: CENTRE@
CHARACTER*10:: OLD='OLDDATA'
CHARACTER*20:: NEWEST=' '
DEFG = CENTRE@(ABCD,LEN(DEFG))
PRINT *,'"',ABCD,'"'
PRINT *,'"',DEFG,'"'
CALL CENTRE_CALL(OLD,NEWEST)
STOP
END
SUBROUTINE CENTRE_CALL(OLD,NEWEST)
CHARACTER*(*) OLD
CHARACTER*(*) NEWEST
CHARACTER(LEN=LEN(NEWEST)),EXTERNAL:: CENTRE@
INTEGER*2:: I
I=LEN(NEWEST)
NEWEST=' ' ! THIS MUST BE HERE, BUT SHOULDN'T NEED TO BE
NEWEST = CENTRE@(OLD,I)
PRINT *,'"',OLD,'"'
PRINT *,'"',NEWEST,'"'
RETURN
END
|
Setting NEWEST to blank should not have to be there (it is initialized in the MAIN routine), but without it, things don't work right.
Also, having to use I works, but replacing it with int(len(newest),2) to set the type properly didn't work. |
|
Back to top |
|
 |
PaulHolden
Joined: 08 Jan 2018 Posts: 6
|
Posted: Thu Jan 11, 2018 8:08 pm Post subject: |
|
|
Thanks wahorger. The subroutine isn't as convenient as a function but it seems to be the only solution. |
|
Back to top |
|
 |
PaulHolden
Joined: 08 Jan 2018 Posts: 6
|
Posted: Fri Jan 12, 2018 7:52 pm Post subject: Re: |
|
|
John-Silver wrote: | does %cn instead of centre@ present a possible preferable solution option ? |
The idea is to make a portable function and %cn is certainly not that. I can easily reproduce the centering in subroutine code and avoid centre@ altogether, but not as a function. |
|
Back to top |
|
 |
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2402 Location: Yateley, Hants, UK
|
Posted: Sun Jan 14, 2018 4:53 pm Post subject: |
|
|
If I am right (and I concede that it is about 20 years since I last worked with Assembler, so I could be wrong), then all a FUNCTION returns is the address to its result on the stack. Moreover, the result is 'forgotten' immediately after the assignment or WRITE in which the function is invoked when the stack is cleaned up.
Hence, so long as the return address is mangled to point to the string of length LW with the input STRING centered in it, then that sequence of characters ought to be picked up in the calling routine and copied (or used) for that one time. It doesn't matter where in RAM that temporary copy resides, surely, and it could reside somewhere where it was ephemeral, i.e. allocated dynamically, if you so wish.
I assume that FTN95 reserves a long enough contiguous sequence of bytes at compilation by finding the longest declaration of the length of CENTRE@ (viz. FTN95.CHM's example call), the address of which is known to it, to Paul, and all the other folk at Silverfrost who understand such things, especially if there is a statically allocated sequence just reserved for it somewhere.
Of course the best answer is not to bother with those other compilers, and stick to FTN95, but then my view is that FTN95 is the best in every respect, and others are free to differ.
Eddie |
|
Back to top |
|
 |
mecej4
Joined: 31 Oct 2006 Posts: 1899
|
Posted: Mon Jan 15, 2018 3:34 pm Post subject: |
|
|
Paul Holden:
I am not sure about what you require, but how about something like this?
Code: | function center(strng)
implicit none
character(len=*) :: strng
character(len=(len(strng)+len_trim(strng))/2) :: center
!
! code to assemble the output string,
! with the correct number of leading blanks added and trailing blanks removed
!
end function center
|
You need to cut out leading blanks from the argument before passing the string to this function. If that is not desirable, or you wish to keep trailing blanks in the result string, you could adjust the length in the declaration of "center" to suit your needs.
Last edited by mecej4 on Mon Jan 15, 2018 4:40 pm; edited 2 times in total |
|
Back to top |
|
 |
mecej4
Joined: 31 Oct 2006 Posts: 1899
|
Posted: Mon Jan 15, 2018 3:48 pm Post subject: Re: |
|
|
LitusSaxonicum wrote: | If I am right (and I concede that it is about 20 years since I last worked with Assembler, so I could be wrong), then all a FUNCTION returns is the address to its result on the stack. |
The compiler writer is free to implement function calls that way, but that is not how FTN95 handles functions that return simple scalar type results (such as integer, real and double precision). For example, for functions of type INTEGER, the return value is held in AX, EAX or RAX. For functions of type real, the return value is in ST0 or XMM0. No address is needed or used, as with more general expressions.
Things were different when we had 8-bit or 16-bit computers, and a register was insufficiently large to hold Fortran integers (other than INTEGER*2 and INTEGER*1).
If such a character type function is referenced in an expression or an I/O list, the compiler may have to create a temporary variable on the stack to hold the result and pass the address or value of the temporary variable to the I/O routines. |
|
Back to top |
|
 |
KennyT
Joined: 02 Aug 2005 Posts: 318
|
Posted: Mon Mar 12, 2018 2:18 pm Post subject: A related question... |
|
|
When using DRAW_CHARACTERS@, with a proportional font, is there a way to determine the size in pixels of the box that contains the text, such that right/centre justification can be calculated for hardcopy...
K |
|
Back to top |
|
 |
|