subroutine scannr(string ,stapos ,endpos ,nrflds ,itype , & & ifield ,rfield ,cfield ,lenchr ,maxfld , & & lconvu ,lconv1 ,lconv2 ) !----- LGPL -------------------------------------------------------------------- ! ! Copyright (C) Stichting Deltares, 2011-2023. ! ! This library is free software; you can redistribute it and/or ! modify it under the terms of the GNU Lesser General Public ! License as published by the Free Software Foundation version 2.1. ! ! This library is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! Lesser General Public License for more details. ! ! You should have received a copy of the GNU Lesser General Public ! License along with this library; if not, see . ! ! contact: delft3d.support@deltares.nl ! Stichting Deltares ! P.O. Box 177 ! 2600 MH Delft, The Netherlands ! ! All indications and logos of, and references to, "Delft3D" and "Deltares" ! are registered trademarks of Stichting Deltares, and remain the property of ! Stichting Deltares. All rights reserved. ! !------------------------------------------------------------------------------- ! ! !!--description----------------------------------------------------------------- ! ! Function: Split string up into sub-strings driven by ! spaces, tabs and quotes (' or ") and convert ! sub-fields to integers or reals if possible and ! required. ! Strings delimited by " can contain ' and ! strings delimited by ' can contain ". ! Note: With the logicals LCONVU, LCONV1 and LCONV2 ! it can be specified if unquoted strings, ! strings delimited by ' or strings delimited ! by " must be converted into integer or real ! if possible. ! ! Method used: ! !!--pseudo code and references-------------------------------------------------- ! NONE !!--declarations---------------------------------------------------------------- use precision ! implicit none ! ! Global variables ! integer , intent(in) :: endpos !! Endposition of scan integer , intent(in) :: maxfld !! Size of buffers (max number of sub-fields). integer :: nrflds !! Number of found sub-fields !! Error values: !! -1: One ore more parameters wrong !! STAPOS < 1; !! ENDPOS < STAPOS; !! ENDPOS > LEN(STRING); !! MAXFLD < 1. !! -2: More sub-fields than MAXFLD. !! There are more sub-fields than !! that there is space in ITYPE, !! IFIELD, RFIELD and CFIELD. !! -3: There is a character sub-field !! which is longer than the size !! of CFIELD. !! -4: Unmatching quotes. integer , intent(in) :: stapos !! Start position of scan integer , dimension(maxfld), intent(out) :: ifield !! Buffer integer sub-fields integer , dimension(maxfld), intent(out) :: itype !! Sub-field descriptions !! 1: INTEGER. Value in IFIELD. !! 2: REAL. Value in RFIELD. !! 3: CHARACTER. Text in CFIELD. The !! length is given in LENCHR. integer , dimension(maxfld), intent(out) :: lenchr !! Length of character sub-fields logical , intent(in) :: lconv1 !! Logical to determine if strings !! delimited by ' must be converted !! to integer or real if possible. logical , intent(in) :: lconv2 !! Logical to determine if strings !! delimited by " must be converted !! to integer or real if possible. logical , intent(in) :: lconvu !! Logical to determine if unquoted !! string must be converted !! to integer or real if possible. real(fp) , dimension(maxfld), intent(out) :: rfield !! Buffer real sub-fields character(*) , intent(in) :: string !! String to be scanned character(*), dimension(maxfld) :: cfield !! Buffer character sub-fields ! ! Local variables ! integer :: chrlng integer :: chrpos integer :: endchr integer :: i integer :: nbrchr integer :: stachr logical :: lconv logical :: lebyq logical :: lfound logical :: lqstr logical :: parerr character(1) :: blank character(1) :: quote character(1) :: quote1 character(1) :: quote2 character(1) :: tab character(8) :: fmtr ! !! executable statements ------------------------------------------------------- ! ! initialisation ! nrflds = 0 blank = ' ' tab = char(09) quote = ' ' quote1 = char(39) quote2 = char(34) ! ! Clear sub-field buffers. ! do i = 1, maxfld cfield(i) = ' ' rfield(i) = 0.0 ifield(i) = 0 itype(i) = 0 lenchr(i) = 0 enddo ! ! test parameters ! parerr = stapos<1 .or. endposlen(string) .or. maxfld<1 ! ! if something wrong: return(-1) ! if (parerr) then nrflds = -1 goto 999 endif ! ! Get maximum length of character-subfields ! chrlng = len(cfield(1)) ! ! Initialise local variables ! stachr = -1 endchr = -1 lqstr = .false. lebyq = .false. ! ! scan and convert the string-field ! do chrpos = stapos, endpos + 1 ! ! Check if unquoted sub-field was ended by quote ! if (lebyq) then stachr = chrpos - 1 lebyq = .false. lqstr = .true. endif ! ! Test on end of scan-string ! if (chrpos > endpos) then endchr = endpos - 1 if (lqstr) then ! ! End of scan found in quote-mode. ! That means no matching quote found. ! nrflds = -4 exit endif elseif (.not.lqstr) then if ( string(chrpos:chrpos)==quote1 & & .or. string(chrpos:chrpos)==quote2 )then ! ! Set active quote to found quote ! quote = string(chrpos:chrpos) if (chrpos < endpos) then if (stachr > 0) then ! ! Unquoted string terminated by quote ! endchr = chrpos - 1 lebyq = .true. quote = string(chrpos:chrpos) else ! ! Quote found, go into quoted string mode ! stachr = chrpos lqstr = .true. endif else ! ! Quote found on last position, can never match ! nrflds = -4 exit endif elseif ( string(chrpos:chrpos)==blank & & .or. string(chrpos:chrpos)==tab )then if (stachr > 0) then ! ! End of unquoted sub-string found ! endchr = chrpos - 1 endif elseif ( string(chrpos:chrpos)/=blank & & .and. string(chrpos:chrpos)/=tab )then if (stachr == -1) then ! ! Start of unquoted sub-string found ! stachr = chrpos endif else endif elseif (string(chrpos:chrpos) == quote) then ! ! Matching quote found ! endchr = chrpos else endif ! ! Check if substring found, if so process it ! if (stachr>0 .and. endchr>0) then ! ! In case of Quote-delimited string, exclude the quotes ! and determine length of found sub-field ! if (lqstr) then stachr = stachr + 1 endchr = endchr - 1 endif nbrchr = endchr - stachr + 1 ! ! If length of sub-field is zero (only will happen ! in case of two successive quotes) no field has ! to be added, field is emty!! ! if (nbrchr > 0) then ! ! Test if maximum number of allowed fields is exceeded ! if (nrflds == maxfld) then nrflds = -2 exit endif nrflds = nrflds + 1 ! ! Determine if conversion is required ! if (lqstr) then if ( (quote=='''' .and. lconv1) & & .or. (quote=='"' .and. lconv2) )then lconv = .true. else lconv = .false. endif else ! ! As given for unquoted strings ! lconv = lconvu endif lfound = .false. if (lconv) then ! ! Try if it is an integer ! fmtr = '(ixxx)' write (fmtr(3:5), '(i3.3)') nbrchr read (string(stachr:endchr), fmtr, err = 111) ifield(nrflds) lfound = .true. itype(nrflds) = 1 ! ! If no integer, try a real ! 111 continue if (.not.lfound) then fmtr = '(gxxx.0)' write (fmtr(3:5), '(i3.3)') nbrchr read (string(stachr:endchr), fmtr, err = 222) rfield(nrflds) lfound = .true. itype(nrflds) = 2 else ! ! Provide integer data also as real data ! rfield(nrflds) = real(ifield(nrflds),fp) endif endif ! ! If no real as well, take it as character string ! 222 continue if (.not.lfound) then ! ! Character field, first check on length ! if (nbrchr > chrlng) then nrflds = -3 exit endif itype (nrflds) = 3 lenchr(nrflds) = nbrchr ! ! Copy character sub-field to output-field ! cfield(nrflds) = string(stachr:endchr) else ! ! Provide integer and real data also as string ! limit to maximum space, don't generate error! ! if (nbrchr > chrlng) then lenchr(nrflds) = chrlng cfield(nrflds) = string(stachr:stachr+chrlng-1) else lenchr(nrflds) = nbrchr cfield(nrflds) = string(stachr:endchr) endif endif endif ! ! Reset substring locations and quote-mode to ! be ready for searching for the next sub-field. ! stachr = -1 endchr = -1 lqstr = .false. endif enddo ! ! exit-label ! 999 continue end subroutine scannr