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