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