0.6.2-dev0
FORCES
FORtran lib for Comp. Env. Sys.
Loading...
Searching...
No Matches
mo_os.F90
Go to the documentation of this file.
1!> \file mo_os.f90
2!> \brief \copybrief mo_os
3!> \details \copydetails mo_os
4
5!> \brief Path and directory management.
6!> \details Path handling and existence checks for files and directories.
7!> \changelog
8!! - Nicola Doering, Aug 2020
9!! - module implementation
10!! - Sebastian Mueller, Jan 2023
11!! - changed signatures (path, answer, verbose, raise) for path_exists, path_isfile and path_isdir
12!! - respect show_msg and show_err from mo_message
13!! - simplify inquire logic
14!> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
15!! FORCES is released under the LGPLv3+ license \license_note
16module mo_os
17
18 use mo_kind, only: i4
19
20 implicit none
21
22 public :: get_cwd
23 public :: change_dir
24 public :: check_path_exists
25 public :: check_path_isfile
26 public :: check_path_isdir
27 public :: path_exists
28 public :: path_isfile
29 public :: path_isdir
30 public :: path_isabs
31 public :: path_isroot
32 public :: path_splitext
33 public :: path_split
34 public :: path_parts
35 public :: path_dirname
36 public :: path_basename
37 public :: path_root
38 public :: path_ext
39 public :: path_stem
40 public :: path_as_posix
41 public :: path_normpath
42 public :: path_abspath
43 public :: path_join
44
45 !> \brief Join given path segments with separator if needed.
46 !> \details If a segment is an absolute path, the previous ones will be ignored.
47 !> \author Sebastian Müller
48 !> \date Mar 2023
49 interface path_join
50 module procedure :: path_join_char_opt
51 module procedure :: path_join_arr
52 end interface
53
54 !> The constant string used by the operating system to refer to the current directory.
55 character(len = *), public, parameter :: curdir = '.'
56 !> The constant string used by the operating system to refer to the parent directory.
57 character(len = *), public, parameter :: pardir = '..'
58 !> The character used by the operating system to separate pathname components.
59 character(len = *), public, parameter :: sep = '/'
60 !> The character which separates the base filename from the extension.
61 character(len = *), public, parameter :: extsep = '.'
62 !> The string used to separate (or, rather, terminate) lines on the current platform.
63 character(len = *), public, parameter :: linesep = '\n'
64 !> The file path of the null device.
65 character(len = *), public, parameter :: devnull = '/dev/null'
66 !> Maximum length of a path component (folder/file names).
67 integer(i4), public, save :: max_path_comp_len = 256_i4
68 !> Maximum length of a path (16 max. length components).
69 integer(i4), public, save :: max_path_len = 4096_i4
70
71 private
72
73 ! ------------------------------------------------------------------
74
75contains
76
77 ! ------------------------------------------------------------------
78 !> \brief Get the current working directory.
79 !> \author Sebastian Müller
80 !> \date Mar 2023
81 subroutine get_cwd(path, status, verbose, raise)
82#ifdef NAG
83 use f90_unix_dir, only : getcwd
84#endif
85#ifdef INTEL
86 use ifport, only : getcwd
87#endif
88 implicit none
89
90 character(*), intent(out) :: path !< the current working directory
91 integer(i4), intent(out), optional :: status !< error status (will prevent error raise if present)
92 logical, intent(in), optional :: verbose !< Be verbose or not (default: setting of SHOW_MSG/SHOW_ERR)
93 logical, intent(in), optional :: raise !< Throw an error if current directory can't be determined (default: .true.)
94
95 integer(i4) :: status_
96 logical :: raise_
97
98 raise_ = .true.
99 if ( present(raise) ) raise_ = raise
100 ! prevent raise if error code should be returned
101 raise_ = raise_ .and. .not. present(status)
102
103#ifdef NAG
104 call getcwd(path, errno=status_)
105#else
106 ! gfortran and intel can use a function
107 status_ = getcwd(path)
108#endif
109
110 if (status_ /= 0) call path_msg("Can't determine current working directory.", verbose=verbose, raise=raise_)
111 if ( present(status) ) status = status_
112
113 end subroutine get_cwd
114
115 ! ------------------------------------------------------------------
116 !> \brief Change current working directory.
117 !> \author Sebastian Müller
118 !> \date Mar 2023
119 subroutine change_dir(path, status, verbose, raise)
120#ifdef NAG
121 use f90_unix_dir, only : chdir
122#endif
123#ifdef INTEL
124 use ifport, only : chdir
125#endif
126 implicit none
127
128 character(*), intent(in) :: path !< path to change CWD to
129 integer(i4), intent(out), optional :: status !< error status (will prevent error raise if present)
130 logical, intent(in), optional :: verbose !< Be verbose or not (default: setting of SHOW_MSG/SHOW_ERR)
131 logical, intent(in), optional :: raise !< Throw an error if directory can't be opened (default: .true.)
132
133 integer(i4) :: status_
134 logical :: raise_
135
136 raise_ = .true.
137 if ( present(raise) ) raise_ = raise
138 ! prevent raise if error code should be returned
139 raise_ = raise_ .and. .not. present(status)
140
141#ifdef NAG
142 call chdir(trim(path), errno=status_)
143#else
144 ! gfortran and intel can use a function
145 status_ = chdir(path)
146#endif
147
148 if (status_ /= 0) call path_msg("Can't open directory: ", trim(path), verbose, raise_)
149 if ( present(status) ) status = status_
150
151 end subroutine change_dir
152
153 ! ------------------------------------------------------------------
154 !> \brief Checks whether a given path exists.
155 !> \author Nicola Doering
156 !> \date Aug 2020
157 subroutine check_path_exists(path, answer, verbose, raise)
158
159 implicit none
160
161 character(len=*), intent(in) :: path !< given path
162 logical, intent(out), optional :: answer !< result
163 logical, intent(in), optional :: verbose !< Be verbose or not (default: setting of SHOW_MSG/SHOW_ERR)
164 logical, intent(in), optional :: raise !< Throw an error if path does not exist (default: .false.)
165
166 LOGICAL :: exists
167
168 exists = path_exists(path)
169 if (.not. exists) call path_msg("Path does not exist: ", path, verbose, raise)
170 if (present(answer)) answer = exists
171
172 end subroutine check_path_exists
173
174 ! ------------------------------------------------------------------
175 !> \brief Checks whether a given path exists and describes a file.
176 !> \author Nicola Doering
177 !> \date Aug 2020
178 subroutine check_path_isfile(path, answer, verbose, raise)
179
180 implicit none
181
182 character(len=*), intent(in) :: path !< given path
183 logical, intent(out), optional :: answer !< result
184 logical, intent(in), optional :: verbose !< Be verbose or not (default: setting of SHOW_MSG/SHOW_ERR)
185 logical, intent(in), optional :: raise !< Throw an error if file does not exist (default: .false.)
186
187 LOGICAL :: isfile
188
189 isfile = path_isfile(path)
190 if (.not. isfile) call path_msg("File does not exist: ", path, verbose, raise)
191 if (present(answer)) answer = isfile
192
193 end subroutine check_path_isfile
194
195 ! ------------------------------------------------------------------
196 !> \brief Checks whether a given path exists and describes a directory.
197 !> \author Nicola Doering
198 !> \date Aug 2020
199 subroutine check_path_isdir(path, answer, verbose, raise)
200
201 implicit none
202
203 character(len=*), intent(in) :: path !< given path
204 logical, intent(out), optional :: answer !< result
205 logical, intent(in), optional :: verbose !< Be verbose or not (default: setting of SHOW_MSG/SHOW_ERR)
206 logical, intent(in), optional :: raise !< Throw an error if dir does not exist (default: .false.)
207
208 logical :: isdir
209
210 isdir = path_isdir(path)
211 if (.not. isdir) call path_msg("Directory does not exist: ", path, verbose, raise)
212 if (present(answer)) answer = isdir
213
214 end subroutine check_path_isdir
215
216 ! ------------------------------------------------------------------
217 !> \brief Return .true. if path refers to an existing path.
218 !> \author Sebastian Mueller
219 !> \date Mar 2023
220 logical function path_exists(path)
221 implicit none
222 character(len=*), intent(in) :: path !< given path
223
224 path_exists = path_isfile(path) .or. path_isdir(path)
225
226 end function path_exists
227
228 ! ------------------------------------------------------------------
229 !> \brief Return .true. if path is an existing regular file.
230 !> \author Sebastian Mueller
231 !> \date Mar 2023
232 logical function path_isfile(path)
233 implicit none
234 character(len=*), intent(in) :: path !< given path
235
236 inquire(file=trim(path), exist=path_isfile)
237 ! gfortran/NAG need the check if it is not a directory explicitly
238 path_isfile = path_isfile .and. (.not. path_isdir(path))
239
240 end function path_isfile
241
242 ! ------------------------------------------------------------------
243 !> \brief Return .true. if path is an existing directory.
244 !> \author Sebastian Mueller
245 !> \date Mar 2023
246 logical function path_isdir(path)
247 implicit none
248 character(len=*), intent(in) :: path !< given path
249
250#ifdef INTEL
251 ! intel has non-standard 'directory' argument
252 inquire(directory=trim(path), exist=path_isdir)
253#else
254 ! append "/" and check if it still exists
255 inquire(file=trim(path)//sep, exist=path_isdir)
256#endif
257
258 end function path_isdir
259
260 ! ------------------------------------------------------------------
261 !> \brief Return .true. if path is an absolute pathname.
262 !> \author Sebastian Müller
263 !> \date Mar 2023
264 logical function path_isabs(path)
265 use mo_string_utils, only : startswith
266 implicit none
267 character(len=*), intent(in) :: path !< given path
268
269 ! absolute posix path starts with '/'
270 path_isabs = startswith(path, sep)
271
272 end function path_isabs
273
274 ! ------------------------------------------------------------------
275 !> \brief Return .true. if path is root ('/' or '//' or '///' and so on).
276 !> \author Sebastian Müller
277 !> \date Mar 2023
278 logical function path_isroot(path)
279 use mo_string_utils, only : startswith
280 implicit none
281 character(len=*), intent(in) :: path !< given path
282
283 integer :: i
284
285 do i=len_trim(path), 0, -1
286 if (i == 0) exit ! only sep found or empty
287 if (path(i:i) /= sep) exit
288 end do
289 path_isroot = (i == 0) .and. (len_trim(path) > 0)
290
291 end function path_isroot
292
293 ! ------------------------------------------------------------------
294 !> \brief Splitting the path into root and ext
295 !> \details Splitting the path name into a pair root and ext.
296 !! Here, ext stands for extension and has the extension string
297 !! of the specified path while root is everything except this extension.
298 !> \changelog
299 !! - Sebastian Müller Mar 2023
300 !! - don't check for folder
301 !! - ignore leading dots in tail of the path
302 !! - make root and ext optional
303 !> \author Nicola Doering
304 !> \date Aug 2020
305 subroutine path_splitext(path, root, ext)
306
307 use mo_string_utils, only: endswith
308 implicit none
309
310 character(len=*), intent(in) :: path !< given path
311 character(len=*), intent(out), optional :: root !< root part of path without extension
312 character(len=*), intent(out), optional :: ext !< extension of given path (starting with ".")
313
314 integer :: lead_i, dot_i, sep_i
315 character(len=len_trim(path)) :: head, tail
316
317 ! find last '/' and split there
318 sep_i = index(trim(path), sep, back=.true.)
319 head = path(1:sep_i)
320 tail = path(sep_i+1:len_trim(path))
321
322 ! ignore leading dots of the tail ("...a" has no extension)
323 do lead_i = 1, len_trim(tail) + 1
324 if ( lead_i > len_trim(tail) ) exit ! only dots
325 if ( tail(lead_i:lead_i) /= extsep ) exit
326 end do
327
328 ! check for last dot in tail to split extension
329 dot_i = index(trim(tail), extsep, back=.true.)
330 ! last dot needs to come after leading dots to indicate an extension
331 if ( dot_i > lead_i ) then
332 ! dot_i is at least 2 here
333 if (present(ext)) ext = tail(dot_i:len_trim(tail))
334 if (present(root)) root = trim(head) // tail(1:dot_i-1)
335 else
336 ! no dot found at all or the leading dots are found
337 if (present(ext)) ext = ""
338 if (present(root)) root = trim(head) // trim(tail)
339 end if
340
341 end subroutine path_splitext
342
343 ! ------------------------------------------------------------------
344 !>\brief Splitting the path into head and tail
345 !>\details Splitting the path name into a pair head and tail.
346 !! Here, tail is the last path name component and head is
347 !! everything leading up to that.
348 !! If the path ends with an '/' tail is returned empty and
349 !! if there is no '/' in path head is returned empty.
350 !! Trailing '/'es are stripped from head unless it is the root.
351 !> \changelog
352 !! - Sebastian Müller Mar 2023
353 !! - remove trailing '/' from head unleass it is root (e.g. '/' or '//' or '///' and so on)
354 !! - make head and tail optional
355 !>\author Nicola Doering
356 !>\date Aug 2020
357 subroutine path_split(path, head, tail)
358
359 implicit none
360
361 character(len=*), intent(in) :: path !< given path
362 character(len=*), intent(out), optional :: head !< everything leading up to the last path component
363 character(len=*), intent(out), optional :: tail !< last pathname component
364
365 integer :: i
366 character(len=len_trim(path)) :: head_
367
368 ! find last '/'
369 i = index(trim(path), sep, back=.true.)
370
371 if (i == 0) then
372 ! no '/' found
373 if (present(tail)) tail = trim(path)
374 if (present(head)) head = ''
375 else
376 if (present(tail)) tail = path((i+1):len_trim(path))
377 if (.not. present(head)) return
378 head_ = path(1:i)
379 ! remove trailing '/' from head unless it is root
380 do i=len_trim(head_), 0, -1
381 if (i == 0) exit ! only sep found
382 if (head_(i:i) /= sep) exit
383 end do
384 if (i == 0) i = len_trim(head_) ! all characters are '/'
385 head = head_(1:i)
386 endif
387
388 end subroutine path_split
389
390 ! ------------------------------------------------------------------
391 !>\brief Splitting the path into its components.
392 !>\author Sebastian Müller
393 !>\date Mar 2023
394 subroutine path_parts(path, parts)
395 use mo_append, only : append
396 implicit none
397 character(len=*), intent(in) :: path !< given path
398 character(len=len_trim(path)), allocatable, intent(out) :: parts(:) !< parts of the given path
399
400 integer :: i
401 character(len=len_trim(path)) :: temp, comp
402
403 ! create array to join
404 temp = trim(path)
405 allocate(parts(0))
406 ! stop if we can't further split the path
407 do while (len_trim(temp) > 0)
408 if (path_isroot(temp)) then
409 ! POSIX allows one or two initial slashes, but treats three or more as single slash.
410 if (len_trim(temp) == 2) then
411 call append(parts, temp)
412 else
413 call append(parts, sep)
414 end if
415 exit
416 end if
417 ! get next component
418 call path_split(temp, temp, comp)
419 if (len_trim(comp) > 0) call append(parts, comp)
420 end do
421
422 ! reverse only if 2 or more elements
423 if (size(parts) > 1) parts = [(parts(i), i = size(parts), 1, -1)]
424
425 end subroutine path_parts
426
427 ! ------------------------------------------------------------------
428 !> \brief Return the directory name of pathname path.
429 !> \details This is the first element of the pair returned by passing path to the subroutine path_split.
430 !> \author Sebastian Müller
431 !> \date Mar 2023
432 function path_dirname(path) result(dirname)
433 implicit none
434 character(len=*), intent(in) :: path !< given path
435 character(:), allocatable :: dirname !< dirname
436
437 character(len=len_trim(path)) :: temp
438
439 call path_split(path, head=temp)
440 dirname = trim(temp)
441
442 end function path_dirname
443
444 ! ------------------------------------------------------------------
445 !> \brief Return the base name of pathname path.
446 !> \details This is the second element of the pair returned by passing path to the subroutine path_split.
447 !> \author Sebastian Müller
448 !> \date Mar 2023
449 function path_basename(path) result(basename)
450 implicit none
451 character(len=*), intent(in) :: path !< given path
452 character(:), allocatable :: basename !< basename
453
454 character(len=len_trim(path)) :: temp
455
456 call path_split(path, tail=temp)
457 basename = trim(temp)
458
459 end function path_basename
460
461 ! ------------------------------------------------------------------
462 !> \brief Return the path without its suffix.
463 !> \author Sebastian Müller
464 !> \date Mar 2023
465 function path_root(path) result(root)
466 implicit none
467 character(len=*), intent(in) :: path !< given path
468 character(:), allocatable :: root !< root
469
470 character(len=len_trim(path)) :: temp
471
472 call path_splitext(path, root=temp)
473 root = trim(temp)
474
475 end function path_root
476
477 ! ------------------------------------------------------------------
478 !> \brief Return the file extension of the final path component.
479 !> \author Sebastian Müller
480 !> \date Mar 2023
481 function path_ext(path) result(ext)
482 implicit none
483 character(len=*), intent(in) :: path !< given path
484 character(:), allocatable :: ext !< ext
485
486 character(len=len_trim(path)) :: temp
487
488 call path_splitext(path, ext=temp)
489 ext = trim(temp)
490
491 end function path_ext
492
493 ! ------------------------------------------------------------------
494 !> \brief Return the final path component without its suffix.
495 !> \author Sebastian Müller
496 !> \date Mar 2023
497 function path_stem(path) result(stem)
498 implicit none
499 character(len=*), intent(in) :: path !< given path
500 character(:), allocatable :: stem !< stem
501
502 character(len=len_trim(path)) :: temp, tail
503
504 call path_split(path, tail=tail)
505 call path_splitext(tail, root=temp)
506 stem = trim(temp)
507
508 end function path_stem
509
510 ! ------------------------------------------------------------------
511 !> \brief Return the string representation of the path with forward (/) slashes.
512 !> \author Sebastian Müller
513 !> \date Mar 2023
514 function path_as_posix(path) result(posix)
515 use mo_string_utils, only : replace_text
516 implicit none
517 character(len=*), intent(in) :: path !< given path
518 character(:), allocatable :: posix !< posix version of the path
519
520 posix = trim(replace_text(path, "\\", sep))
521
522 end function path_as_posix
523
524 ! ------------------------------------------------------------------
525 !> \brief Normalize a pathname by collapsing redundant separators and up-level references.
526 !> \details Normalize a pathname by collapsing redundant separators and up-level references so that
527 !! A//B, A/B/, A/./B and A/foo/../B all become A/B.
528 !! This string manipulation may change the meaning of a path that contains symbolic links.
529 !> \author Sebastian Müller
530 !> \date Mar 2023
531 function path_normpath(path) result(normpath)
532 use mo_append, only : append
533 implicit none
534 character(len=*), intent(in) :: path !< given path
535 character(:), allocatable :: normpath !< normalized path
536
537 character(len=len_trim(path)) :: temp, comp, root
538 character(len=len_trim(path)), allocatable :: comps_raw(:), comps(:)
539 integer :: i
540 logical :: has_root ! flag to indicate an absolute path
541
542 ! get path components
543 call path_parts(path, comps_raw)
544 ! return '.' for empty path
545 if (size(comps_raw) == 0) then
546 normpath = curdir
547 return
548 end if
549
550 has_root = path_isroot(comps_raw(1))
551
552 allocate(comps(0))
553 ! care about '.' and '..'
554 do i = 1, size(comps_raw)
555 comp = comps_raw(i)
556 if ( len_trim(comp) == 0 ) cycle ! skip empty
557 if ( trim(comp) == curdir ) cycle ! skip '.'
558 ! handle '..'
559 if ( trim(comp) /= pardir ) then
560 ! append normal component
561 call append(comps, comp)
562 else if (.not. has_root .and. (size(comps) == 0)) then
563 ! if '..' but we can't pop anything, append
564 call append(comps, comp)
565 else if ( size(comps) > 0 ) then
566 if (comps(size(comps)) == pardir) then
567 ! if '..' but previous is also '..', append
568 call append(comps, comp)
569 else if (.not. path_isroot(comps(size(comps)))) then
570 ! if '..' pop previous folder if it is not root
571 call pop(comps)
572 end if
573 end if
574 ! in all other cases, don't append anything
575 end do
576
577 if (size(comps) > 0) then
578 normpath = path_join_arr(comps)
579 else
580 ! '.' if no components given
581 normpath = curdir
582 end if
583
584 end function path_normpath
585
586 ! ------------------------------------------------------------------
587 !> \brief Return a normalized absolutized version of the given path.
588 !> \author Sebastian Müller
589 !> \date Mar 2023
590 function path_abspath(path) result(abspath)
591 implicit none
592 character(len=*), intent(in) :: path !< given path
593 character(:), allocatable :: abspath !< stem
594
595 character(len=max_path_len) :: cwd
596
597 call get_cwd(cwd)
598 abspath = path_normpath(path_join_char(cwd, path))
599
600 end function path_abspath
601
602 ! ------------------------------------------------------------------
603 !> \brief Join two path segments with separator if needed.
604 !> \details If the second segment is an absolute path, the first one will be ignored.
605 !> \author Sebastian Müller
606 !> \date Mar 2023
607 function path_join_char(p1, p2) result(join)
608 use mo_string_utils, only : endswith
609 implicit none
610 character(len=*), intent(in) :: p1, p2 ! given paths
611 character(:), allocatable :: join !< joined paths
612
613 if (path_isabs(p2)) then
614 ! if second path is absolute, first path gets ignored
615 join = trim(p2)
616 else
617 ! check if sep should be added (p1 not empty and not ending with sep)
618 if ( (len_trim(p1) > 0) .and. .not. endswith(p1, sep) ) then
619 join = trim(p1) // sep // trim(p2)
620 else
621 join = trim(p1) // trim(p2)
622 end if
623 end if
624
625 end function path_join_char
626
627 ! ------------------------------------------------------------------
628 !> \brief Join given path segments with separator if needed.
629 !> \details If a segment is an absolute path, the previous ones will be ignored.
630 !> \author Sebastian Müller
631 !> \date Mar 2023
632 function path_join_char_opt(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) result(join)
633 use mo_string_utils, only : endswith
634 implicit none
635 character(len=*), intent(in) :: p1 !< initial path
636 character(len=*), intent(in), optional :: p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16 ! given paths
637 character(:), allocatable :: join !< joined paths
638
639 join = p1
640 if (present(p2)) join = path_join_char(join, p2)
641 if (present(p3)) join = path_join_char(join, p3)
642 if (present(p4)) join = path_join_char(join, p4)
643 if (present(p5)) join = path_join_char(join, p5)
644 if (present(p6)) join = path_join_char(join, p6)
645 if (present(p7)) join = path_join_char(join, p7)
646 if (present(p8)) join = path_join_char(join, p8)
647 if (present(p9)) join = path_join_char(join, p9)
648 if (present(p10)) join = path_join_char(join, p10)
649 if (present(p11)) join = path_join_char(join, p11)
650 if (present(p12)) join = path_join_char(join, p12)
651 if (present(p13)) join = path_join_char(join, p13)
652 if (present(p14)) join = path_join_char(join, p14)
653 if (present(p15)) join = path_join_char(join, p15)
654 if (present(p16)) join = path_join_char(join, p16)
655
656 end function path_join_char_opt
657
658 ! ------------------------------------------------------------------
659 !> \brief Join given path segments with separator if needed.
660 !> \details If a segment is an absolute path, the previous ones will be ignored.
661 !> \author Sebastian Müller
662 !> \date Mar 2023
663 function path_join_arr(paths) result(join)
664 implicit none
665 character(len=*), dimension(:), intent(in) :: paths !< given paths
666 character(:), allocatable :: join !< joined paths
667
668 integer(i4) :: i
669
670 join = ""
671 do i = 1, size(paths)
672 join = path_join_char(join, paths(i))
673 end do
674 end function path_join_arr
675
676 ! ------------------------------------------------------------------
677
678 subroutine path_msg(msg, path, verbose, raise)
680 implicit none
681 character(len=*), intent(in), optional :: msg
682 character(len=*), intent(in), optional :: path
683 logical, intent(in), optional :: verbose
684 logical, intent(in), optional :: raise
685
686 logical :: raise_
687
688 raise_ = .false.
689 if (present(raise)) raise_ = raise
690 if (raise_) then ! LCOV_EXCL_LINE
691 call error_message(msg, trim(path), show=verbose) ! LCOV_EXCL_LINE
692 else
693 call message(msg, trim(path), show=verbose)
694 endif
695
696 end subroutine path_msg
697
698 !> \brief character array pop
699 subroutine pop(arr)
700 ! TODO: move to mo_utils; add other type versions
701 implicit none
702 character(len=*), allocatable, intent(inout) :: arr(:)
703
704 character(:), allocatable :: temp(:)
705
706 if (.not.allocated(arr)) return
707 if (size(arr) == 0) return
708
709 allocate(character(len(arr(1))) :: temp(size(arr)-1))
710 temp(:) = arr(1:size(arr)-1)
711 call move_alloc(temp, arr)
712
713 end subroutine pop
714
715end module mo_os
Append (rows) scalars, vectors, and matrixes onto existing array.
Join given path segments with separator if needed.
Definition mo_os.F90:49
Append values on existing arrays.
Definition mo_append.f90:20
Define number representations.
Definition mo_kind.F90:17
integer, parameter i4
4 Byte Integer Kind
Definition mo_kind.F90:40
Write out concatenated strings.
subroutine, public error_message(t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15, t16, uni, advance, show, raise, reset_format)
Write out an error message to stderr and call stop 1.
subroutine, public message(t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15, t16, uni, advance, show, reset_format)
Write out an error message to stdout.
Path and directory management.
Definition mo_os.F90:16
character(:) function, allocatable, public path_stem(path)
Return the final path component without its suffix.
Definition mo_os.F90:498
subroutine, public check_path_isdir(path, answer, verbose, raise)
Checks whether a given path exists and describes a directory.
Definition mo_os.F90:200
logical function, public path_isfile(path)
Return .true. if path is an existing regular file.
Definition mo_os.F90:233
character(:) function, allocatable, public path_root(path)
Return the path without its suffix.
Definition mo_os.F90:466
character(:) function, allocatable, public path_dirname(path)
Return the directory name of pathname path.
Definition mo_os.F90:433
character(len=*), parameter, public curdir
The constant string used by the operating system to refer to the current directory.
Definition mo_os.F90:55
character(:) function, allocatable, public path_abspath(path)
Return a normalized absolutized version of the given path.
Definition mo_os.F90:591
character(:) function, allocatable path_join_char_opt(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16)
Join given path segments with separator if needed.
Definition mo_os.F90:633
logical function, public path_exists(path)
Return .true. if path refers to an existing path.
Definition mo_os.F90:221
subroutine, public change_dir(path, status, verbose, raise)
Change current working directory.
Definition mo_os.F90:120
character(:) function, allocatable, public path_basename(path)
Return the base name of pathname path.
Definition mo_os.F90:450
subroutine, public get_cwd(path, status, verbose, raise)
Get the current working directory.
Definition mo_os.F90:82
character(:) function, allocatable, public path_as_posix(path)
Return the string representation of the path with forward (/) slashes.
Definition mo_os.F90:515
character(len=*), parameter, public sep
The character used by the operating system to separate pathname components.
Definition mo_os.F90:59
subroutine pop(arr)
character array pop
Definition mo_os.F90:700
logical function, public path_isroot(path)
Return .true. if path is root ('/' or '//' or '///' and so on).
Definition mo_os.F90:279
subroutine, public path_splitext(path, root, ext)
Splitting the path into root and ext.
Definition mo_os.F90:306
character(:) function, allocatable path_join_char(p1, p2)
Join two path segments with separator if needed.
Definition mo_os.F90:608
subroutine, public path_parts(path, parts)
Splitting the path into its components.
Definition mo_os.F90:395
character(:) function, allocatable, public path_normpath(path)
Normalize a pathname by collapsing redundant separators and up-level references.
Definition mo_os.F90:532
character(len=*), parameter, public pardir
The constant string used by the operating system to refer to the parent directory.
Definition mo_os.F90:57
subroutine, public path_split(path, head, tail)
Splitting the path into head and tail.
Definition mo_os.F90:358
character(:) function, allocatable, public path_ext(path)
Return the file extension of the final path component.
Definition mo_os.F90:482
logical function, public path_isdir(path)
Return .true. if path is an existing directory.
Definition mo_os.F90:247
character(:) function, allocatable path_join_arr(paths)
Join given path segments with separator if needed.
Definition mo_os.F90:664
character(len=*), parameter, public extsep
The character which separates the base filename from the extension.
Definition mo_os.F90:61
subroutine, public check_path_exists(path, answer, verbose, raise)
Checks whether a given path exists.
Definition mo_os.F90:158
subroutine, public check_path_isfile(path, answer, verbose, raise)
Checks whether a given path exists and describes a file.
Definition mo_os.F90:179
logical function, public path_isabs(path)
Return .true. if path is an absolute pathname.
Definition mo_os.F90:265
integer(i4), save, public max_path_len
Maximum length of a path (16 max. length components).
Definition mo_os.F90:69
character(len=*), parameter, public linesep
The string used to separate (or, rather, terminate) lines on the current platform.
Definition mo_os.F90:63
integer(i4), save, public max_path_comp_len
Maximum length of a path component (folder/file names).
Definition mo_os.F90:67
character(len=*), parameter, public devnull
The file path of the null device.
Definition mo_os.F90:65
String utilities.
logical function, public startswith(string, start, strip)
Checks if string starts with character(s)
logical function, public endswith(string, suffix, strip)
Checks if (maybe trimmed) string ends with given character(s)