1 | ! Copyright (c) (2013-2015,2017,2022) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). |
---|
2 | ! |
---|
3 | ! This file is part of SWIFT |
---|
4 | ! |
---|
5 | ! Permission is hereby granted, free of charge, to any person obtaining a copy of |
---|
6 | ! this software and associated documentation files (the "Software"), to deal in |
---|
7 | ! the Software without restriction, including without limitation the rights to |
---|
8 | ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
---|
9 | ! the Software, and to permit persons to whom the Software is furnished to do so, |
---|
10 | ! subject to the following conditions: |
---|
11 | ! |
---|
12 | ! The above copyright notice and this permission notice shall be included in all |
---|
13 | ! copies or substantial portions of the Software. |
---|
14 | ! |
---|
15 | ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
---|
16 | ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
---|
17 | ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
---|
18 | ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
---|
19 | ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
---|
20 | ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
---|
21 | |
---|
22 | !! file: fsystem.F90 |
---|
23 | !! summary: File system methods source file. |
---|
24 | !! author: J. Burgalat |
---|
25 | !! date: 2013-2015,2017,2022 |
---|
26 | |
---|
27 | |
---|
28 | #include "defined.h" |
---|
29 | |
---|
30 | MODULE FSYSTEM |
---|
31 | !! File system methods module |
---|
32 | USE, INTRINSIC :: ISO_C_BINDING |
---|
33 | USE ERRORS |
---|
34 | IMPLICIT NONE |
---|
35 | |
---|
36 | PUBLIC |
---|
37 | |
---|
38 | PRIVATE :: get_umask |
---|
39 | PRIVATE :: c2t |
---|
40 | |
---|
41 | INTEGER, PARAMETER :: MAX_PATH = 512 !! Maximum length of a path |
---|
42 | |
---|
43 | TYPE, PUBLIC :: chrono |
---|
44 | !! Define a simple chronometer |
---|
45 | !! |
---|
46 | !! This object can be used to get an approximation of the execution of some piece of code. |
---|
47 | REAL(kind=8), PRIVATE :: cpu_start = 0d0 |
---|
48 | !! Starting CPU time |
---|
49 | INTEGER(kind=8), PRIVATE :: clock_start = 0d0 |
---|
50 | !! Starting clock time |
---|
51 | LOGICAL, PRIVATE :: on_run = .false. |
---|
52 | !! Chrono running state. |
---|
53 | #if HAVE_FTNPROC |
---|
54 | CONTAINS |
---|
55 | PROCEDURE :: is_running => chrono_is_running |
---|
56 | PROCEDURE :: start => chrono_start |
---|
57 | PROCEDURE :: stop => chrono_stop |
---|
58 | PROCEDURE :: reset => chrono_reset |
---|
59 | PROCEDURE :: get => chrono_get |
---|
60 | #endif |
---|
61 | END TYPE chrono |
---|
62 | |
---|
63 | #ifndef FORD_DOC |
---|
64 | ! C interfaces |
---|
65 | INTERFACE |
---|
66 | FUNCTION strlen_c(s) RESULT(length) bind(C,name="strlen") |
---|
67 | !! Get length of C-string up to (but not including) the terminator |
---|
68 | IMPORT C_PTR, C_SIZE_T |
---|
69 | TYPE(C_PTR), INTENT(in), VALUE :: s !! C string (a C_PTR type) |
---|
70 | INTEGER(kind=C_SIZE_T) :: length !! An integer with the size of the string. |
---|
71 | END FUNCTION strlen_c |
---|
72 | |
---|
73 | SUBROUTINE free_c(ptr) bind(C,name="free") |
---|
74 | !! Free memory used by a C pointer |
---|
75 | IMPORT C_PTR |
---|
76 | TYPE(C_PTR), INTENT(in), VALUE :: ptr !! TYPE(C_PTR) object with the underlying C pointer to free |
---|
77 | END SUBROUTINE free_c |
---|
78 | |
---|
79 | FUNCTION errno_c() BIND(C,name="c_get_errno") |
---|
80 | !! Get last error numero |
---|
81 | IMPORT C_INT |
---|
82 | INTEGER(kind=C_INT) :: errno_c !! Last errno |
---|
83 | END FUNCTION errno_c |
---|
84 | |
---|
85 | FUNCTION usleep_c(usec) BIND(C,name="usleep") |
---|
86 | !! (attemps to) Sleep for a given number of microseconds |
---|
87 | IMPORT C_INT |
---|
88 | INTEGER(kind=C_INT), INTENT(in), VALUE :: usec !! Number of microseconds to sleep |
---|
89 | INTEGER(kind=C_INT) :: usleep_c !! An integer with 0 on success, last errno otherwise |
---|
90 | END FUNCTION usleep_c |
---|
91 | |
---|
92 | FUNCTION getgid_c() BIND(C, name="getgid") |
---|
93 | !! Get Group ID |
---|
94 | IMPORT C_INT |
---|
95 | INTEGER(kind=C_INT) :: getgid_c !! Group identifier |
---|
96 | END FUNCTION getgid_c |
---|
97 | |
---|
98 | FUNCTION getpid_c() BIND(C, name="getpid") |
---|
99 | !! Get Process ID |
---|
100 | IMPORT C_INT |
---|
101 | INTEGER(kind=C_INT) :: getpid_c !! Current process identifier |
---|
102 | END FUNCTION getpid_c |
---|
103 | |
---|
104 | FUNCTION getuid_c() BIND(C, name="getuid") |
---|
105 | !! Get User ID |
---|
106 | IMPORT C_INT |
---|
107 | INTEGER(kind=C_INT) :: getuid_c !! User identifier |
---|
108 | END FUNCTION getuid_c |
---|
109 | |
---|
110 | FUNCTION umask_c() BIND(C,name="c_umask") |
---|
111 | !! Get the current umask of the session |
---|
112 | IMPORT C_INT |
---|
113 | INTEGER(kind=C_INT) :: umask_c !! Current umask value in decimal system |
---|
114 | END FUNCTION umask_c |
---|
115 | |
---|
116 | FUNCTION access_c(path,perm) BIND(C,name="c_access") |
---|
117 | !! Check if path is accessible for current user |
---|
118 | IMPORT c_char, C_INT |
---|
119 | CHARACTER(len=c_char), INTENT(in) :: path(*) !! Path to check |
---|
120 | INTEGER(kind=C_INT), INTENT(in), VALUE :: perm !! User's permission to check |
---|
121 | INTEGER(kind=C_INT) :: access_c !! 0 on success, last errno on failure |
---|
122 | END FUNCTION access_c |
---|
123 | |
---|
124 | FUNCTION create_c(path,mode,asfile,forced) BIND(C,name="c_create") |
---|
125 | !! Create a directory or a file in given path |
---|
126 | IMPORT c_char, C_INT |
---|
127 | CHARACTER(len=c_char), INTENT(in) :: path(*) !! Path to create |
---|
128 | INTEGER(kind=C_INT), INTENT(in), VALUE :: mode, & !! Decimal permission of the path |
---|
129 | asfile, & !! 0 to create a directory, any other value to create file |
---|
130 | forced !! non-zero value to force the creation of intermediate directories |
---|
131 | INTEGER(kind=C_INT) :: create_c !! 0 on success, last errno otherwise |
---|
132 | END FUNCTION create_c |
---|
133 | |
---|
134 | FUNCTION uname_c(uid) BIND(C, name="c_uname") |
---|
135 | !! Get the name of the given user id |
---|
136 | IMPORT C_INT, c_ptr |
---|
137 | INTEGER(kind=C_INT), INTENT(in), VALUE :: uid !! User id |
---|
138 | TYPE(C_PTR) :: uname_c !! C_PTR to the underlying char* pointer storing user name |
---|
139 | END FUNCTION uname_c |
---|
140 | |
---|
141 | FUNCTION gname_c(gid) BIND(C, name="c_gname") |
---|
142 | !! Get the name of the given group id |
---|
143 | IMPORT C_INT, c_ptr |
---|
144 | INTEGER(kind=C_INT), INTENT(in), VALUE :: gid !! Group id |
---|
145 | TYPE(C_PTR) :: gname_c !! C_PTR to the underlying char* pointer storing group name |
---|
146 | END FUNCTION gname_c |
---|
147 | |
---|
148 | FUNCTION dirname_c(path) BIND(C,name="c_dirname") |
---|
149 | !! Get the directory name of the path |
---|
150 | IMPORT c_char, c_ptr |
---|
151 | CHARACTER(kind=c_char), INTENT(in) :: path(*) !! Input path |
---|
152 | TYPE(C_PTR) :: dirname_c !! C_PTR to the underlying char* pointer storing dirname |
---|
153 | END FUNCTION dirname_c |
---|
154 | |
---|
155 | FUNCTION basename_c(path) BIND(C,name="c_basename") |
---|
156 | !! Get the basename of the path |
---|
157 | IMPORT c_char, c_ptr |
---|
158 | CHARACTER(kind=c_char), INTENT(in) :: path(*) !! Input path |
---|
159 | TYPE(C_PTR) :: basename_c !! C_PTR to the underlying char* pointer sotring basename |
---|
160 | END FUNCTION basename_c |
---|
161 | |
---|
162 | FUNCTION getcwd_c() BIND(C,name="c_getcwd") |
---|
163 | !! Get the current working directory |
---|
164 | IMPORT c_ptr |
---|
165 | TYPE(C_PTR) :: getcwd_c !! C_PTR to the underlying char* pointer storing current working directory |
---|
166 | END FUNCTION getcwd_c |
---|
167 | |
---|
168 | FUNCTION realpath_c(path) BIND(C, name="c_realpath") |
---|
169 | !! Get the real path from given path |
---|
170 | IMPORT c_char, c_ptr |
---|
171 | CHARACTER(kind=c_char), INTENT(in) :: path(*) !! The path to expand |
---|
172 | TYPE(C_PTR) :: realpath_c !! C_PTR to the underlying char* pointer storing realpath |
---|
173 | END FUNCTION realpath_c |
---|
174 | |
---|
175 | FUNCTION relpath_c(fname,reldir) BIND(C, name="c_relpath") |
---|
176 | !! Get the relative path of path from another |
---|
177 | IMPORT c_char, c_ptr |
---|
178 | CHARACTER(kind=c_char), INTENT(in) :: fname(*), & !! Path to process |
---|
179 | reldir(*) !! New base path |
---|
180 | TYPE(C_PTR) :: relpath_c !! C_PTR to the underlying char* pointer storing relative path |
---|
181 | END FUNCTION |
---|
182 | |
---|
183 | FUNCTION rename_c(input,output) BIND(C,name="c_rename") |
---|
184 | !! Rename a path |
---|
185 | IMPORT c_char, C_INT |
---|
186 | CHARACTER(kind=c_char), INTENT(in) :: input(*) !! Path to rename |
---|
187 | CHARACTER(kind=c_char), INTENT(in) :: output(*) !! New name of the path |
---|
188 | INTEGER(kind=C_INT) :: rename_c !! 0 on success, last errno on failure |
---|
189 | END FUNCTION rename_c |
---|
190 | |
---|
191 | FUNCTION chmod_c(path,mode) BIND(C,name="c_chmod") |
---|
192 | !! Change file/directory permissions |
---|
193 | IMPORT c_char, C_INT |
---|
194 | CHARACTER(kind=c_char), INTENT(in) :: path(*) !! Path to modify |
---|
195 | INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! New decimal permissions of the path to set |
---|
196 | INTEGER(kind=C_INT) :: chmod_c !! 0 on success, last errno on failure |
---|
197 | END FUNCTION chmod_c |
---|
198 | |
---|
199 | FUNCTION chdir_c(new) BIND(C,name="c_chdir") |
---|
200 | !! Change current directory |
---|
201 | IMPORT c_char, C_INT |
---|
202 | CHARACTER(kind=c_char), INTENT(in) :: new(*) !! Path of the new working directory |
---|
203 | INTEGER(kind=C_INT) :: chdir_c !! 0 on success, last errno on failure |
---|
204 | END FUNCTION chdir_c |
---|
205 | |
---|
206 | FUNCTION mkdir_c(dirname,mode) BIND(C,name="c_mkdir") |
---|
207 | !! Create directory |
---|
208 | IMPORT c_char, C_INT |
---|
209 | CHARACTER(kind=c_char), INTENT(in) :: dirname(*) !! Path of the directory to create |
---|
210 | INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! Decimal permission to set |
---|
211 | INTEGER(kind=C_INT) :: mkdir_c !! 0 on success, last errno on failure |
---|
212 | END FUNCTION mkdir_c |
---|
213 | |
---|
214 | FUNCTION mkdirp_c(dirname,mode) BIND(C,name="c_mkdirp") |
---|
215 | !! Create directory recursively |
---|
216 | IMPORT c_char, C_INT |
---|
217 | CHARACTER(kind=c_char), INTENT(in) :: dirname(*) !! Path of the directory to create |
---|
218 | INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! Decimal permission to set |
---|
219 | INTEGER(kind=C_INT) :: mkdirp_c !! 0 on success, last errno on failure |
---|
220 | END FUNCTION mkdirp_c |
---|
221 | |
---|
222 | FUNCTION copy_c(to,from) BIND(C,name="c_copy") |
---|
223 | !! Copy a file. |
---|
224 | IMPORT c_char, C_INT |
---|
225 | CHARACTER(kind=c_char), INTENT(in) :: to(*) !! Destination path. |
---|
226 | CHARACTER(kind=c_char), INTENT(in) :: from(*) !! Input file path to copy. |
---|
227 | INTEGER(kind=C_INT) :: copy_c !! 0 on success, 1 on failure. |
---|
228 | END FUNCTION copy_c |
---|
229 | |
---|
230 | FUNCTION remove_c(path) BIND(C,name="c_remove") |
---|
231 | !! Remove a file (or a directory) from the filesystem |
---|
232 | IMPORT c_char, C_INT |
---|
233 | CHARACTER(kind=c_char), INTENT(in) :: path(*) !! Path to delete |
---|
234 | INTEGER(kind=C_INT) :: remove_c !! 0 on success, last errno on failure |
---|
235 | END FUNCTION remove_c |
---|
236 | |
---|
237 | FUNCTION rmdir_c(dirpath) BIND(C,name="c_rmdir") |
---|
238 | !! Remove empty directory |
---|
239 | IMPORT c_char, C_INT |
---|
240 | CHARACTER(kind=c_char), INTENT(in) :: dirpath(*) !! Directory to delete |
---|
241 | INTEGER(kind=C_INT) :: rmdir_c !! 0 on success, last errno on failure |
---|
242 | END FUNCTION rmdir_c |
---|
243 | |
---|
244 | FUNCTION rmdirf_c(dirpath) BIND(C,name="c_rmdir_f") |
---|
245 | !! Remove directory (forced) |
---|
246 | IMPORT c_char, C_INT |
---|
247 | CHARACTER(kind=c_char), INTENT(in) :: dirpath(*) !! Directory to delete |
---|
248 | INTEGER(kind=C_INT) :: rmdirf_c !! 0 on success, last errno on failure |
---|
249 | END FUNCTION rmdirf_c |
---|
250 | |
---|
251 | FUNCTION fstat_c(pa, pe, ln, ty, ui, gi, si, at, mt, ct) BIND(C, name='c_fstat') |
---|
252 | !! Get file informations |
---|
253 | IMPORT c_char, c_long, C_INT |
---|
254 | CHARACTER(kind=c_char), INTENT(in) :: pa(*) !! Path of the file |
---|
255 | INTEGER(kind=C_INT), INTENT(out) :: pe !! Decimal permission of the path |
---|
256 | INTEGER(kind=C_INT), INTENT(out) :: ln !! Number of links |
---|
257 | INTEGER(kind=C_INT), INTENT(out) :: ty !! Type of the path |
---|
258 | INTEGER(kind=C_INT), INTENT(out) :: ui !! User ID of the path |
---|
259 | INTEGER(kind=C_INT), INTENT(out) :: gi !! Group ID of the path |
---|
260 | INTEGER(kind=c_long), INTENT(out) :: si !! Size of the path |
---|
261 | CHARACTER(kind=c_char), INTENT(out) :: at(20) !! Last access date |
---|
262 | CHARACTER(kind=c_char), INTENT(out) :: mt(20) !! Last modification date |
---|
263 | CHARACTER(kind=c_char), INTENT(out) :: ct(20) !! Creation date |
---|
264 | INTEGER(kind=C_INT) :: fstat_c !! 0 on success, last errno on failure |
---|
265 | END FUNCTION fstat_c |
---|
266 | |
---|
267 | FUNCTION termsize_c(r,c) BIND(C, name='c_termsize') |
---|
268 | !! Get terminal window size |
---|
269 | IMPORT C_INT |
---|
270 | INTEGER(kind=C_INT), INTENT(out) :: r, & !! Number of rows |
---|
271 | c !! Number of columns |
---|
272 | INTEGER(kind=C_INT) :: termsize_c !! 0 on success, last errno on failure |
---|
273 | END FUNCTION termsize_c |
---|
274 | |
---|
275 | FUNCTION getCurrentRSS_c() BIND(C, name="c_getCurrentRSS") |
---|
276 | !! Get the current resident set size memory in bytes. |
---|
277 | IMPORT C_SIZE_T |
---|
278 | INTEGER(kind=C_SIZE_T) :: getCurrentRSS_c !! Current resident set size in bytes (0 if not available). |
---|
279 | END FUNCTION getCurrentRSS_c |
---|
280 | |
---|
281 | FUNCTION getPeakRSS_c() BIND(C, name="c_getPeakRSS") |
---|
282 | !! Get the peak resident set size memory in bytes. |
---|
283 | IMPORT C_SIZE_T |
---|
284 | INTEGER(kind=C_SIZE_T) :: getPeakRSS_c !! Peak resident set size in bytes (0 if not available). |
---|
285 | END FUNCTION getPeakRSS_c |
---|
286 | |
---|
287 | FUNCTION getSystemMemory_c(total,avail,free) BIND(C, name='c_getSystemMemory') |
---|
288 | !! Get global memory informations. |
---|
289 | IMPORT C_LONG_LONG,C_INT |
---|
290 | INTEGER(kind=C_LONG_LONG), INTENT(out) :: total !! Total available memory. |
---|
291 | INTEGER(kind=C_LONG_LONG), INTENT(out) :: avail !! Current available memory. |
---|
292 | INTEGER(kind=C_LONG_LONG), INTENT(out) :: free !! Current free memory. |
---|
293 | INTEGER(kind=C_INT) :: getSystemMemory_c !! status, 0 on success, 1 otherwise. |
---|
294 | END FUNCTION getSystemMemory_c |
---|
295 | END INTERFACE |
---|
296 | #endif |
---|
297 | |
---|
298 | CONTAINS |
---|
299 | |
---|
300 | FUNCTION fstring(string) RESULT(str) |
---|
301 | !! Convert C string to Fortran string |
---|
302 | !! |
---|
303 | !! The method copies the input C string up to the last C_NULL_CHAR found (not including it), |
---|
304 | !! and returns the converted Fortran string. |
---|
305 | !! All other C_NULL_CHAR found in the C string are removed. |
---|
306 | CHARACTER(len=*), INTENT(in) :: string !! A string from C |
---|
307 | CHARACTER(len=:), ALLOCATABLE :: str !! Converted fortran string |
---|
308 | INTEGER :: i,idx |
---|
309 | str = "" |
---|
310 | idx = INDEX(string,C_NULL_CHAR,.true.) |
---|
311 | IF (idx == 0) THEN |
---|
312 | str = string |
---|
313 | ELSE |
---|
314 | DO i=1,idx-1 |
---|
315 | IF (string(i:i) /= C_NULL_CHAR) str = str//string(i:i) |
---|
316 | ENDDO |
---|
317 | ENDIF |
---|
318 | str = TRIM(str) |
---|
319 | END FUNCTION fstring |
---|
320 | |
---|
321 | FUNCTION cstr2fstr(cstr) RESULT(fstr) |
---|
322 | !! Get a Fortran (allocatable) string from a C string |
---|
323 | !! |
---|
324 | !! The method build the fortran string from a TYPE(C_PTR) object that represent a |
---|
325 | !! C char\* pointer string. |
---|
326 | !! @note |
---|
327 | !! If __cstr__ is not allocated (i.e. the C_PTR is not associated) or if it is set |
---|
328 | !! to a C empty string (i.e. '\0') then the method returns an empty string. |
---|
329 | !! @attention |
---|
330 | !! The method does not free the underlying C string and it should be free using |
---|
331 | !! the subroutine free_c(_cstr_). |
---|
332 | TYPE(C_PTR), INTENT(in) :: cstr |
---|
333 | !! A TYPE(C_PTR) that represent the pointer to the C char array. |
---|
334 | CHARACTER(len=:), ALLOCATABLE :: fstr |
---|
335 | !! An allocatable Fortran string with the content of the input char array. |
---|
336 | CHARACTER(len=1,kind=C_CHAR), DIMENSION(:), POINTER :: pchars |
---|
337 | INTEGER :: i,length |
---|
338 | IF (.NOT.C_ASSOCIATED(cstr)) THEN |
---|
339 | fstr = "" |
---|
340 | RETURN |
---|
341 | ENDIF |
---|
342 | length = INT(strlen_c(cstr), kind=4) |
---|
343 | IF (length ==0) THEN |
---|
344 | fstr = "" |
---|
345 | RETURN |
---|
346 | ENDIF |
---|
347 | CALL C_F_POINTER(cstr,pchars,(/length/)) |
---|
348 | ALLOCATE(CHARACTER(len=length) :: fstr) |
---|
349 | DO i=1,length |
---|
350 | fstr(i:i) = pchars(i) |
---|
351 | ENDDO |
---|
352 | END FUNCTION cstr2fstr |
---|
353 | |
---|
354 | |
---|
355 | FUNCTION cstring(string) RESULT(str) |
---|
356 | !> convert Fortran string to cstring |
---|
357 | !! |
---|
358 | !! The method returns a copy of the input string suitable for C functions argument. |
---|
359 | !! @note |
---|
360 | !! Input string is trimmed during computations |
---|
361 | CHARACTER(len=*), INTENT(in) :: string |
---|
362 | !! A fortran string |
---|
363 | CHARACTER(len=:,kind=C_CHAR), ALLOCATABLE :: str |
---|
364 | !! Same string as __string__ except that C_NULL_CHAR is appended at the end |
---|
365 | INTEGER :: slen |
---|
366 | slen = LEN_TRIM(string) |
---|
367 | ALLOCATE(CHARACTER(len=slen+1,kind=C_CHAR) :: str) |
---|
368 | str(:slen) = TRIM(string) ; str(slen+1:slen+1) = C_NULL_CHAR |
---|
369 | END FUNCTION cstring |
---|
370 | |
---|
371 | !=============================================================================== |
---|
372 | ! C WRAPPER FUNCTIONS/SUBROUTINES |
---|
373 | !=============================================================================== |
---|
374 | |
---|
375 | FUNCTION fs_getgid() RESULT(ret) |
---|
376 | !! Get Group ID |
---|
377 | INTEGER(kind=4) :: ret !! An integer with the group identifier |
---|
378 | ret = INT(getgid_c(),kind=4) |
---|
379 | RETURN |
---|
380 | END FUNCTION fs_getgid |
---|
381 | |
---|
382 | FUNCTION fs_getpid() RESULT(ret) |
---|
383 | !! Get Process ID |
---|
384 | INTEGER(kind=4) :: ret !! An integer with the current process identifier |
---|
385 | ret = INT(getpid_c(),kind=4) |
---|
386 | RETURN |
---|
387 | END FUNCTION fs_getpid |
---|
388 | |
---|
389 | FUNCTION fs_getuid() RESULT(ret) |
---|
390 | !! Get User ID |
---|
391 | INTEGER(kind=4) :: ret !! An integer with the user identifier |
---|
392 | ret = INT(getuid_c(),kind=4) |
---|
393 | RETURN |
---|
394 | END FUNCTION fs_getuid |
---|
395 | |
---|
396 | FUNCTION fs_gname(gid) RESULT(gname) |
---|
397 | !! Get a group name from a group id |
---|
398 | INTEGER, INTENT(in) :: gid !! User id to check |
---|
399 | CHARACTER(len=:), ALLOCATABLE :: gname !! A string with the name of the group id |
---|
400 | TYPE(C_PTR) :: zname |
---|
401 | zname = gname_c(gid) |
---|
402 | IF (.NOT.C_ASSOCIATED(zname)) THEN |
---|
403 | gname = "" |
---|
404 | ELSE |
---|
405 | gname = cstr2fstr(zname) |
---|
406 | ENDIF |
---|
407 | CALL free_c(zname) |
---|
408 | END FUNCTION fs_gname |
---|
409 | |
---|
410 | FUNCTION fs_uname(uid) RESULT(uname) |
---|
411 | !! Get a user name from a user id |
---|
412 | INTEGER, INTENT(in) :: uid !! User id to check |
---|
413 | CHARACTER(len=:), ALLOCATABLE :: uname !! A string with the name of the user id |
---|
414 | TYPE(C_PTR) :: zname |
---|
415 | zname = gname_c(uid) |
---|
416 | IF (.NOT.C_ASSOCIATED(zname)) THEN |
---|
417 | uname = "" |
---|
418 | ELSE |
---|
419 | uname = cstr2fstr(zname) |
---|
420 | ENDIF |
---|
421 | CALL free_c(zname) |
---|
422 | END FUNCTION fs_uname |
---|
423 | |
---|
424 | FUNCTION fs_dirname(path) RESULT(opath) |
---|
425 | !! Get the parent directory path of the given path |
---|
426 | CHARACTER(len=*), INTENT(in) :: path |
---|
427 | !! A string with a (valid) path |
---|
428 | CHARACTER(len=:), ALLOCATABLE :: opath |
---|
429 | !! A Fortran allocated string with the parent directory path or an empty string if method fails |
---|
430 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
431 | TYPE(C_PTR) :: zpath |
---|
432 | IF (LEN_TRIM(path) == 0) THEN |
---|
433 | opath = "" |
---|
434 | RETURN |
---|
435 | ENDIF |
---|
436 | cpath = cstring(ADJUSTL(path)) |
---|
437 | zpath = dirname_c(cpath) |
---|
438 | IF (.NOT.C_ASSOCIATED(zpath)) THEN |
---|
439 | opath = "" |
---|
440 | ELSE |
---|
441 | opath = cstr2fstr(zpath) |
---|
442 | ENDIF |
---|
443 | CALL free_c(zpath) |
---|
444 | END FUNCTION fs_dirname |
---|
445 | |
---|
446 | FUNCTION fs_basename(path) RESULT(opath) |
---|
447 | !! Get the base name of the path |
---|
448 | CHARACTER(len=*), INTENT(in) :: path |
---|
449 | !! A string with a (valid) path |
---|
450 | CHARACTER(len=:), ALLOCATABLE :: opath |
---|
451 | !! The basename of the path or an empty string if method fails |
---|
452 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
453 | TYPE(C_PTR) :: zpath |
---|
454 | IF (LEN_TRIM(path) == 0) THEN |
---|
455 | opath = "" |
---|
456 | RETURN |
---|
457 | ENDIF |
---|
458 | cpath = cstring(ADJUSTL(path)) |
---|
459 | zpath = basename_c(cpath) |
---|
460 | IF (.NOT.C_ASSOCIATED(zpath)) THEN |
---|
461 | opath = "" |
---|
462 | ELSE |
---|
463 | opath = cstr2fstr(zpath) |
---|
464 | ENDIF |
---|
465 | CALL free_c(zpath) |
---|
466 | END FUNCTION fs_basename |
---|
467 | |
---|
468 | FUNCTION fs_realpath(path) RESULT(opath) |
---|
469 | !! Get the real path of the path |
---|
470 | !! |
---|
471 | !! The method computes the absolute path of the given path using C realpath function. |
---|
472 | !! @note |
---|
473 | !! If the input path is empty then current working directory is returned. |
---|
474 | CHARACTER(len=*), INTENT(in) :: path |
---|
475 | !! A string with a (valid) path |
---|
476 | CHARACTER(len=:), ALLOCATABLE :: opath |
---|
477 | !! The absolute of the path or an empty string if method fails |
---|
478 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
479 | TYPE(C_PTR) :: zpath |
---|
480 | cpath = cstring(ADJUSTL(path)) |
---|
481 | zpath = realpath_c(cpath) |
---|
482 | IF (.NOT.C_ASSOCIATED(zpath)) THEN |
---|
483 | opath = "" |
---|
484 | ELSE |
---|
485 | opath = cstr2fstr(zpath) |
---|
486 | ENDIF |
---|
487 | CALL free_c(zpath) |
---|
488 | END FUNCTION fs_realpath |
---|
489 | |
---|
490 | FUNCTION fs_relpath(path,reldir) RESULT(res) |
---|
491 | !! Get the relative representation of two paths |
---|
492 | !! |
---|
493 | !! The method computes the relative representation of __path__ from __reldir__ if possible. |
---|
494 | !! If no common prefix is found, the method returns __path__. |
---|
495 | CHARACTER(len=*), INTENT(in) :: path, & !! Path to be computed relative to reldir |
---|
496 | reldir !! A directory path from which output should be relative to |
---|
497 | CHARACTER(len=:), ALLOCATABLE :: res !! An allocated string with the resulting path |
---|
498 | CHARACTER(len=:), ALLOCATABLE :: cpath1,cpath2 |
---|
499 | TYPE(C_PTR) :: zpath |
---|
500 | cpath1 = cstring(ADJUSTL(path)) |
---|
501 | cpath2 = cstring(ADJUSTL(reldir)) |
---|
502 | zpath = relpath_c(cpath1,cpath2) |
---|
503 | IF (.NOT.C_ASSOCIATED(zpath)) THEN |
---|
504 | res = TRIM(ADJUSTL(path)) |
---|
505 | ELSE |
---|
506 | res = cstr2fstr(zpath) |
---|
507 | ENDIF |
---|
508 | CALL free_c(zpath) |
---|
509 | END FUNCTION fs_relpath |
---|
510 | |
---|
511 | FUNCTION fs_getcwd() RESULT(path) |
---|
512 | !! Get the current working directory |
---|
513 | CHARACTER(len=:), ALLOCATABLE :: path |
---|
514 | !! The current working directory or an empty string if method fails |
---|
515 | TYPE(C_PTR) :: zpath |
---|
516 | zpath = getcwd_c() |
---|
517 | IF (C_ASSOCIATED(zpath)) THEN |
---|
518 | path = cstr2fstr(zpath) |
---|
519 | ELSE |
---|
520 | path = "" |
---|
521 | ENDIF |
---|
522 | CALL free_c(zpath) |
---|
523 | RETURN |
---|
524 | END FUNCTION fs_getcwd |
---|
525 | |
---|
526 | FUNCTION fs_copy(input,output) RESULT(ret) |
---|
527 | !! Copy input file into output file. |
---|
528 | CHARACTER(len=*), INTENT(in) :: input !! Input file path to copy. |
---|
529 | CHARACTER(len=*), INTENT(in) :: output !! Output file path destination. |
---|
530 | LOGICAL :: ret !! True on success, false otherwise. |
---|
531 | CHARACTER(len=:), ALLOCATABLE :: cpath1,cpath2 |
---|
532 | |
---|
533 | IF (LEN_TRIM(input) == 0 .OR. LEN_TRIM(output) == 0 .OR. input == output) THEN |
---|
534 | ret = .false. |
---|
535 | ELSE |
---|
536 | cpath1 = cstring(ADJUSTL(output)) |
---|
537 | cpath2 = cstring(ADJUSTL(input)) |
---|
538 | ret = INT(copy_c(cpath1,cpath2)) == 0 |
---|
539 | ENDIF |
---|
540 | RETURN |
---|
541 | END FUNCTION fs_copy |
---|
542 | |
---|
543 | FUNCTION fs_remove(path) RESULT(ret) |
---|
544 | !! Delete the file/directory pointed by the given path |
---|
545 | CHARACTER(len=*), INTENT(in) :: path !! A string with the (valid) file path to delete |
---|
546 | LOGICAL :: ret !! True on success, false otherwise. |
---|
547 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
548 | IF (LEN_TRIM(path) == 0) THEN |
---|
549 | ret = .false. |
---|
550 | ELSE |
---|
551 | cpath = cstring(ADJUSTL(path)) |
---|
552 | ret = INT(remove_c(cpath)) == 0 |
---|
553 | ENDIF |
---|
554 | RETURN |
---|
555 | END FUNCTION fs_remove |
---|
556 | |
---|
557 | FUNCTION fs_rename(old, new) RESULT(ret) |
---|
558 | !! Rename a path |
---|
559 | CHARACTER(len=*), INTENT(in) :: old, & !! A string with the (valid) path to rename |
---|
560 | new !! A string with the new name of the path |
---|
561 | LOGICAL :: ret !! True on success, false otherwise. |
---|
562 | CHARACTER(len=:), ALLOCATABLE :: cpath1,cpath2 |
---|
563 | IF (LEN_TRIM(old) == 0.OR.LEN_TRIM(new) == 0) THEN |
---|
564 | ret = .false. |
---|
565 | ELSE |
---|
566 | cpath1 = cstring(ADJUSTL(old)) |
---|
567 | cpath2 = cstring(ADJUSTL(new)) |
---|
568 | ret = INT(rename_c(cpath1,cpath2)) == 0 |
---|
569 | ENDIF |
---|
570 | RETURN |
---|
571 | END FUNCTION fs_rename |
---|
572 | |
---|
573 | FUNCTION fs_chmod(path, mode) RESULT(ret) |
---|
574 | !! Change file/directory permissions |
---|
575 | CHARACTER(len=*), INTENT(in) :: path !! Path to modify |
---|
576 | INTEGER, INTENT(in) :: mode !! New octal permissions of the file |
---|
577 | LOGICAL :: ret !! True on success, false otherwise. |
---|
578 | INTEGER(kind=C_INT) :: zmode |
---|
579 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
580 | IF (LEN_TRIM(path) == 0) THEN |
---|
581 | ret = .false. |
---|
582 | ELSE |
---|
583 | zmode = INT(oct_2_dec(mode),kind=C_INT) |
---|
584 | cpath = cstring(ADJUSTL(path)) |
---|
585 | ret = INT(chmod_c(cpath, zmode)) == 0 |
---|
586 | ENDIF |
---|
587 | RETURN |
---|
588 | END FUNCTION fs_chmod |
---|
589 | |
---|
590 | FUNCTION fs_chdir(path) RESULT(ret) |
---|
591 | !! Change current working directory |
---|
592 | CHARACTER(len=*), INTENT(in) :: path !! Path of the new working directory |
---|
593 | LOGICAL :: ret !! True on success, false otherwise. |
---|
594 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
595 | IF (LEN_TRIM(path) == 0) THEN |
---|
596 | ret = .false. |
---|
597 | ELSE |
---|
598 | cpath = cstring(ADJUSTL(path)) |
---|
599 | ret = INT(chdir_c(cpath)) == 0 |
---|
600 | ENDIF |
---|
601 | RETURN |
---|
602 | END FUNCTION fs_chdir |
---|
603 | |
---|
604 | FUNCTION fs_mkdir(path, mode, permissive) RESULT(ret) |
---|
605 | !! Create directory |
---|
606 | !! |
---|
607 | !! The method attempts to create a new directory pointed by __path__ with the permission |
---|
608 | !! given by mode. |
---|
609 | CHARACTER(len=*), INTENT(in) :: path |
---|
610 | !! The path to modify |
---|
611 | INTEGER, INTENT(in), OPTIONAL :: mode |
---|
612 | !! Optional octal permission to set for the new directory |
---|
613 | LOGICAL, INTENT(in), OPTIONAL :: permissive |
---|
614 | !! Optional boolean with .true. to create intermediate directories in the path |
---|
615 | LOGICAL :: ret |
---|
616 | !! True on success, false otherwise. |
---|
617 | INTEGER :: zmode |
---|
618 | LOGICAL :: zperm |
---|
619 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
620 | |
---|
621 | IF (LEN_TRIM(path) == 0) THEN |
---|
622 | ret = .false. |
---|
623 | ELSE |
---|
624 | zmode = oct_2_dec(744) |
---|
625 | IF (PRESENT(mode)) THEN |
---|
626 | IF (.NOT.chk_pm(mode)) THEN |
---|
627 | ret = .false. ; RETURN |
---|
628 | ENDIF |
---|
629 | zmode = oct_2_dec(mode) |
---|
630 | ENDIF |
---|
631 | cpath = cstring(ADJUSTL(path)) |
---|
632 | zperm = .false. ; IF (PRESENT(permissive)) zperm = permissive |
---|
633 | IF (zperm) THEN |
---|
634 | ret = INT(mkdirp_c(cpath,INT(zmode,kind=C_INT))) == 0 |
---|
635 | ELSE |
---|
636 | ret = INT(mkdir_c(cpath,INT(zmode,kind=C_INT))) == 0 |
---|
637 | ENDIF |
---|
638 | ENDIF |
---|
639 | RETURN |
---|
640 | END FUNCTION fs_mkdir |
---|
641 | |
---|
642 | FUNCTION fs_rmdir(path,forced) RESULT(ret) |
---|
643 | !! Remove directory |
---|
644 | !! |
---|
645 | !! By default, the function removes an __empty__ directory. If __forced__ is given and set |
---|
646 | !! to .true. then the function recursively deletes the directory and __ALL__ its content. |
---|
647 | CHARACTER(len=*), INTENT(in) :: path |
---|
648 | !! The path of the directory to delete |
---|
649 | LOGICAL, INTENT(in), OPTIONAL :: forced |
---|
650 | !! Optional boolean with @ti{.true.} to remove all contents of the directory. |
---|
651 | LOGICAL :: ret |
---|
652 | !! True on success, false otherwise. |
---|
653 | LOGICAL :: zforce |
---|
654 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
655 | IF (LEN_TRIM(path) == 0) THEN |
---|
656 | ret = .false. |
---|
657 | ELSE |
---|
658 | zforce = .false. ; IF (PRESENT(forced)) zforce = forced |
---|
659 | cpath = cstring(ADJUSTL(path)) |
---|
660 | IF (.NOT.zforce) THEN |
---|
661 | ret = INT(rmdir_c(cpath)) == 0 |
---|
662 | ELSE |
---|
663 | ret = INT(rmdirf_c(cpath)) == 0 |
---|
664 | ENDIF |
---|
665 | ENDIF |
---|
666 | RETURN |
---|
667 | END FUNCTION fs_rmdir |
---|
668 | |
---|
669 | FUNCTION fs_stat(path,type,perm,nlnks,uid,gid,fsize,atime,mtime,ctime) RESULT(ret) |
---|
670 | !! Get some informations about a path |
---|
671 | !! |
---|
672 | !! The method retrieves various informations about the input path using fstat C function. |
---|
673 | !! The type of path as returned in __type__ argument is can take the following values: |
---|
674 | !! |
---|
675 | !! - 0, a file |
---|
676 | !! - 1, a link to a file |
---|
677 | !! - 2, a directory |
---|
678 | !! - 3, a link to a directory |
---|
679 | !! - 4, other (fifo, socket, block special, char special...) |
---|
680 | CHARACTER(len=*), INTENT(in) :: path !! Input path |
---|
681 | INTEGER, INTENT(out), OPTIONAL :: type, & !! Optional type of path (see function documentation). |
---|
682 | perm, & !! Optional permission of the path |
---|
683 | nlnks, & !! Optional number of links to the path |
---|
684 | uid, & !! Optional user id |
---|
685 | gid !! Optional group id |
---|
686 | INTEGER(kind=8), INTENT(out), OPTIONAL :: fsize !! Optional file size |
---|
687 | CHARACTER(len=19), INTENT(out), OPTIONAL :: atime, & !! Optional last access time |
---|
688 | mtime, & !! Optional last modification time |
---|
689 | ctime !! Optional creation time |
---|
690 | LOGICAL :: ret !! True on success, false otherwise. |
---|
691 | INTEGER :: ty,pe,ln,ud,gd |
---|
692 | INTEGER(kind=8) :: fs |
---|
693 | CHARACTER(len=:), ALLOCATABLE :: at,mt,ct |
---|
694 | INTEGER(kind=C_INT) :: p,l,t,u,g |
---|
695 | INTEGER(kind=c_long) :: f |
---|
696 | CHARACTER(len=20,kind=C_CHAR) :: ta,tm,tc |
---|
697 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
698 | IF (LEN_TRIM(path) == 0) THEN |
---|
699 | ret = .false.; RETURN |
---|
700 | ELSE IF (.NOT.(PRESENT(type) .OR. PRESENT(perm) .OR. PRESENT(nlnks) .OR. & |
---|
701 | PRESENT(uid) .OR. PRESENT(gid) .OR. PRESENT(fsize) .OR. & |
---|
702 | PRESENT(atime) .OR. PRESENT(mtime) .OR. PRESENT(ctime))) THEN |
---|
703 | ret = .true. |
---|
704 | ELSE |
---|
705 | ! set default values |
---|
706 | pe=-1 ; ty=-1 ; ud=-1 ; gd=-1 ; fs=-1 ; at="" ; mt="" ; ct="" |
---|
707 | cpath = cstring(ADJUSTL(path)) |
---|
708 | ret = INT(fstat_c(cpath,p,l,t,u,g,f,ta,tm,tc)) == 0 |
---|
709 | IF (ret) THEN |
---|
710 | pe=INT(p) ; ln=INT(l) ; ty=INT(t) ; ud=INT(u) ; gd=INT(g) |
---|
711 | fs=INT(f,kind=8) |
---|
712 | at = fstring(ta) |
---|
713 | mt = fstring(tm) |
---|
714 | ct = fstring(tc) |
---|
715 | ENDIF |
---|
716 | IF (PRESENT(type)) type = ty |
---|
717 | IF (PRESENT(perm)) perm = pe |
---|
718 | IF (PRESENT(nlnks)) nlnks = ln |
---|
719 | IF (PRESENT(uid)) uid = ud |
---|
720 | IF (PRESENT(gid)) gid = gd |
---|
721 | IF (PRESENT(fsize)) fsize = fs |
---|
722 | IF (PRESENT(atime)) atime = at |
---|
723 | IF (PRESENT(mtime)) mtime = mt |
---|
724 | IF (PRESENT(ctime)) ctime = ct |
---|
725 | ENDIF |
---|
726 | RETURN |
---|
727 | END FUNCTION fs_stat |
---|
728 | |
---|
729 | FUNCTION fs_isdir(path) RESULT (ret) |
---|
730 | !! Check if a path is a directory |
---|
731 | !! |
---|
732 | !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific |
---|
733 | !! information about __path__ type. |
---|
734 | CHARACTER(len=*), INTENT(in) :: path !! The path to check |
---|
735 | LOGICAL :: ret !! .true. if the path is a directory, .false. otherwise. |
---|
736 | INTEGER :: ty |
---|
737 | ret = fs_stat(path,type=ty) |
---|
738 | ret = ret.AND.(ty==2.or.ty==3) |
---|
739 | RETURN |
---|
740 | END FUNCTION fs_isdir |
---|
741 | |
---|
742 | FUNCTION fs_isfile(path) RESULT (ret) |
---|
743 | !! Check if a path is a file |
---|
744 | !! |
---|
745 | !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific |
---|
746 | !! information about __path__ type. |
---|
747 | CHARACTER(len=*), INTENT(in) :: path !! The path to check |
---|
748 | LOGICAL :: ret !! .true. if the path is a file, .false. otherwise. |
---|
749 | INTEGER :: ty |
---|
750 | ret=fs_stat(path,type=ty) |
---|
751 | ret = ret.and.(ty==0.or.ty==1) |
---|
752 | RETURN |
---|
753 | END FUNCTION fs_isfile |
---|
754 | |
---|
755 | FUNCTION fs_islink(path) RESULT (ret) |
---|
756 | !! Check if a path is a link |
---|
757 | !! |
---|
758 | !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific |
---|
759 | !! information about __path__ type. |
---|
760 | CHARACTER(len=*), INTENT(in) :: path !! The path to check |
---|
761 | LOGICAL :: ret !! .true. if the path is a link, .false. otherwise. |
---|
762 | INTEGER :: ty |
---|
763 | ret=fs_stat(path,type=ty) |
---|
764 | ret = ret.and.(ty==1.or.ty==3) |
---|
765 | RETURN |
---|
766 | END FUNCTION fs_islink |
---|
767 | |
---|
768 | FUNCTION fs_access(path,permission) RESULT(ret) |
---|
769 | !! Check if a path is accessible for current user |
---|
770 | !! |
---|
771 | !! The method checks if the given path is accessible for the current user. By default, |
---|
772 | !! it does not check for specific permissions. If __permission__ is given it should be |
---|
773 | !! an integer between 0 and 7 resulting from the possible combinations: |
---|
774 | !! |
---|
775 | !! - 0 : Checks for path existence (default) |
---|
776 | !! - 1 : Checks for EXECUTE permission |
---|
777 | !! - 2 : Checks for WRITE permission |
---|
778 | !! - 4 : Checks for READ permission |
---|
779 | CHARACTER(len=*), INTENT(in) :: path !! Path to check |
---|
780 | INTEGER, INTENT(in), OPTIONAL :: permission !! Optional permission to check |
---|
781 | LOGICAL :: ret !! True on success, false otherwise. |
---|
782 | INTEGER(kind=C_INT) :: zp |
---|
783 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
784 | IF (LEN_TRIM(path) == 0) THEN |
---|
785 | ret = .false. |
---|
786 | ELSE |
---|
787 | zp = 0 ; IF (PRESENT(permission)) zp = INT(permission,kind=C_INT) |
---|
788 | ! Defaults are set in the C function. |
---|
789 | cpath = cstring(ADJUSTL(path)) |
---|
790 | ret = INT(access_c(cpath,zp)) == 0 |
---|
791 | ENDIF |
---|
792 | RETURN |
---|
793 | END FUNCTION fs_access |
---|
794 | |
---|
795 | FUNCTION fs_split_ext(path, base, ext, absolute) RESULT(ret) |
---|
796 | !! Split given path into base,extension |
---|
797 | !! |
---|
798 | !! The __base__ of a path is conventionnally defined as all characters before the last dot of the path. |
---|
799 | !! The extension (__ext__) of the path gathers consequently all characters from the last dot to the end |
---|
800 | !! of the string. |
---|
801 | !! @note |
---|
802 | !! If the basename of the path begins by a dot then the path is assumed to be an hidden file (directory). |
---|
803 | !! __ext__ will then be empty. |
---|
804 | CHARACTER(len=*), INTENT(in) :: path !! Path to split |
---|
805 | CHARACTER(len=:), INTENT(out), ALLOCATABLE :: base, & !! Output base of the path |
---|
806 | ext !! Output extension of the path |
---|
807 | LOGICAL, INTENT(in), OPTIONAL :: absolute !! .true. to return absolute path |
---|
808 | LOGICAL :: ret !! .true. on success, .false. otherwise. |
---|
809 | LOGICAL :: zabs |
---|
810 | INTEGER :: p |
---|
811 | CHARACTER(len=:), ALLOCATABLE :: d,b,apath |
---|
812 | base = "" ; ext = "" |
---|
813 | ret = .false. |
---|
814 | IF (LEN_TRIM(path) == 0) THEN |
---|
815 | RETURN |
---|
816 | ENDIF |
---|
817 | zabs = .false. ; IF (PRESENT(absolute)) zabs = absolute |
---|
818 | apath = TRIM(path) |
---|
819 | IF (zabs) THEN |
---|
820 | apath = fs_realpath(path) ; IF (LEN_TRIM(apath) == 0) RETURN |
---|
821 | ENDIF |
---|
822 | d = fs_dirname(apath) ; IF (LEN_TRIM(d) == 0) RETURN |
---|
823 | b = fs_basename(apath) ; IF (LEN_TRIM(b) == 0) RETURN |
---|
824 | p = INDEX(b,".",.true.) |
---|
825 | ! If dot is set as first char of basename : it's an hidden file |
---|
826 | IF (p > 1) THEN |
---|
827 | ext = b(p:) ; base = TRIM(d)//"/"//b(:p-1) |
---|
828 | ELSE |
---|
829 | base = TRIM(apath) |
---|
830 | ENDIF |
---|
831 | ret = .true. |
---|
832 | RETURN |
---|
833 | END FUNCTION fs_split_ext |
---|
834 | |
---|
835 | FUNCTION fs_create(path, mode, type, permissive) RESULT(ret) |
---|
836 | !! Create a directory/file |
---|
837 | !! |
---|
838 | !! The method creates the file/directory pointed by given __path__. |
---|
839 | !! If __type__ is not given, the method builds the path as : |
---|
840 | !! |
---|
841 | !! -# A file if the basename of the path contains an extension |
---|
842 | !! -# A directory in any other cases. |
---|
843 | !! |
---|
844 | !! Otherwise __type__ should be set to "f" for file or "d" for directory. |
---|
845 | !! |
---|
846 | !! Unless __permissive__ is set to .true., the method will fails if intermediate |
---|
847 | !! directories in the path do not exist. |
---|
848 | CHARACTER(len=*), INTENT(in) :: path !! Path to create |
---|
849 | INTEGER, INTENT(in), OPTIONAL :: mode !! Optional octal permisions to set |
---|
850 | CHARACTER(len=1), INTENT(in), OPTIONAL :: type !! Optional type of path to create |
---|
851 | LOGICAL, INTENT(in), OPTIONAL :: permissive !! .true. to create intermediate directories if not existing |
---|
852 | LOGICAL :: ret !! True on success, false otherwise. |
---|
853 | INTEGER :: zmd,zt,zp |
---|
854 | CHARACTER(len=:), ALLOCATABLE :: b,e |
---|
855 | CHARACTER(len=:), ALLOCATABLE :: cpath |
---|
856 | ret = .false. |
---|
857 | ! Checking for existence |
---|
858 | IF (LEN_TRIM(path) == 0) THEN |
---|
859 | RETURN |
---|
860 | ELSE IF (fs_access(path)) THEN |
---|
861 | RETURN |
---|
862 | ENDIF |
---|
863 | ! Set type of path |
---|
864 | IF (PRESENT(type)) THEN |
---|
865 | IF (.NOT.(type(1:1)=="f".OR.type(1:1)=="d")) THEN |
---|
866 | RETURN |
---|
867 | ELSE |
---|
868 | zt=0 ; IF (type(1:1)=="f") zt = 1 |
---|
869 | ENDIF |
---|
870 | ELSE |
---|
871 | IF(.NOT.fs_split_ext(path,b,e)) RETURN |
---|
872 | zt = 0 ; IF (LEN_TRIM(e) /= 0) zt=1 |
---|
873 | ENDIF |
---|
874 | ! set permissions according to type |
---|
875 | IF (zt == 0) THEN |
---|
876 | zmd = oct_2_dec(777)-get_umask() |
---|
877 | ELSE |
---|
878 | zmd = oct_2_dec(666) -get_umask() |
---|
879 | ENDIF |
---|
880 | ! Check mode argument if present |
---|
881 | IF (PRESENT(mode)) THEN |
---|
882 | IF(.NOT.chk_pm(mode)) THEN |
---|
883 | ! not a valid permission : We raise an error and abort |
---|
884 | RETURN |
---|
885 | ELSE |
---|
886 | zmd = oct_2_dec(mode) |
---|
887 | ENDIF |
---|
888 | ENDIF |
---|
889 | zp = 0 ; IF(PRESENT(permissive)) THEN ; IF(permissive) zp=1 ; ENDIF |
---|
890 | |
---|
891 | cpath = cstring(ADJUSTL(path)) |
---|
892 | ret = INT(create_c(cpath,INT(zmd,kind=C_INT),INT(zt,kind=C_INT),INT(zp,kind=C_INT))) == 0 |
---|
893 | RETURN |
---|
894 | END FUNCTION fs_create |
---|
895 | |
---|
896 | FUNCTION fs_get_parent(path, n) RESULT(opath) |
---|
897 | !! Get the nth parent of the given path |
---|
898 | !! |
---|
899 | !! The method first resolves the given path using [[fsystem(module):fs_realpath(function)]] |
---|
900 | !! to get an absolute path. |
---|
901 | !! @note |
---|
902 | !! If __n__ is greater than the maximum parent level of the path, "/" is returned. |
---|
903 | CHARACTER(len=*), INTENT(in) :: path |
---|
904 | !! Input path |
---|
905 | INTEGER, INTENT(in), OPTIONAL :: n |
---|
906 | !! The level of the parent to get |
---|
907 | CHARACTER(len=:), ALLOCATABLE :: opath |
---|
908 | !! The nth parent of the given path, or an empty string if the parent can not be computed |
---|
909 | CHARACTER(len=:), ALLOCATABLE :: zp |
---|
910 | INTEGER :: i,mx,zl,mzl |
---|
911 | opath = "" |
---|
912 | zl = 1 ; IF (PRESENT(n)) zl = MAX(n,1) |
---|
913 | IF (LEN_TRIM(path) == 0) THEN |
---|
914 | RETURN |
---|
915 | ENDIF |
---|
916 | ! Gets the absolute path |
---|
917 | zp = fs_realpath(TRIM(ADJUSTL(path))) |
---|
918 | IF (LEN_TRIM(zp) == 0) RETURN |
---|
919 | ! removing trailing / (only if it's not the first ^^) |
---|
920 | mx = LEN_TRIM(zp) ; IF (zp(mx:mx)=="/".AND.mx/=1) zp(mx:mx) = "" |
---|
921 | ! compute maximum level |
---|
922 | mzl = 1 ; DO i=1,mx ; IF(zp(i:i) == '/') mzl=mzl+1 ; ENDDO |
---|
923 | i=0 |
---|
924 | DO |
---|
925 | mx = INDEX(zp(1:mx),'/',.true.) ; i=i+1 |
---|
926 | IF (mx==0.OR.i>=zl.OR.i>=mzl) EXIT |
---|
927 | mx = mx - 1 |
---|
928 | ENDDO |
---|
929 | IF (mx >= 1) THEN |
---|
930 | opath = zp(1:MAX(1,mx-1)) |
---|
931 | ELSE |
---|
932 | opath = "/" |
---|
933 | ENDIF |
---|
934 | RETURN |
---|
935 | END FUNCTION fs_get_parent |
---|
936 | |
---|
937 | SUBROUTINE fs_termsize(row, column) |
---|
938 | !! Get the current terminal window size |
---|
939 | !! @attention |
---|
940 | !! If the program is redirected to a file (and maybe some other device), the C |
---|
941 | !! function can raise an error. In that case, the default values (20,80) are |
---|
942 | !! returned by the C function and thus the subroutine ! |
---|
943 | INTEGER, INTENT(out) :: row, & !! Number of rows of the window |
---|
944 | column !! Number of columns of the window |
---|
945 | INTEGER(kind=C_INT) :: r, c, ret |
---|
946 | ret = termsize_c(r,c) |
---|
947 | row = INT(r) ; column = INT(c) |
---|
948 | RETURN |
---|
949 | END SUBROUTINE fs_termsize |
---|
950 | |
---|
951 | SUBROUTINE fs_usleep(usec) |
---|
952 | !! Sleep for a given number of microseconds |
---|
953 | !! @note |
---|
954 | !! Currently if C usleep function failed, the system... does not sleep ! |
---|
955 | INTEGER, INTENT(in) :: usec !! The number of microseconds to sleep for |
---|
956 | INTEGER(kind=C_INT) :: ret |
---|
957 | ! usleep expects useconds_t (unsigned int) which is given here as a 4-bytes int |
---|
958 | ret = usleep_c(INT(usec,kind=C_INT)) |
---|
959 | END SUBROUTINE fs_usleep |
---|
960 | |
---|
961 | SUBROUTINE fs_msleep(msec) |
---|
962 | !! Sleep for a given number of milliseconds |
---|
963 | INTEGER, INTENT(in) :: msec !! The number of milliseconds to sleep for |
---|
964 | CALL fs_usleep(msec*1000) |
---|
965 | END SUBROUTINE fs_msleep |
---|
966 | |
---|
967 | FUNCTION fs_get_memory(peak,units) RESULT(mem) |
---|
968 | !! Get the memory usage of the current process. |
---|
969 | LOGICAL, INTENT(in), OPTIONAL :: peak !! True to retrieve the peak RSS memory, otherwise retrieve the current RSS memory. Default to False. |
---|
970 | CHARACTER(len=*), INTENT(in), OPTIONAL :: units !! Output units: either 'B' (Bytes),'KB' (Kilo-),'MB' (Mega-),'GB' (Giga-). Default to 'B'. |
---|
971 | REAL(kind=8) :: mem !! Memory usage. |
---|
972 | LOGICAL :: zpeak |
---|
973 | CHARACTER(len=2) :: zunits |
---|
974 | zpeak = .false. ; IF (PRESENT(peak)) zpeak = peak |
---|
975 | zunits = 'B ' ; IF (PRESENT(units)) zunits = units |
---|
976 | IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B ' |
---|
977 | IF (zpeak) THEN |
---|
978 | mem = REAL(getPeakRSS_c(),kind=8) |
---|
979 | ELSE |
---|
980 | mem = REAL(getCurrentRSS_c(),kind=8) |
---|
981 | ENDIF |
---|
982 | IF (zunits == 'KB') THEN |
---|
983 | mem = mem / 1024d0 |
---|
984 | ELSE IF (zunits == 'MB') THEN |
---|
985 | mem = mem / 1048576d0 |
---|
986 | ELSE IF (zunits == 'GB') THEN |
---|
987 | mem = mem / 1073741824d0 |
---|
988 | ENDIF |
---|
989 | RETURN |
---|
990 | END FUNCTION fs_get_memory |
---|
991 | |
---|
992 | FUNCTION fs_get_system_memory(total,available,free,units) RESULT(ret) |
---|
993 | !! Get informations about system memory. |
---|
994 | !! |
---|
995 | !! If no informations is available, output arguments are set to 0 and the method returns false. |
---|
996 | REAL(kind=8), INTENT(out), OPTIONAL :: total !! Total available memory. |
---|
997 | REAL(kind=8), INTENT(out), OPTIONAL :: available !! Current available memory. |
---|
998 | REAL(kind=8), INTENT(out), OPTIONAL :: free !! Current free memory. |
---|
999 | CHARACTER(len=*), INTENT(in), OPTIONAL :: units !! Output units: either 'B' (Bytes),'KB' (Kilo-),'MB' (Mega-),'GB' (Giga-). Default to 'B'. |
---|
1000 | LOGICAL :: ret !! True on success, false otherwise. |
---|
1001 | LOGICAL :: zpeak |
---|
1002 | CHARACTER(len=2) :: zunits |
---|
1003 | INTEGER(kind=8) :: ztot,zava,zfre |
---|
1004 | |
---|
1005 | zunits = 'B ' ; IF (PRESENT(units)) zunits = units |
---|
1006 | IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B ' |
---|
1007 | ret = INT(getSystemMemory_c(ztot,zava,zfre),kind=4) == 0 |
---|
1008 | ztot = ztot * 1024 ; zava = zava * 1024 ; zfre = zfre * 1024 |
---|
1009 | |
---|
1010 | IF (PRESENT(total)) total = ztot |
---|
1011 | IF (PRESENT(available)) available = zava |
---|
1012 | IF (PRESENT(free)) free = zfre |
---|
1013 | IF (.NOT.ret) RETURN |
---|
1014 | |
---|
1015 | IF (zunits == 'KB') THEN |
---|
1016 | IF (PRESENT(total)) total = ztot / 1024d0 |
---|
1017 | IF (PRESENT(available)) available = zava / 1024d0 |
---|
1018 | IF (PRESENT(free)) free = zfre / 1024d0 |
---|
1019 | ELSE IF (zunits == 'MB') THEN |
---|
1020 | IF (PRESENT(total)) total = ztot / 1048576d0 |
---|
1021 | IF (PRESENT(available)) available = zava / 1048576d0 |
---|
1022 | IF (PRESENT(free)) free = zfre / 1048576d0 |
---|
1023 | ELSE IF (zunits == 'GB') THEN |
---|
1024 | IF (PRESENT(total)) total = ztot / 1073741824d0 |
---|
1025 | IF (PRESENT(available)) available = zava / 1073741824d0 |
---|
1026 | IF (PRESENT(free)) free = zfre / 1073741824d0 |
---|
1027 | ENDIF |
---|
1028 | RETURN |
---|
1029 | END FUNCTION fs_get_system_memory |
---|
1030 | |
---|
1031 | |
---|
1032 | !=============================================================================== |
---|
1033 | ! MODULE MISCELLANEOUS METHODS |
---|
1034 | !=============================================================================== |
---|
1035 | |
---|
1036 | FUNCTION oct_2_dec(octal) RESULT(res) |
---|
1037 | !> Octal to decimal conversion |
---|
1038 | !! |
---|
1039 | !! The method converts the octal number ranging from 0 to 777 in the decimal system. |
---|
1040 | !! @attention |
---|
1041 | !! If the __octal__ number is out of range then the method returns 384 (600 in octal). |
---|
1042 | INTEGER, INTENT(in) :: octal !! The octal value to convert |
---|
1043 | INTEGER :: res !! The converted decimal value |
---|
1044 | INTEGER :: o,d,i |
---|
1045 | IF (octal < 0 .OR. octal > 777) THEN |
---|
1046 | res = 384 ; RETURN ! --> 600 in octal : rw------- |
---|
1047 | ENDIF |
---|
1048 | d = 0 ; i = 0 ; o = octal |
---|
1049 | DO WHILE(o/=0) |
---|
1050 | d=d+mod(o,10)*8**i ; i=i+1 ; o=o/10 |
---|
1051 | ENDDO |
---|
1052 | res=d |
---|
1053 | RETURN |
---|
1054 | END FUNCTION oct_2_dec |
---|
1055 | |
---|
1056 | FUNCTION dec_2_oct(decimal) RESULT(res) |
---|
1057 | !! Decimal to octal conversion |
---|
1058 | !! The method converts the decimal number ranging from 0 to 511 in the octal system. |
---|
1059 | !! @attention |
---|
1060 | !! If the __decimal__ number is out of range, then it the method returns 600 (384 in decimal). |
---|
1061 | INTEGER, INTENT(in) :: decimal !! The decimal value to convert |
---|
1062 | INTEGER :: res !! The converted octal value |
---|
1063 | ! - LOCAL |
---|
1064 | INTEGER :: o,d,i,m |
---|
1065 | IF (decimal < 0 .OR. decimal > 511) THEN |
---|
1066 | res = 600 ; RETURN ! --> 384 in decimal : rw------- |
---|
1067 | ENDIF |
---|
1068 | o=0 ; d = decimal ; i=0 ; m=0 |
---|
1069 | DO WHILE(d/=0) |
---|
1070 | d=d/8 ; m=m+1 |
---|
1071 | ENDDO |
---|
1072 | m=m-1 ; d=decimal |
---|
1073 | DO i=0,m |
---|
1074 | o=o+mod(d,8)*10**i ; d=d/8 |
---|
1075 | ENDDO |
---|
1076 | res = o |
---|
1077 | RETURN |
---|
1078 | END FUNCTION dec_2_oct |
---|
1079 | |
---|
1080 | FUNCTION sp_2_op(str) RESULT(oct) |
---|
1081 | !! Get octal number of string representation's permission |
---|
1082 | CHARACTER(len=3),INTENT(in) :: str !! The permission to convert |
---|
1083 | INTEGER :: oct !! Octal value of the string permission on succes, -1 otherwise. |
---|
1084 | oct = -1 |
---|
1085 | IF (LEN_TRIM(str) /= 3) RETURN |
---|
1086 | SELECT CASE(str) |
---|
1087 | CASE("---") ; oct = 0 |
---|
1088 | CASE("--x") ; oct = 1 |
---|
1089 | CASE("-w-") ; oct = 2 |
---|
1090 | CASE("-wx") ; oct = 3 |
---|
1091 | CASE("r--") ; oct = 4 |
---|
1092 | CASE("r-x") ; oct = 5 |
---|
1093 | CASE("rw-") ; oct = 6 |
---|
1094 | CASE("rwx") ; oct = 7 |
---|
1095 | CASE DEFAULT |
---|
1096 | oct = -1 ; RETURN |
---|
1097 | END SELECT |
---|
1098 | RETURN |
---|
1099 | END FUNCTION sp_2_op |
---|
1100 | |
---|
1101 | FUNCTION op_2_sp(oct) RESULT(str) |
---|
1102 | !! Get string representation of the octal number's permission |
---|
1103 | INTEGER, INTENT(in) :: oct !! Octal number to convert |
---|
1104 | CHARACTER(len=3) :: str !! String representation of the octal number on succes, 'ukn' otherwise |
---|
1105 | SELECT CASE(oct) |
---|
1106 | CASE(0) ; str="---" |
---|
1107 | CASE(1) ; str="--x" |
---|
1108 | CASE(2) ; str="-w-" |
---|
1109 | CASE(3) ; str="-wx" |
---|
1110 | CASE(4) ; str="r--" |
---|
1111 | CASE(5) ; str="r-x" |
---|
1112 | CASE(6) ; str="rw-" |
---|
1113 | CASE(7) ; str="rwx" |
---|
1114 | CASE DEFAULT |
---|
1115 | str='ukn' ; RETURN |
---|
1116 | END SELECT |
---|
1117 | RETURN |
---|
1118 | END FUNCTION op_2_sp |
---|
1119 | |
---|
1120 | FUNCTION str_perm(oct_perm) RESULT(ret) |
---|
1121 | !! Get the string representation of the given permission mask |
---|
1122 | INTEGER, INTENT(in) :: oct_perm !! The octal representation of the permission |
---|
1123 | CHARACTER(len=9) :: ret !! String representation of the octal number on succes, 'ukn' otherwise |
---|
1124 | INTEGER :: u,g,o |
---|
1125 | IF (.NOT.chk_pm(oct_perm)) THEN |
---|
1126 | ret = "ukn" ; RETURN |
---|
1127 | ENDIF |
---|
1128 | u=int(oct_perm/100) ; g=int((oct_perm-u*100)/10) ; o=int(oct_perm-u*100-g*10) |
---|
1129 | ret(1:3) = op_2_sp(u) ; ret(4:6) = op_2_sp(g) ; ret(7:9) = op_2_sp(o) |
---|
1130 | RETURN |
---|
1131 | END FUNCTION str_perm |
---|
1132 | |
---|
1133 | FUNCTION oct_perm(str) RESULT(ret) |
---|
1134 | !! Get the string representation of the given permission mask |
---|
1135 | CHARACTER(len=9), INTENT(in) :: str !! The string representation of the permission |
---|
1136 | INTEGER :: ret !! Octal permission on success, -1 otherwise |
---|
1137 | ! - LOCAL |
---|
1138 | INTEGER :: u,g,o |
---|
1139 | u = sp_2_op(str(1:3)) ; g = sp_2_op(str(4:6)) ; o = sp_2_op(str(7:9)) |
---|
1140 | IF (u==-1.OR.g==-1.OR.o==-1) THEN |
---|
1141 | ret = -1 ; RETURN |
---|
1142 | ELSE |
---|
1143 | ret = u*100 + g*10 + o |
---|
1144 | ENDIF |
---|
1145 | RETURN |
---|
1146 | END FUNCTION oct_perm |
---|
1147 | |
---|
1148 | FUNCTION chk_pm(perm) RESULT(valid) |
---|
1149 | !! Check if the given permission is valid |
---|
1150 | INTEGER, INTENT(in) :: perm !! Octal permission mask |
---|
1151 | LOGICAL :: valid !! .true. if the permission mask is valid, .false. otherwise |
---|
1152 | INTEGER :: u,g,o |
---|
1153 | u=int(perm/100) ; g=int((perm-u*100)/10) ; o=int(perm-u*100-g*10) |
---|
1154 | valid = (u>=0.AND.u<=7).AND.(g>=0.AND.g<=7).AND.(o>=0.AND.o<=7) |
---|
1155 | RETURN |
---|
1156 | END FUNCTION chk_pm |
---|
1157 | |
---|
1158 | FUNCTION get_umask() RESULT(mask) |
---|
1159 | !! Get the umask value of the current session |
---|
1160 | INTEGER :: mask !! Current umask value in decimal system |
---|
1161 | mask = INT(umask_c()) |
---|
1162 | RETURN |
---|
1163 | END FUNCTION get_umask |
---|
1164 | |
---|
1165 | FUNCTION sz2str(file_size) RESULT(fstr) |
---|
1166 | !! Get a human readable file size |
---|
1167 | INTEGER(kind=8), INTENT(in) :: file_size !! File size (assumed to be bytes) |
---|
1168 | CHARACTER(len=50) :: fstr !! Size in a human readable format |
---|
1169 | ! - LOCAL |
---|
1170 | INTEGER :: cc |
---|
1171 | REAL(kind=8) :: zfs |
---|
1172 | CHARACTER(len=2), DIMENSION(6), PARAMETER :: sn = & |
---|
1173 | (/'B ','KB','MB','GB','TB','PB'/) |
---|
1174 | zfs=DBLE(file_size) |
---|
1175 | DO cc=1,size(sn)-1 ; IF (zfs<1024.) EXIT ; zfs=zfs/1024. ; ENDDO |
---|
1176 | IF (MOD(zfs,1.0) == 0) THEN |
---|
1177 | WRITE(fstr,'(I50)') INT(zfs) ; fstr = TRIM(ADJUSTL(fstr))//sn(cc) |
---|
1178 | ELSE |
---|
1179 | WRITE(fstr,'(F50.2)') zfs ; fstr = TRIM(ADJUSTL(fstr))//sn(cc) |
---|
1180 | ENDIF |
---|
1181 | RETURN |
---|
1182 | END FUNCTION sz2str |
---|
1183 | |
---|
1184 | FUNCTION chrono_is_running(this) RESULT (ret) |
---|
1185 | !! Get chrono's state. |
---|
1186 | OBJECT(chrono), INTENT(in) :: this !! Chrono object reference. |
---|
1187 | LOGICAL :: ret !! Running state. |
---|
1188 | ret = this%on_run |
---|
1189 | RETURN |
---|
1190 | END FUNCTION chrono_is_running |
---|
1191 | |
---|
1192 | SUBROUTINE chrono_start(this) |
---|
1193 | !! Start the chrono. |
---|
1194 | !! |
---|
1195 | !! @note |
---|
1196 | !! Calling the method multiple times without explicitly stopping the chrono |
---|
1197 | !! [[chrono(type):stop(bound)]] does nothing (except for the first called). |
---|
1198 | OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference. |
---|
1199 | IF (.NOT.this%on_run) THEN |
---|
1200 | CALL CPU_TIME(this%cpu_start) |
---|
1201 | CALL SYSTEM_CLOCK(this%clock_start) |
---|
1202 | ENDIF |
---|
1203 | this%on_run = .true. |
---|
1204 | END SUBROUTINE chrono_start |
---|
1205 | |
---|
1206 | SUBROUTINE chrono_stop(this) |
---|
1207 | !! Stop the chrono. |
---|
1208 | OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference. |
---|
1209 | REAL(kind=8) :: ecpu |
---|
1210 | INTEGER(kind=8) :: eclk,nbm,nbr |
---|
1211 | this%on_run = .false. |
---|
1212 | END SUBROUTINE chrono_stop |
---|
1213 | |
---|
1214 | SUBROUTINE chrono_reset(this) |
---|
1215 | !! Reset the chrono's internal elapsed times. |
---|
1216 | OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference. |
---|
1217 | CALL CPU_TIME(this%cpu_start) |
---|
1218 | CALL SYSTEM_CLOCK(this%clock_start) |
---|
1219 | END SUBROUTINE chrono_reset |
---|
1220 | |
---|
1221 | SUBROUTINE chrono_get(this,cpu,clock,units) |
---|
1222 | !! Get elapsed time since last call of start or reset methods. |
---|
1223 | !! |
---|
1224 | !! The method computes the time elapsed in two ways : |
---|
1225 | !! |
---|
1226 | !! - If the [[fsystem(module):chrono(type)]] is not running, the method retruns 0. |
---|
1227 | !! - Otherwise, elapsed time since the last call of |
---|
1228 | !! [[chrono(type):start(bound)]] (or [[chrono(type):reset(bound)]]). |
---|
1229 | OBJECT(chrono), INTENT(in) :: this |
---|
1230 | !! Chrono object reference. |
---|
1231 | REAL(kind=8), INTENT(out), OPTIONAL :: cpu |
---|
1232 | !! Elapsed cpu time in seconds by default (see units argument). |
---|
1233 | REAL(kind=8), INTENT(out), OPTIONAL :: clock |
---|
1234 | !! Elapsed system clock time in seconds by default (see units argument). |
---|
1235 | CHARACTER(len=2), INTENT(in), OPTIONAL :: units |
---|
1236 | !! A two characters wide string with the units to convert in. Units should |
---|
1237 | !! be one of the following : 'ms', 's' (default), 'm', 'h' or 'd'. |
---|
1238 | CHARACTER(len=2) :: zu |
---|
1239 | REAL(kind=8) :: cu, fact |
---|
1240 | INTEGER(kind=8) :: ck, r, m |
---|
1241 | IF (this%on_run) THEN |
---|
1242 | IF (PRESENT(cpu)) THEN |
---|
1243 | CALL CPU_TIME(cu) |
---|
1244 | cpu = (cu - this%cpu_start) |
---|
1245 | ENDIF |
---|
1246 | IF (PRESENT(clock)) THEN |
---|
1247 | CALL SYSTEM_CLOCK(ck,r,m) |
---|
1248 | clock = c2t(ck,this%clock_start,r,m) |
---|
1249 | ENDIF |
---|
1250 | ELSE |
---|
1251 | IF (PRESENT(cpu)) cpu = 0d0 |
---|
1252 | IF (PRESENT(clock)) clock = 0d0 |
---|
1253 | ENDIF |
---|
1254 | fact = 1d0 |
---|
1255 | zu = 's' |
---|
1256 | IF (PRESENT(units)) THEN |
---|
1257 | zu = units |
---|
1258 | SELECT CASE(zu) |
---|
1259 | CASE ('d') ; fact = 3600d0*24. |
---|
1260 | CASE ('h') ; fact = 3600d0 |
---|
1261 | CASE ('m') ; fact = 60d0 |
---|
1262 | CASE ('ms') ; fact = 1d-3 |
---|
1263 | CASE DEFAULT ; fact = 1d0 |
---|
1264 | END SELECT |
---|
1265 | ENDIF |
---|
1266 | IF (PRESENT(cpu)) cpu = cpu / fact |
---|
1267 | IF (PRESENT(clock)) clock = clock / fact |
---|
1268 | END SUBROUTINE chrono_get |
---|
1269 | |
---|
1270 | FUNCTION c2t(e,i,r,m) RESULT(time) |
---|
1271 | !! Get the real-time between two clock counts from system_clock. |
---|
1272 | INTEGER(kind=8), INTENT(in) :: e !! Final clock count |
---|
1273 | INTEGER(kind=8), INTENT(in) :: i !! Initial clock count |
---|
1274 | INTEGER(kind=8), INTENT(in) :: r !! Clock count rate |
---|
1275 | INTEGER(kind=8), INTENT(in) :: m !! Maximum Clock count value |
---|
1276 | REAL(kind=8) :: time !! Time in seconds |
---|
1277 | INTEGER(kind=8) :: nc |
---|
1278 | nc = e-i ; IF (e < i) nc = nc+m |
---|
1279 | time = REAL(nc,kind=8)/r |
---|
1280 | RETURN |
---|
1281 | END FUNCTION c2t |
---|
1282 | END MODULE FSYSTEM |
---|
1283 | |
---|