Loading...
Searching...
No Matches
string.f90
Go to the documentation of this file.
1!> @file
2!! @defgroup group_string String
3!! Minimal yet powerful variable-length string type with modern Fortran features.
4!! This module implements a lightweight `string` derived type that behaves like
5!! a true variable-length character string while remaining fully compatible with
6!! intrinsic Fortran character operations.
7!!
8!! Features:
9!! - Automatic memory management via `allocatable character(:)`
10!! - Overloaded assignment (`=`) between `string` and `character(*)`
11!! - Overloaded operators: `//` (concatenation), `==` (equality), `.contains.` (membership)
12!! - Generic interfaces for `len`, `len_trim`, `trim`
13!! - Full support for formatted I/O (`write`, `print`)
14!! - Helper routines for parsing Fortran source (line continuation, uppercase conversion, etc.)
15!!
16!! The design is intentionally minimal — it provides only what's necessary for
17!! robust string handling in scientific and preprocessing applications,
18!! avoiding the bloat of larger string libraries while remaining fast and standards-compliant.
19!! @note All procedures are `pure` or `elemental` when possible for maximum performance
20!! and usability in array contexts.
21!!
22!! <h2 class="groupheader">Examples</h2>
23!! @par Basic Usage
24!! @code{.f90}
25!! type(string) :: s, t
26!! character(:), allocatable :: line
27!!
28!! s = 'Hello' ! Assignment from literal
29!! t = s // ' World!' ! Concatenation
30!! print *, t%chars ! Output: Hello World!
31!!
32!! if (s == 'Hello') then
33!! print *, 'Equal'
34!! else
35!! print *, 'Case sensitive'
36!! endif
37!!
38!! print *, len(t) ! -> 12
39!! print *, len_trim(t) ! -> 12
40!! ...
41!! @endcode
42!!
43!! @par Array and Container Support
44!! @code{.f90}
45!! type(string) :: words(3)
46!! logical :: found
47!!
48!! words = [string('apple'), string('banana'), string('cherry')]
49!! found = words .contains. 'banana' ! --> .true.
50!! found = words .contains. string('date') ! --> .false.
51!! ...
52!! @endcode
53!!
54!! @par Advanced: Source Code Processing
55!! @code{.f90}
56!! character(len=:), allocatable :: code_line
57!! code_line = uppercase('program hello_world ! comment') ! --> 'PROGRAM HELLO_WORLD ! comment'
58!! ...
59!! @endcode
60module fpx_string
61 use fpx_constants
62 implicit none; private
63
64 public :: len, &
65 len_trim, &
66 trim, &
67 operator(//), &
68 operator(.contains.)
69
70 public :: starts_with, &
71 head, &
72 tail, &
73 previous, &
74 concat, &
75 writechk, &
77
78 !> Represents text as a sequence of ASCII code units.
79 !! The derived type wraps an allocatable character array.
80 !!
81 !! <h2 class="groupheader">Examples</h2>
82 !! @code{.f90}
83 !! type(string) :: s
84 !! s = 'foo'
85 !! @endcode
86 !!
87 !! <h2 class="groupheader">Constructors</h2>
88 !! Initializes a new instance of the string class
89 !! <h3>string(character(:))</h3>
90 !! @verbatim type(string) function string(character(:) chars) @endverbatim
91 !!
92 !! @param[in] chars
93 !!
94 !! @b Examples
95 !! @code{.f90}
96 !! type(string) :: s
97 !! s = string('foo')
98 !! @endcode
99 !! @return The constructed string object.
100 !!
101 !! <h2 class="groupheader">Remarks</h2>
102 !! The string implementation proposed here is kept at the bare
103 !! minimum of what is required by the library. There are many
104 !! other implementations that can be found.
105 !!
106 !! @ingroup group_string
107 type, public :: string
108 character(:), allocatable :: chars !< Variable length character array
109 contains
110 !! @cond
111 procedure, pass(lhs), private :: character_assign_string
112 procedure, pass(rhs), private :: string_assign_character
113 procedure, pass(lhs), private :: string_eq_string !! Equal to string logical operator.
114 procedure, pass(lhs), private :: string_eq_character !! Equal to character logical operator.
115 procedure, pass(rhs), private :: character_eq_string !! Equal to character (inverted) logical operator.
116 procedure, pass(dtv), private :: write_formatted !! Formatted output.
117 !! @endcond
118 generic, public :: assignment(=) => character_assign_string, &
119 string_assign_character
120 generic, public :: operator(==) => string_eq_string, &
121 string_eq_character, &
122 character_eq_string
123 generic, public :: write(formatted) => write_formatted
124 end type
125
126 !> Return the length of a string
127 !!
128 !! @b Remarks
129 !! @ingroup group_string
130 interface len
131 module procedure :: string_len
132 end interface
133
134 !> Return the trimmed length of a string
135 !!
136 !! @b Remarks
137 !! @ingroup group_string
138 interface len_trim
139 module procedure :: string_len_trim
140 end interface
141
142 !> Return the trimmed string
143 !!
144 !! @b Remarks
145 !! @ingroup group_string
146 interface trim
147 module procedure :: string_trim
148 end interface
149
150 !> Concatenation operator
151 !!
152 !! @b Remarks
153 !! @ingroup group_string
154 interface operator(//)
155 module procedure :: string_concat_string
156 module procedure :: string_concat_character
157 module procedure :: character_concat_string
158 end interface
159
160 !> Check whether a string belongs to a list or not
161 !!
162 !! @b Remarks
163 !! @ingroup group_string
164 interface operator(.contains.)
165 module procedure :: strings_contain_string
166 module procedure :: strings_contain_character
167 module procedure :: characters_contain_string
168 module procedure :: characters_contain_character
169 end interface
170
171contains
172
173 !> Assignment overloading. Assign a character array to a string.
174 !! @param[inout] lhs string
175 !! @param[in] rhs character(*)
176 !!
177 !! @b Examples
178 !! @code{.f90}
179 !! type(string) :: s
180 !!
181 !! s = 'foo'
182 !! @endcode
183 !!
184 !! @b Remarks
185 subroutine character_assign_string(lhs, rhs)
186 class(string), intent(inout) :: lhs
187 character(*), intent(in) :: rhs
188
189 if (allocated(lhs%chars)) deallocate(lhs%chars)
190 allocate(lhs%chars, source=rhs)
191 end subroutine
192
193 !> Assignment overloading. Assign a string to a character array.
194 !! @param[inout] lhs character(:), allocatable
195 !! @param[in] rhs string
196 !!
197 !! @b Examples
198 !! @code{.f90}
199 !! type(string) :: s
200 !! character(:), allocatable :: c
201 !!
202 !! s = 'foo'
203 !! c = s
204 !! ! The value of c is now 'foo'
205 !! @endcode
206 !!
207 !! @b Remarks
208 subroutine string_assign_character(lhs, rhs)
209 character(:), allocatable, intent(inout) :: lhs
210 class(string), intent(in) :: rhs
211
212 lhs = rhs%chars
213 end subroutine
214
215 !> Length of the string entity.
216 !! @param[in] this string
217 !!
218 !! @b Examples
219 !! @code{.f90}
220 !! type(string) :: s
221 !! integer :: l
222 !!
223 !! s = string('foo ')
224 !! l = len(s)
225 !! ! The value of l is 4
226 !! @endcode
227 !! @return An integer corresponding to the length of the string.
228 !!
229 !! @b Remarks
230 elemental integer function string_len(this) result(res)
231 class(string), intent(in) :: this
232
233 if (allocated(this%chars)) then
234 res = len(this%chars)
235 else
236 res = 0
237 end if
238 end function
239
240 !> Length of the string entity without trailing blanks (len_trim).
241 !! @param[in] this string
242 !!
243 !! @b Examples
244 !! @code{.f90}
245 !! type(string) :: s
246 !! integer :: l
247 !!
248 !! s = string('foo ')
249 !! l = len_trim(s)
250 !! ! The value of l is 3
251 !! @endcode
252 !! @return An integer corresponding to the trimmed length of the string.
253 !!
254 !! @b Remarks
255 pure integer function string_len_trim(this) result(res)
256 class(string), intent(in) :: this
257
258 if (allocated(this%chars)) then
259 res = len_trim(this%chars)
260 else
261 res = 0
262 end if
263 end function
264
265 !> Returns a copy of the string with trailing blanks removed.
266 !! @param[in] this string
267 !! @return Trimmed character string (deferred length).
268 !!
269 !! @b Remarks
270 pure function string_trim(this) result(res)
271 class(string), intent(in) :: this
272 character(:), allocatable :: res
273
274 if (allocated(this%chars)) then
275 res = trim(this%chars)
276 else
277 res = ''
278 end if
279 end function
280
281 !> Concatenation of two string objects.
282 !! @param[in] lhs left-hand side string
283 !! @param[in] rhs right-hand side string
284 !! @return New concatenated string.
285 !!
286 !! @b Remarks
287 pure function string_concat_string(lhs, rhs) result(res)
288 class(string), intent(in) :: lhs
289 class(string), intent(in) :: rhs
290 character(:), allocatable :: res
291
292 if (allocated(lhs%chars) .and. allocated(rhs%chars)) then
293 res = lhs%chars // rhs%chars
294 elseif (allocated(lhs%chars)) then
295 res = lhs%chars
296 elseif (allocated(rhs%chars)) then
297 res = rhs%chars
298 else
299 res = ''
300 end if
301 end function
302
303 !> Concatenation of string and character expression.
304 !! @param[in] lhs string
305 !! @param[in] rhs character expression
306 !! @return New concatenated string.
307 !!
308 !! @b Remarks
309 pure function string_concat_character(lhs, rhs) result(res)
310 class(string), intent(in) :: lhs
311 character(*), intent(in) :: rhs
312 character(:), allocatable :: res
313
314 if (allocated(lhs%chars)) then
315 res = lhs%chars // rhs
316 else
317 res = rhs
318 end if
319 end function
320
321 !> Concatenation of character expression and string.
322 !! @param[in] lhs character expression
323 !! @param[in] rhs string
324 !! @return New concatenated string.
325 !!
326 !! @b Remarks
327 pure function character_concat_string(lhs, rhs) result(res)
328 character(*), intent(in) :: lhs
329 class(string), intent(in) :: rhs
330 character(:), allocatable :: res
331
332 if (allocated(rhs%chars)) then
333 res = lhs // rhs%chars
334 else
335 res = lhs
336 end if
337 end function
338
339 !> Equality comparison between two string objects.
340 !! @param[in] lhs left-hand side
341 !! @param[in] rhs right-hand side
342 !! @return .true. if the strings are equal, .false. otherwise.
343 !!
344 !! @b Remarks
345 elemental function string_eq_string(lhs, rhs) result(res)
346 class(string), intent(in) :: lhs !! Left hand side.
347 type(string), intent(in) :: rhs !! Right hand side.
348 logical :: res !! Opreator test result.
349
350 if (.not. allocated(lhs%chars)) then
351 res = allocated(rhs%chars)
352 else
353 res = lhs%chars == rhs%chars
354 end if
355 end function
356
357 !> Equality comparison between string and character expression.
358 !! @param[in] lhs string
359 !! @param[in] rhs character expression
360 !! @return .true. if equal, .false. otherwise.
361 !!
362 !! @b Remarks
363 elemental function string_eq_character(lhs, rhs) result(res)
364 class(string), intent(in) :: lhs !! Left hand side.
365 character(*), intent(in) :: rhs !! Right hand side.
366 logical :: res !! Opreator test result.
367
368 if (.not. allocated(lhs%chars)) then
369 res = .false.
370 else
371 res = lhs%chars == rhs
372 end if
373 end function
374
375 !> Equality comparison (reversed) between character expression and string.
376 !! @param[in] lhs character expression
377 !! @param[in] rhs string
378 !! @return .true. if equal, .false. otherwise.
379 !!
380 !! @b Remarks
381 elemental function character_eq_string(lhs, rhs) result(res)
382 character(*), intent(in) :: lhs !! Left hand side.
383 class(string), intent(in) :: rhs !! Right hand side.
384 logical :: res !! Operator test result.
385
386 if (.not. allocated(rhs%chars)) then
387 res = .false.
388 else
389 res = rhs%chars == lhs
390 end if
391 end function
392
393 !> Formatted output procedure for user-defined type @ref string (UDTIO)
394 !! This procedure is called automatically when a formatted WRITE statement is used
395 !! with a variable of type `string` (when using the DT edit descriptor or default
396 !! formatted output for the type).
397 !!
398 !! It writes the content of the string component `dtv%chars` using a simple `A` format.
399 !! If the string is not allocated, an empty string is written.
400 !!
401 !! @param[in] dtv The @ref string object to be written (polymorphic dummy argument)
402 !! @param[in] unit Fortran logical unit number
403 !! @param[in] iotype String describing the edit descriptor ('DT' + optional string)
404 !! @param[in] v_list Integer array containing the values from the DT edit descriptor
405 !! (v_list is empty if no parentheses were used after DT)
406 !! @param[out] iostat I/O status code (0 = success, positive = error, negative = end-of-file/end-of-record)
407 !! @param[inout] iomsg Message describing the I/O error (if any)
408 !!
409 !! @b Note
410 !! - This implementation **ignores** `iotype` and `v_list` parameters
411 !! → the same simple character output is always performed
412 !! - The procedure always uses format `(A)`
413 !! - Empty (not allocated) string is written as empty line (zero characters)
414 !!
415 !! @b Warning
416 !! This is a minimal implementation of UDTIO formatted output.
417 !! More sophisticated versions could:
418 !! - respect `iotype` (DT"..." or LISTDIRECTED)
419 !! - use `v_list` for width/precision control
420 !! - add quotation marks, escaping, etc.
421 !!
422 !! @b Examples
423 !! @code{.f90}
424 !! type(string) :: s
425 !! call s%set("Hello formatted world!")
426 !!
427 !! write(*, *) s ! may call write_formatted (depending on compiler)
428 !! write(*, '(DT)') s ! explicitly calls write_formatted
429 !! @endcode
430 !!
431 !! @b Remarks
432 ! allow(assumed-size-character-intent)
433 subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
434 class(string), intent(in) :: dtv
435 integer, intent(in) :: unit !! Logical unit.
436 character(*), intent(in) :: iotype !! Edit descriptor.
437 integer, intent(in) :: v_list(:) !! Edit descriptor list.
438 integer, intent(out) :: iostat !! IO status code.
439 character(*), intent(inout) :: iomsg !! IO status message.
440
441 if (allocated(dtv%chars)) then
442 write(unit, '(A)', iostat=iostat, iomsg=iomsg) dtv%chars
443 else
444 write(unit, '(A)', iostat=iostat, iomsg=iomsg) ''
445 end if
446 end subroutine
447
448 !> Checks if a string starts with a given prefix
449 !! Returns `.true.` if the string `str` (after trimming leading/trailing whitespace)
450 !! begins exactly with the substring `arg1`.
451 !! The function uses `index()` after trimming both strings with `trim(adjustl())`.
452 !!
453 !! @param[in] str The string to be tested
454 !! @param[in] arg1 The prefix to look for at the beginning of `str`
455 !! @param[out] idx (optional) If present, receives the starting position of `arg1` in the trimmed string
456 !! (will be 1 if the function returns `.true.`, otherwise >1 or 0)
457 !!
458 !! @return `.true.` if `str` starts with `arg1` (after trimming), `.false.` otherwise
459 !!
460 !! @b Note
461 !! - Leading and trailing whitespace of both `str` and `arg1` is ignored
462 !! - Comparison is case-sensitive
463 !! - Empty `arg1` will always return `.true.` (any string starts with empty string)
464 !!
465 !! @b Warning
466 !! The returned index (when requested) is the position **after trimming** of the input string,
467 !! not in the original untrimmed string.
468 !!
469 !! @b Examples
470 !! @code{.f90}
471 !! character(80) :: line = ' hello world '
472 !! logical :: ok
473 !! integer :: pos
474 !!
475 !! ok = starts_with(line, 'hello') ! → .true.
476 !! ok = starts_with(line, 'hello', pos) ! → .true. and pos = 1
477 !! ok = starts_with(line, 'world') ! → .false.
478 !! ok = starts_with(' test123 ', 'test') ! → .true.
479 !! ...
480 !! @endcode
481 !!
482 !! @b Remarks
483 !! @ingroup group_string
484 logical function starts_with(str, arg1, idx) result(res)
485 character(*), intent(in) :: str
486 character(*), intent(in) :: arg1
487 integer, intent(out), optional :: idx
488 !private
489 integer :: i
490
491 i = index(trim(adjustl(str)), trim(arg1))
492 res = (i == 1)
493 if (present(idx)) idx = i
494 end function
495
496 !> Returns the first non-blank character of a string.
497 !! @param[in] str input string
498 !! @return First character (space if empty)
499 !!
500 !! @b Remarks
501 !! @ingroup group_string
502 character function head(str) result(res)
503 character(*), intent(in) :: str
504
505 res = ' '
506 if (len_trim(str) == 0) return
507
508 res = str(1:1)
509 end function
510
511 !> Returns the last non-blank character of a string.
512 !! @param[in] str input string
513 !! @return Last character (space if empty)
514 !!
515 !! @b Remarks
516 !! @ingroup group_string
517 character function tail(str) result(res)
518 character(*), intent(in) :: str
519 !private
520 integer :: n
521
522 res = ' '; n = len_trim(str)
523 if (n == 0) return
524
525 res = str(n:n)
526 end function
527
528 !> Smart concatenation that removes continuation markers (&) and handles line-continuation rules.
529 !! @param[in] str1 first line
530 !! @param[in] str2 second line
531 !! @return Concatenated string with proper continuation handling
532 !!
533 !! @b Remarks
534 !! @ingroup group_string
535 function concat(str1, str2) result(res)
536 character(*), intent(in) :: str1
537 character(*), intent(in) :: str2
538 character(:), allocatable :: res
539 !private
540 integer :: n1, n2
541
542 n1 = len(str1); n2 = 1
543 if (head(str1) == '!') then
544 n2 = 2
545 if (tail(str1) == '&') n1 = len_trim(str1) - 1
546 if (starts_with(str2, '!dir$') .or. starts_with(str2, '!DIR$') .or. &
547 starts_with(str2, '!dec$') .or. starts_with(str2, '!DEC$') .or. &
548 starts_with(str2, '!gcc$') .or. starts_with(str2, '!GCC$') .or. &
549 starts_with(str2, '!acc$') .or. starts_with(str2, '!ACC$') .or. &
550 starts_with(str2, '!$omp') .or. starts_with(str2, '!$OMP')) then
551 n2 = 6
552 end if
553 if (head(adjustl(str2(n2:))) == '&') then
554 n2 = index(str2, '&') + 1
555 end if
556 else
557 if (tail(str1) == '&') n1 = len_trim(str1) - 1
558 if (head(trim(str2)) == '&') n2 = index(str2, '&') + 1
559 if (tail(str1(:n1)) == '(') n1 = index(str1(:n1), '(', back=.true.)
560 end if
561
562 if (len(str1) > 0 .and. len(str2) >= n2) then
563 if (str1(n1:n1) == ' ' .and. str2(n2:n2) == ' ') n2 = n2 + 1
564 end if
565 res = str1(:n1) // str2(n2:)
566 end function
567
568 !> Convert string to upper case (respects contents of quotes).
569 !! @param[in] str input string
570 !! @return Upper-case version of the string
571 !!
572 !! @b Examples
573 !! @code
574 !! character(*), parameter :: input = 'test'
575 !! character(:), allocatable :: output
576 !! output = uppercase(input)
577 !! if (output == 'TEST') print*, 'OK'
578 !! @endcode
579 !!
580 !! @b Remarks
581 !! @ingroup group_string
582 pure function uppercase(str) result(res)
583 character(*), intent(in) :: str
584 character(len_trim(str)) :: res
585 !private
586 integer :: ilen, ioffset, iquote, iqc, iav, i
587
588 ilen = len_trim(str)
589 ioffset = iachar('A') - iachar('a')
590 iquote = 0
591 res = str
592 do i = 1, ilen
593 iav = iachar(str(i:i))
594 if (iquote == 0 .and. (iav == 34 .or. iav == 39)) then
595 iquote = 1
596 iqc = iav
597 cycle
598 end if
599 if (iquote == 1 .and. iav == iqc) then
600 iquote = 0
601 cycle
602 end if
603 if (iquote == 1) cycle
604 if (iav >= iachar('a') .and. iav <= iachar('z')) then
605 res(i:i) = achar(iav + ioffset)
606 else
607 res(i:i) = str(i:i)
608 end if
609 end do
610 end function
611
612 !> Write a long line split into chunks of size CHKSIZE with continuation (&).
613 !! @param[in] unit logical unit
614 !! @param[in] str string to write
615 !!
616 !! @b Remarks
617 !! @ingroup group_string
618 subroutine writechk(unit, str)
619 integer, intent(in) :: unit
620 character(*), intent(in) :: str
621 !private
622 integer :: i, n
623
624 n = 0
625 if (head(str) /= '!') then
626 n = floor(len(str) / real(chksize))
627 do i = 1, n
628 write(unit, '(A)') str((i - 1) * chksize + 1:i * chksize) // '&'
629 end do
630 end if
631 write(unit, '(A)') str(n * chksize + 1:)
632 end subroutine
633
634 !> Returns the previous non-blank character before position pos (updates pos).
635 !! @param[in] line input line
636 !! @param[inout] pos current position (moved backward)
637 !! @return Previous non-blank character
638 !!
639 !! @b Remarks
640 !! @ingroup group_string
641 character(1) function previous(line, pos) result(res)
642 character(*), intent(in) :: line
643 integer, intent(inout) :: pos
644 !private
645
646 if (pos == 1) then
647 res = trim(line(pos:pos))
648 else
649 do while (line(pos:pos) == ' ')
650 pos = pos - 1
651 if (pos == 1) exit
652 end do
653 res = line(pos:pos)
654 end if
655 end function
656
657 !> Checks whether an array of string contains a given string.
658 !! @param[in] lhs array of string
659 !! @param[in] rhs string to search for
660 !! @return .true. if rhs is present in lhs
661 !!
662 !! @b Remarks
663 logical function strings_contain_string(lhs, rhs) result(res)
664 type(string), intent(in) :: lhs(:)
665 type(string), intent(in) :: rhs
666 !private
667 integer :: i
668
669 res = .false.
670 do i = 1, size(lhs)
671 if (lhs(i) == rhs) then
672 res = .true.
673 exit
674 end if
675 end do
676 end function
677
678 !> Checks whether an array of string contains a given character expression.
679 !! @param[in] lhs array of string
680 !! @param[in] rhs character expression to search for
681 !! @return .true. if rhs is present in lhs
682 !!
683 !! @b Remarks
684 logical function strings_contain_character(lhs, rhs) result(res)
685 type(string), intent(in) :: lhs(:)
686 character(*), intent(in) :: rhs
687 !private
688 integer :: i
689
690 res = .false.
691 do i = 1, size(lhs)
692 if (lhs(i) == rhs) then
693 res = .true.
694 exit
695 end if
696 end do
697 end function
698
699 !> Checks whether an array of character contains a given character expression.
700 !! @param[in] lhs array of character
701 !! @param[in] rhs character expression to search for
702 !! @return .true. if rhs is present in lhs
703 !!
704 !! @b Remarks
705 logical function characters_contain_character(lhs, rhs) result(res)
706 character(*), intent(in) :: lhs(:)
707 character(*), intent(in) :: rhs
708 !private
709 integer :: i
710
711 res = .false.
712 do i = 1, size(lhs)
713 if (lhs(i) == rhs) then
714 res = .true.
715 exit
716 end if
717 end do
718 end function
719
720 !> Checks whether an array of character contains a given string.
721 !! @param[in] lhs array of character
722 !! @param[in] rhs string to search for
723 !! @return .true. if rhs is present in lhs
724 !!
725 !! @b Remarks
726 logical function characters_contain_string(lhs, rhs) result(res)
727 character(*), intent(in) :: lhs(:)
728 type(string), intent(in) :: rhs
729 !private
730 integer :: i
731
732 res = .false.
733 do i = 1, size(lhs)
734 if (lhs(i) == rhs) then
735 res = .true.
736 exit
737 end if
738 end do
739 end function
740end module
integer, parameter, public chksize
Maximum chunk size.
Definition constants.f90:31
character function, public tail(str)
Returns the last non-blank character of a string.
Definition string.f90:518
subroutine, public writechk(unit, str)
Write a long line split into chunks of size CHKSIZE with continuation (&).
Definition string.f90:619
character(1) function, public previous(line, pos)
Returns the previous non-blank character before position pos (updates pos).
Definition string.f90:642
pure character(len_trim(str)) function, public uppercase(str)
Convert string to upper case (respects contents of quotes).
Definition string.f90:583
character(:) function, allocatable, public concat(str1, str2)
Smart concatenation that removes continuation markers (&) and handles line-continuation rules.
Definition string.f90:536
logical function, public starts_with(str, arg1, idx)
Checks if a string starts with a given prefix Returns .true. if the string str (after trimming leadin...
Definition string.f90:485
character function, public head(str)
Returns the first non-blank character of a string.
Definition string.f90:503
Return the trimmed length of a string.
Definition string.f90:138
Return the length of a string.
Definition string.f90:130
Return the trimmed string.
Definition string.f90:146
Represents text as a sequence of ASCII code units. The derived type wraps an allocatable character ar...
Definition string.f90:107