1! This file is part of xtb. 2! 3! Copyright (C) 2017-2020 Stefan Grimme 4! 5! xtb is free software: you can redistribute it and/or modify it under 6! the terms of the GNU Lesser General Public License as published by 7! the Free Software Foundation, either version 3 of the License, or 8! (at your option) any later version. 9! 10! xtb is distributed in the hope that it will be useful, 11! but WITHOUT ANY WARRANTY; without even the implied warranty of 12! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13! GNU Lesser General Public License for more details. 14! 15! You should have received a copy of the GNU Lesser General Public License 16! along with xtb. If not, see <https://www.gnu.org/licenses/>. 17 18module xtb_mctc_strings 19!use iso_fortran_env, only : kr4 => real32, kr8 => real64, & 20!& ki4 => int32, ki8 => int64 21implicit none 22 23! Real kinds 24!> @brief single precision real 25integer, parameter :: kr4 = selected_real_kind(6,37) 26!> @brief double precision real 27integer, parameter :: kr8 = selected_real_kind(15,307) 28 29! Integer kinds 30!> @brief single precision integer 31integer, parameter :: ki4 = selected_int_kind(9) 32!> @brief double precision integer 33integer, parameter :: ki8 = selected_int_kind(18) 34 35! Complex kinds 36!> @brief single precision complex 37integer, parameter :: kc4 = kr4 38!> @brief double precision complex 39integer, parameter :: kc8 = kr8 40 41private :: kr4,kr8,ki4,ki8,kc4,kc8 42 43private :: value_dr,value_sr,value_di,value_si 44private :: write_dr,write_sr,write_di,write_si 45private :: writeq_dr,writeq_sr,writeq_di,writeq_si 46 47!> @brief Generic operator for converting a number string to a 48!! number. Calling syntax is 'call value(numstring,number,ios)' 49!! where 'numstring' is a number string and 'number' is a 50!! real number or an integer (single or double precision). 51interface value 52 module procedure value_dr 53 module procedure value_sr 54 module procedure value_di 55 module procedure value_si 56end interface 57 58!> @brief Generic interface for writing a number to a string. The 59!! number is left justified in the string. The calling syntax 60!! is 'call writenum(number,string,format)' where 'number' is 61!! a real number or an integer, 'string' is a character string 62!! containing the result, and 'format' is the format desired, 63!! e.g., 'e15.6' or 'i5'. 64interface writenum 65 module procedure write_dr 66 module procedure write_sr 67 module procedure write_di 68 module procedure write_si 69end interface 70 71!> @brief Generic interface equating a name to a numerical value. The 72!! calling syntax is 'call writeq(unit,name,value,format)' where 73!! unit is the integer output unit number, 'name' is the variable 74!! name, 'value' is the real or integer value of the variable, 75!! and 'format' is the format of the value. The result written to 76!! the output unit has the form <name> = <value>. 77interface writeq 78 module procedure writeq_dr 79 module procedure writeq_sr 80 module procedure writeq_di 81 module procedure writeq_si 82end interface 83 84 85!********************************************************************** 86 87contains 88 89!********************************************************************** 90 91pure function capitalize (str) 92integer :: il,i 93character(len=*),intent(in) :: str 94character(len=len(str)) :: capitalize 95character(len=26),parameter :: cap = & 96& 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 97character(len=26),parameter :: low = & 98& 'abcdefghijklmnopqrstuvwxyz' 99capitalize = str 100il = INDEX(low, str(1:1)) 101if (il.gt.0) capitalize(1:1) = cap(il:il) 102do i = 2, len_trim(str) 103 il = INDEX(cap, str(i:i)) 104 if (il.gt.0) capitalize(i:i) = low(il:il) 105enddo 106end function capitalize 107 108!********************************************************************** 109 110!> @brief Parses the string 'str' into arguments args(1), ..., args(nargs) based on 111!! the delimiters contained in the string 'delims'. Preceding a delimiter in 112!! 'str' by a backslash (\) makes this particular instance not a delimiter. 113!! The integer output variable nargs contains the number of arguments found. 114pure subroutine parse(str,delims,args,nargs) 115 116character(len=*), intent(in) :: str 117character(len=*), intent(in) :: delims 118character(len=len_trim(str)) :: tmpstr 119character(len=*), dimension(:), intent(out) :: args 120 121integer, intent(out) :: nargs 122integer :: na,i,lenstr,k 123 124tmpstr=str 125call compact(tmpstr) 126na=size(args) 127do i=1,na 128 args(i)=' ' 129end do 130nargs=0 131lenstr=len_trim(tmpstr) 132if(lenstr==0) return 133k=0 134 135do 136 if(len_trim(tmpstr) == 0) exit 137 nargs=nargs+1 138 if (nargs > size(args)) exit 139 call split(tmpstr,delims,args(nargs)) 140 call removebksl(args(nargs)) 141end do 142 143end subroutine parse 144 145!********************************************************************** 146 147!> @brief Converts multiple spaces and tabs to single spaces; deletes control characters; 148!! removes initial spaces. 149pure subroutine compact(str) 150 151 152character(len=*), intent(inout) :: str 153character(len=1) :: ch 154character(len=len_trim(str)) :: outstr 155 156integer :: lenstr,isp,k,i,ich 157 158str=adjustl(str) 159lenstr=len_trim(str) 160outstr=' ' 161isp=0 162k=0 163 164do i=1,lenstr 165 ch=str(i:i) 166 ich=iachar(ch) 167 168 select case(ich) 169 170 case(9,32) ! space or tab character 171 if(isp==0) then 172 k=k+1 173 outstr(k:k)=' ' 174 end if 175 isp=1 176 177 case(33:) ! not a space, quote, or control character 178 k=k+1 179 outstr(k:k)=ch 180 isp=0 181 182 end select 183 184end do 185 186str=adjustl(outstr) 187 188end subroutine compact 189 190!********************************************************************** 191 192!> @brief Removes spaces, tabs, and control characters in string str 193pure subroutine removesp(str) 194 195character(len=*), intent(inout) :: str 196character(len=1) :: ch 197character(len=len_trim(str)) :: outstr 198 199integer :: lenstr,k,i,ich 200 201str=adjustl(str) 202lenstr=len_trim(str) 203outstr=' ' 204k=0 205 206do i=1,lenstr 207 ch=str(i:i) 208 ich=iachar(ch) 209 select case(ich) 210 case(0:32) ! space, tab, or control character 211 cycle 212 case(33:) 213 k=k+1 214 outstr(k:k)=ch 215 end select 216end do 217 218str=adjustl(outstr) 219 220end subroutine removesp 221 222!********************************************************************** 223 224!> @brief Converts number string to a double precision real number 225pure subroutine value_dr(str,rnum,iostat) 226 227character(len=*), intent(in) ::str 228real(kr8), intent(out) ::rnum 229integer, intent(out), optional :: iostat 230 231integer :: ilen,ipos,ios 232 233ilen=len_trim(str) 234ipos=scan(str,'Ee') 235if(.not.is_digit(str(ilen:ilen)) .and. ipos/=0) then 236 if (present(iostat)) iostat=3 237 return 238end if 239read(str,*,iostat=ios) rnum 240if (present(iostat)) iostat = ios 241 242end subroutine value_dr 243 244!********************************************************************** 245 246!> @brief Converts number string to a single precision real number 247pure subroutine value_sr(str,rnum,iostat) 248 249character(len=*), intent(in) ::str 250real(kr4), intent(out) :: rnum 251real(kr8) :: rnumd 252 253integer, intent(out), optional :: iostat 254integer :: ios 255 256call value_dr(str,rnumd,ios) 257if (present(iostat)) iostat = ios 258if( abs(rnumd) > huge(rnum) ) then 259 if (present(iostat)) iostat = 15 260 return 261end if 262if( abs(rnumd) < tiny(rnum) ) rnum=0.0_kr4 263rnum=rnumd 264 265end subroutine value_sr 266 267!********************************************************************** 268 269!> @brief Converts number string to a double precision integer value 270pure subroutine value_di(str,inum,iostat) 271 272 273character(len=*), intent(in) ::str 274integer(ki8), intent(out) :: inum 275real(kr8) :: rnum 276 277integer, intent(out), optional :: iostat 278integer :: ios 279 280call value_dr(str,rnum,ios) 281if (present(iostat)) iostat = ios 282if(abs(rnum)>huge(inum)) then 283 if (present(iostat)) iostat = 15 284 return 285end if 286inum=nint(rnum,ki8) 287 288end subroutine value_di 289 290!********************************************************************** 291 292!> @brief Converts number string to a single precision integer value 293pure subroutine value_si(str,inum,iostat) 294 295character(len=*), intent(in) ::str 296integer(ki4), intent(out) :: inum 297real(kr8) :: rnum 298 299integer, intent(out), optional :: iostat 300integer :: ios 301 302call value_dr(str,rnum,ios) 303if (present(iostat)) iostat = ios 304if(abs(rnum)>huge(inum)) then 305 if (present(iostat)) iostat=15 306 return 307end if 308inum=nint(rnum,ki4) 309 310end subroutine value_si 311 312!********************************************************************** 313 314!> @brief Shifts characters in in the string 'str' n positions (positive values 315!! denote a right shift and negative values denote a left shift). Characters 316!! that are shifted off the end are lost. Positions opened up by the shift 317!! are replaced by spaces. 318pure subroutine shiftstr(str,n) 319 320character(len=*), intent(inout) :: str 321integer, intent(in) :: n 322 323integer :: lenstr,nabs 324 325lenstr=len(str) 326nabs=iabs(n) 327if(nabs>=lenstr) then 328 str=repeat(' ',lenstr) 329 return 330end if 331if(n<0) str=str(nabs+1:)//repeat(' ',nabs) ! shift left 332if(n>0) str=repeat(' ',nabs)//str(:lenstr-nabs) ! shift right 333return 334 335end subroutine shiftstr 336 337!********************************************************************** 338 339!> @brief Inserts the string 'strins' into the string 'str' at position 'loc'. 340!! Characters in 'str' starting at position 'loc' are shifted right to 341!! make room for the inserted string. Trailing spaces of 'strins' are 342!! removed prior to insertion 343pure subroutine insertstr(str,strins,loc) 344 345 346character(len=*), intent(inout) :: str 347character(len=*), intent(in) :: strins 348character(len=len(str)) :: tempstr 349 350integer, intent(in) :: loc 351integer :: lenstrins 352 353lenstrins=len_trim(strins) 354tempstr=str(loc:) 355call shiftstr(tempstr,lenstrins) 356tempstr(1:lenstrins)=strins(1:lenstrins) 357str(loc:)=tempstr 358return 359 360end subroutine insertstr 361 362!********************************************************************** 363 364!> @brief Deletes first occurrence of substring 'substr' from string 'str' and 365!! shifts characters left to fill hole. Trailing spaces or blanks are 366!! not considered part of 'substr'. 367pure subroutine delsubstr(str,substr) 368 369character(len=*), intent(inout) :: str 370character(len=*), intent(in) :: substr 371 372integer :: lensubstr,ipos 373 374lensubstr=len_trim(substr) 375ipos=index(str,substr) 376if(ipos==0) return 377if(ipos == 1) then 378 str=str(lensubstr+1:) 379else 380 str=str(:ipos-1)//str(ipos+lensubstr:) 381end if 382return 383 384end subroutine delsubstr 385 386!********************************************************************** 387 388!> @brief Deletes all occurrences of substring 'substr' from string 'str' and 389!! shifts characters left to fill holes. 390pure subroutine delall(str,substr) 391 392 393character(len=*), intent(inout) :: str 394character(len=*), intent(in) :: substr 395 396integer :: lensubstr 397integer :: ipos 398 399lensubstr=len_trim(substr) 400do 401 ipos=index(str,substr) 402 if(ipos == 0) exit 403 if(ipos == 1) then 404 str=str(lensubstr+1:) 405 else 406 str=str(:ipos-1)//str(ipos+lensubstr:) 407 end if 408end do 409return 410 411end subroutine delall 412 413!********************************************************************** 414 415!> @brief convert string to upper case 416function uppercase(str) result(ucstr) 417 418 419character (len=*):: str 420character (len=len_trim(str)):: ucstr 421 422integer :: ilen,ioffset,iquote,i,iav,iqc 423 424ilen=len_trim(str) 425ioffset=iachar('A')-iachar('a') 426iquote=0 427ucstr=str 428do i=1,ilen 429 iav=iachar(str(i:i)) 430 if(iquote==0 .and. (iav==34 .or.iav==39)) then 431 iquote=1 432 iqc=iav 433 cycle 434 end if 435 if(iquote==1 .and. iav==iqc) then 436 iquote=0 437 cycle 438 end if 439 if (iquote==1) cycle 440 if(iav >= iachar('a') .and. iav <= iachar('z')) then 441 ucstr(i:i)=achar(iav+ioffset) 442 else 443 ucstr(i:i)=str(i:i) 444 end if 445end do 446return 447 448end function uppercase 449 450!********************************************************************** 451 452!> @brief convert string to lower case 453function lowercase(str) result(lcstr) 454 455character (len=*):: str 456character (len=len_trim(str)):: lcstr 457 458integer :: ilen,ioffset,iquote,i,iav,iqc 459 460ilen=len_trim(str) 461ioffset=iachar('A')-iachar('a') 462iquote=0 463lcstr=str 464do i=1,ilen 465 iav=iachar(str(i:i)) 466 if(iquote==0 .and. (iav==34 .or.iav==39)) then 467 iquote=1 468 iqc=iav 469 cycle 470 end if 471 if(iquote==1 .and. iav==iqc) then 472 iquote=0 473 cycle 474 end if 475 if (iquote==1) cycle 476 if(iav >= iachar('A') .and. iav <= iachar('Z')) then 477 lcstr(i:i)=achar(iav-ioffset) 478 else 479 lcstr(i:i)=str(i:i) 480 end if 481end do 482return 483 484end function lowercase 485 486!********************************************************************** 487 488!> @brief Reads line from unit=nunitr, ignoring blank lines 489!! and deleting comments beginning with an exclamation point(!) 490subroutine readline(nunitr,line,ios) 491 492character (len=*):: line 493 494integer :: nunitr,ios,ipos 495 496do 497 read(nunitr,'(a)', iostat=ios) line ! read input line 498 if(ios /= 0) return 499 line=adjustl(line) 500 ipos=index(line,'!') 501 if(ipos == 1) cycle 502 if(ipos /= 0) line=line(:ipos-1) 503 if(len_trim(line) /= 0) exit 504end do 505return 506 507end subroutine readline 508 509!********************************************************************** 510 511!> @brief Sets imatch to the position in string of the delimiter matching the delimiter 512!! in position ipos. Allowable delimiters are (), [], {}, <>. 513pure subroutine match(str,ipos,imatch,status) 514 515character(len=*), intent(in) :: str 516character :: delim1,delim2,ch 517 518integer, intent(out), optional :: status 519integer :: stat 520 521integer, intent(in) :: ipos 522integer, intent(out) :: imatch 523integer :: lenstr,idelim2,istart,inc,iend,isum,i 524 525lenstr=len_trim(str) 526delim1=str(ipos:ipos) 527select case(delim1) 528 case('(') 529 idelim2=iachar(delim1)+1 530 istart=ipos+1 531 iend=lenstr 532 inc=1 533 case(')') 534 idelim2=iachar(delim1)-1 535 istart=ipos-1 536 iend=1 537 inc=-1 538 case('[','{','<') 539 idelim2=iachar(delim1)+2 540 istart=ipos+1 541 iend=lenstr 542 inc=1 543 case(']','}','>') 544 idelim2=iachar(delim1)-2 545 istart=ipos-1 546 iend=1 547 inc=-1 548 case default 549 stat = 1 550 if (present(status)) status = stat 551 !write(*,*) delim1,' is not a valid delimiter' 552 return 553end select 554if(istart < 1 .or. istart > lenstr) then 555 stat = 2 556 if (present(status)) status = stat 557 !write(*,*) delim1,' has no matching delimiter' 558 return 559end if 560delim2=achar(idelim2) ! matching delimiter 561 562isum=1 563do i=istart,iend,inc 564 ch=str(i:i) 565 if(ch /= delim1 .and. ch /= delim2) cycle 566 if(ch == delim1) isum=isum+1 567 if(ch == delim2) isum=isum-1 568 if(isum == 0) exit 569end do 570if(isum /= 0) then 571 stat = 3 572 if (present(status)) status = stat 573 !write(*,*) delim1,' has no matching delimiter' 574 return 575end if 576imatch=i 577if (present(status)) status = 0 578 579return 580 581end subroutine match 582 583!********************************************************************** 584 585!> @brief Writes double precision real number rnum to string str using format fmt 586pure subroutine write_dr(rnum,str,fmt) 587 588real(kr8), intent(in) :: rnum 589character(len=*), intent(out) :: str 590character(len=*), intent(in), optional :: fmt 591character(len=80) :: formt 592 593if (present(fmt)) then 594 formt='('//trim(fmt)//')' 595else 596 formt='(g0)' 597endif 598write(str,formt) rnum 599str=adjustl(str) 600 601end subroutine write_dr 602 603!*********************************************************************** 604 605!> @brief Writes single precision real number rnum to string str using format fmt 606pure subroutine write_sr(rnum,str,fmt) 607 608real(kr4), intent(in) :: rnum 609character(len=*), intent(out) :: str 610character(len=*), intent(in), optional :: fmt 611character(len=80) :: formt 612 613if (present(fmt)) then 614 formt='('//trim(fmt)//')' 615else 616 formt='(g0)' 617endif 618write(str,formt) rnum 619str=adjustl(str) 620 621end subroutine write_sr 622 623!*********************************************************************** 624 625!> @brief Writes double precision integer inum to string str using format fmt 626pure subroutine write_di(inum,str,fmt) 627 628integer(ki8), intent(in) :: inum 629character(len=*), intent(out) :: str 630character(len=*), intent(in), optional :: fmt 631character(len=80) :: formt 632 633if (present(fmt)) then 634 formt='('//trim(fmt)//')' 635else 636 formt='(g0)' 637endif 638write(str,formt) inum 639str=adjustl(str) 640 641end subroutine write_di 642 643!*********************************************************************** 644 645!> @brief Writes single precision integer inum to string str using format fmt 646pure subroutine write_si(inum,str,fmt) 647 648integer(ki4), intent(in) :: inum 649character(len=*), intent(out) :: str 650character(len=*), intent(in), optional :: fmt 651character(len=80) :: formt 652 653if (present(fmt)) then 654 formt='('//trim(fmt)//')' 655else 656 formt='(g0)' 657endif 658write(str,formt) inum 659str=adjustl(str) 660 661end subroutine write_si 662 663!*********************************************************************** 664 665 666!> @brief Deletes nonsignificant trailing zeroes from number string str. If number 667!! string ends in a decimal point, one trailing zero is added. 668pure subroutine trimzero(str) 669 670character(len=*), intent(inout) :: str 671character :: ch 672character(len=10) :: exp 673 674integer :: ipos,i,lstr 675 676ipos=scan(str,'eE') 677if(ipos>0) then 678 exp=str(ipos:) 679 str=str(1:ipos-1) 680endif 681lstr=len_trim(str) 682do i=lstr,1,-1 683 ch=str(i:i) 684 if(ch=='0') cycle 685 if(ch=='.') then 686 str=str(1:i)//'0' 687 if(ipos>0) str=trim(str)//trim(exp) 688 exit 689 endif 690 str=str(1:i) 691 exit 692end do 693if(ipos>0) str=trim(str)//trim(exp) 694 695end subroutine trimzero 696 697!********************************************************************** 698 699!> @brief Writes a string of the form <name> = value to unit 700subroutine writeq_dr(unit,namestr,value,fmt) 701 702real(kr8) :: value 703integer :: unit 704character(len=*) :: namestr,fmt 705character(len=32) :: tempstr 706 707call writenum(value,tempstr,fmt) 708call trimzero(tempstr) 709write(unit,*) trim(namestr)//' = '//trim(tempstr) 710 711end subroutine writeq_dr 712 713!********************************************************************** 714 715!> @brief Writes a string of the form <name> = value to unit 716subroutine writeq_sr(unit,namestr,value,fmt) 717 718 719real(kr4) :: value 720integer :: unit 721character(len=*) :: namestr,fmt 722character(len=32) :: tempstr 723 724call writenum(value,tempstr,fmt) 725call trimzero(tempstr) 726write(unit,*) trim(namestr)//' = '//trim(tempstr) 727 728end subroutine writeq_sr 729 730!********************************************************************** 731 732!> @brief Writes a string of the form <name> = ivalue to unit 733subroutine writeq_di(unit,namestr,ivalue,fmt) 734 735 736integer(ki8) :: ivalue 737integer :: unit 738character(len=*) :: namestr,fmt 739character(len=32) :: tempstr 740call writenum(ivalue,tempstr,fmt) 741call trimzero(tempstr) 742write(unit,*) trim(namestr)//' = '//trim(tempstr) 743 744end subroutine writeq_di 745 746!********************************************************************** 747 748!> @brief Writes a string of the form <name> = ivalue to unit 749subroutine writeq_si(unit,namestr,ivalue,fmt) 750 751 752integer(ki4) :: ivalue 753integer :: unit 754character(len=*) :: namestr,fmt 755character(len=32) :: tempstr 756call writenum(ivalue,tempstr,fmt) 757call trimzero(tempstr) 758write(unit,*) trim(namestr)//' = '//trim(tempstr) 759 760end subroutine writeq_si 761 762!********************************************************************** 763 764!> @brief Returns .true. if ch is a letter and .false. otherwise 765function is_letter(ch) result(res) 766 767 768character :: ch 769logical :: res 770 771select case(ch) 772case('A':'Z','a':'z') 773 res=.true. 774case default 775 res=.false. 776end select 777return 778 779end function is_letter 780 781!********************************************************************** 782 783!> @brief Returns .true. if ch is a digit (0,1,...,9) and .false. otherwise 784pure elemental function is_digit(ch) result(res) 785 786character, intent(in) :: ch 787logical :: res 788 789select case(ch) 790case('0':'9') 791 res=.true. 792case default 793 res=.false. 794end select 795return 796 797end function is_digit 798 799!********************************************************************** 800 801!> @brief Routine finds the first instance of a character from 'delims' in the 802!! the string 'str'. The characters before the found delimiter are 803!! output in 'before'. The characters after the found delimiter are 804!! output in 'str'. The optional output character 'sep' contains the 805!! found delimiter. A delimiter in 'str' is treated like an ordinary 806!! character if it is preceded by a backslash (\). If the backslash 807!! character is desired in 'str', then precede it with another backslash. 808pure subroutine split(str,delims,before,sep) 809 810character(len=*), intent(inout) :: str 811character(len=*), intent(in) :: delims 812character(len=*), intent(out) :: before 813character, intent(out), optional :: sep 814logical :: pres 815character :: ch,cha 816 817integer :: lenstr,k,ibsl,i,ipos,iposa 818 819pres=present(sep) 820str=adjustl(str) 821call compact(str) 822lenstr=len_trim(str) 823if(lenstr == 0) return ! string str is empty 824k=0 825ibsl=0 ! backslash initially inactive 826before=' ' 827do i=1,lenstr 828 ch=str(i:i) 829 if(ibsl == 1) then ! backslash active 830 k=k+1 831 before(k:k)=ch 832 ibsl=0 833 cycle 834 end if 835 if(ch == '\') then ! backslash with backslash inactive 836 k=k+1 837 before(k:k)=ch 838 ibsl=1 839 cycle 840 end if 841 ipos=index(delims,ch) 842 if(ipos == 0) then ! character is not a delimiter 843 k=k+1 844 before(k:k)=ch 845 cycle 846 end if 847 if(ch /= ' ') then ! character is a delimiter that is not a space 848 str=str(i+1:) 849 if(pres) sep=ch 850 exit 851 end if 852 cha=str(i+1:i+1) ! character is a space delimiter 853 iposa=index(delims,cha) 854 if(iposa > 0) then ! next character is a delimiter 855 str=str(i+2:) 856 if(pres) sep=cha 857 exit 858 else 859 str=str(i+1:) 860 if(pres) sep=ch 861 exit 862 end if 863end do 864if(i >= lenstr) str='' 865str=adjustl(str) ! remove initial spaces 866return 867 868end subroutine split 869 870!********************************************************************** 871 872!> @brief Removes backslash (\) characters. Double backslashes (\\) are replaced 873!! by a single backslash. 874pure subroutine removebksl(str) 875 876character(len=*), intent(inout) :: str 877character(len=1) :: ch 878character(len=len_trim(str)) :: outstr 879 880integer :: lenstr,k,ibsl,i 881 882str=adjustl(str) 883lenstr=len_trim(str) 884outstr=' ' 885k=0 886ibsl=0 ! backslash initially inactive 887 888do i=1,lenstr 889 ch=str(i:i) 890 if(ibsl == 1) then ! backslash active 891 k=k+1 892 outstr(k:k)=ch 893 ibsl=0 894 cycle 895 end if 896 if(ch == '\') then ! backslash with backslash inactive 897 ibsl=1 898 cycle 899 end if 900 k=k+1 901 outstr(k:k)=ch ! non-backslash with backslash inactive 902end do 903 904str=adjustl(outstr) 905 906end subroutine removebksl 907 908!********************************************************************** 909 910end module xtb_mctc_strings 911 912