Skip to content

stdlib_system: essential path functionality #999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU AND CMAKE_Fortran_COMPILER_VERSION VER
message(FATAL_ERROR "GCC Version 9 or newer required")
endif()

# Convert CMAKE_SYSTEM_NAME to uppercase
string(TOUPPER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME_UPPER)

# Pass the uppercase system name as a macro
add_compile_options(-D${SYSTEM_NAME_UPPER})

# --- compiler feature checks
include(CheckFortranSourceCompiles)
include(CheckFortranSourceRuns)
Expand Down
2 changes: 2 additions & 0 deletions config/fypp_deployment.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import platform
import fypp
import argparse
from joblib import Parallel, delayed
Expand Down Expand Up @@ -115,6 +116,7 @@ def fpm_build(args,unknown):
for idx, arg in enumerate(unknown):
if arg.startswith("--flag"):
flags= flags + unknown[idx+1]
flags = flags + "-D{}".format(platform.system().upper())
#==========================================
# build with fpm
subprocess.run("fpm build"+
Expand Down
177 changes: 177 additions & 0 deletions doc/specs/stdlib_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,180 @@ The file is removed from the filesystem if the operation is successful. If the o
```fortran
{!example/system/example_delete_file.f90!}
```

## `joinpath` - Joins the provided paths according to the OS

### Status

Experimental

### Description

This interface joins the paths provided to it according to the platform specific path-separator.
i.e `\` for windows and `/` for others

### Syntax

`res = [[stdlib_system(module):joinpath(interface)]] (p1, p2)`
`res = [[stdlib_system(module):joinpath(interface)]] (p)`

### Class
Pure function

### Arguments

`p1, p2`: Shall be a character string. It is an `intent(in)` argument.
or
`p`: Shall be a list of character strings. `intent(in)` argument.

### Return values

The resultant path.

### Example

```fortran
{!example/system/example_path_1.f90!}
```

## `operator(/)`

Join two paths according to the platform specific path-separator,
Behavior exactly similar to `joinpath`

### Status

Experimental

### Syntax

`p = lval + rval`

### Class

Pure function.

### Arguments

`lval`: A character string, `intent(in)`.
`rval`: A character string, `intent(in)`.

### Result value

The result is an `allocatable` character string

#### Example

```fortran
{!example/system/example_path_1.f90!}
```

## `splitpath` - splits a path immediately following the last separator

### Status

Experimental

### Description

This subroutine splits a path immediately following the last separator after removing the trailing separators
splitting it into most of the times a directory and a file name.

### Syntax

`call [[stdlib_system(module):splitpath(interface)]] (p, head, tail)`

### Class
Subroutine

### Arguments

`p`: A character string containing the path to be split. `intent(in)`
`head`: The first part of the path. `allocatable, intent(out)`
`tail`: The rest part of the path. `allocatable, intent(out)`

### Behavior

- If `p` is empty, `head` is set to `.` and `tail` is empty
- If `p` consists entirely of path-separators. `head` is set to the path-separator and `tail` is empty
- `head` ends in a path-separator iff and only if `p` appears to be a root directory or child of one

### Return values

The splitted path. `head` and `tail`.

### Example

```fortran
{!example/system/example_path_1.f90!}
```

## `basename` - The last part of a path

### Status

Experimental

### Description

This function returns the last part of a path after removing trailing path separators.

### Syntax

`res = [[stdlib_system(module):basename(interface)]] (p)`

### Class
Function

### Arguments

`p`: the path, a character string, `intent(in)`

### Behavior

- The `tail` of `stdlib_system(module):splitpath(interface)` is exactly what is returned. Same Behavior.

### Return values

A character string.

### Example

```fortran
{!example/system/example_path_1.f90!}
```

## `dirname` - Everything except the last part of the path

### Status

Experimental

### Description

This function returns everything except the last part of a path.

### Syntax

`res = [[stdlib_system(module):dirname(interface)]] (p)`

### Class
Function

### Arguments

`p`: the path, a character string, `intent(in)`

### Behavior

- The `head` of `stdlib_system(module):splitpath(interface)` is exactly what is returned. Same Behavior.

### Return values

A character string.

### Example

```fortran
{!example/system/example_path_1.f90!}
```
1 change: 1 addition & 0 deletions example/system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ ADD_EXAMPLE(process_5)
ADD_EXAMPLE(process_6)
ADD_EXAMPLE(process_7)
ADD_EXAMPLE(sleep)
ADD_EXAMPLE(path_1)
41 changes: 41 additions & 0 deletions example/system/example_path_1.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
program example_path
use stdlib_system, only: joinpath, operator(/), splitpath, ISWIN, dirname, basename
character(len=:), allocatable :: p1, p2, head, tail
character(len=20) :: parr(4)

if (ISWIN) then
p1 = 'C:'/'Users'/'User1'/'Desktop'
parr = [character(len=20) :: 'C:', 'Users', 'User1', 'Desktop']
p2 = joinpath(parr)

! p1 == p2 = 'C:\Users\User1\Desktop'
print *, p1
print *, "p1 == p2: ", p1 == p2

call splitpath(p1, head, tail)
print *, p1 // " -> " // head // " + " // tail

call splitpath(head, p1, tail)
print *, head // " -> " // p1 // " + " // tail

print *, 'dirname of '// p1 // ' -> ' // dirname(p1)
print *, 'basename of '// p1 // ' -> ' // basename(p1)
else
p1 = ''/'home'/'User1'/'Desktop'
parr = [character(len=20) :: '', 'home', 'User1', 'Desktop']
p2 = joinpath(parr)

! p1 == p2 = '/home/User1/Desktop'
print *, p1
print *, "p1 == p2: ", p1 == p2

call splitpath(p1, head, tail)
print *, p1 // " -> " // head // " + " // tail

call splitpath(head, p1, tail)
print *, head // " -> " // p1 // " + " // tail

print *, 'dirname of '// p1 // ' -> ' // dirname(p1)
print *, 'basename of '// p1 // ' -> ' // basename(p1)
end if
end program example_path
7 changes: 4 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ set(fppFiles
stdlib_linalg_kronecker.fypp
stdlib_linalg_cross_product.fypp
stdlib_linalg_eigenvalues.fypp
stdlib_linalg_solve.fypp
stdlib_linalg_solve.fypp
stdlib_linalg_determinant.fypp
stdlib_linalg_qr.fypp
stdlib_linalg_inverse.fypp
stdlib_linalg_pinv.fypp
stdlib_linalg_norms.fypp
stdlib_linalg_state.fypp
stdlib_linalg_svd.fypp
stdlib_linalg_svd.fypp
stdlib_linalg_cholesky.fypp
stdlib_linalg_schur.fypp
stdlib_optval.fypp
Expand Down Expand Up @@ -94,6 +94,7 @@ set(cppFiles

stdlib_linalg_blas.fypp
stdlib_linalg_lapack.fypp
stdlib_system.F90
)

add_subdirectory(blas)
Expand All @@ -116,7 +117,7 @@ set(SRC
stdlib_sorting_radix_sort.f90
stdlib_system_subprocess.c
stdlib_system_subprocess.F90
stdlib_system.F90
stdlib_system_path.f90
stdlib_sparse.f90
stdlib_specialfunctions_legendre.f90
stdlib_quadrature_gauss.f90
Expand Down
Loading
Loading