61 use iso_fortran_env,
only : iostat_end
70 implicit none;
private
75 integer,
parameter,
private :: INCLUDE_TYPE_SYSTEM = 1
76 integer,
parameter,
private :: INCLUDE_TYPE_LOCAL = 2
78 integer,
parameter,
private :: MAX_PATH_LEN = 256
80 integer,
parameter,
private :: MAX_PATH_LEN = 4096
101 type(
context),
intent(in) :: ctx
102 integer,
intent(in) :: ounit
104 type(
macro),
allocatable,
intent(inout) :: macros(:)
105 character(*),
intent(in) :: token
107 character(:),
allocatable :: include_file
108 character(:),
allocatable :: dir, ifile
109 character(:),
allocatable :: sys_paths(:)
110 integer :: i, iunit, ierr, pos
111 integer :: include_type
118 include_file =
trim(adjustl(ctx%content(pos:)))
121 if (include_file(1:1) ==
'"')
then
122 include_type = include_type_local
123 include_file = include_file(2:
index(include_file(2:),
'"'))
124 else if (include_file(1:1) ==
'<')
then
125 include_type = include_type_system
126 include_file = include_file(2:
index(include_file(2:),
'>'))
130 message=
'Malformed #include directive', &
131 label=
label_type(
'Filepath should either be delimited by "<...>" or "..."',
index(ctx%content, include_file), &
132 len(include_file)), &
133 source=
trim(ctx%path)), &
134 ctx%content, ctx%line))
141 inquire(file=ifile, exist=exists)
147 message=
'File not found', &
148 label=
label_type(
'Cannot find include file ' //
trim(include_file),
index(ctx%content, include_file), &
149 len(include_file)), &
150 source=
trim(ctx%path)), &
151 ctx%content, ctx%line))
159 ifile =
join(dir, include_file)
160 if (include_type == include_type_local)
then
161 ifile =
join(dir, include_file)
162 inquire(file=ifile, exist=exists)
169 if (.not. exists .and.
allocated(
global%includedir))
then
170 do i = 1,
size(
global%includedir)
171 ifile =
join(
global%includedir(i), include_file)
172 inquire(file=ifile, exist=exists)
181 if (.not. exists)
then
183 character(:),
allocatable :: ipaths(:)
185 ipaths = get_system_paths()
186 do i = 1,
size(ipaths)
187 ifile =
join(ipaths(i), include_file)
188 inquire(file=ifile, exist=exists)
197 if (.not. exists)
then
198 ifile =
join(
cwd(), include_file)
199 inquire(file=ifile, exist=exists)
206 if (.not. exists)
then
208 message=
'File not found', &
209 label=
label_type(
'Cannot find include file ' //
trim(include_file),
index(ctx%content, include_file),
len(&
211 source=
trim(ctx%path)), &
212 ctx%content, ctx%line))
218 open(newunit=iunit, file=include_file, status=
'old', action=
'read', iostat=ierr)
221 message=
'File not found', &
222 label=
label_type(
'Cannot open include file ' //
trim(include_file),
index(ctx%content, include_file),
len(&
224 source=
trim(ctx%path)), &
225 ctx%content, ctx%line))
229 call preprocess(iunit, ounit, macros, .true.)
239 function get_system_paths()
result(paths)
240 character(:),
allocatable :: paths(:)
242 character(:),
allocatable :: path_env, tmp(:)
243 integer :: lpath, i, n_paths, start_pos, end_pos, count
244 character(len=1) :: path_sep
253 call get_environment_variable(
'INCLUDE', length=lpath)
255 allocate(
character(len=0) :: paths(0)); return
259 allocate(
character(len=lpath) :: path_env)
260 call get_environment_variable(
'INCLUDE',
value=path_env)
264 do i = 1, len(path_env)
265 if (path_env(i:i) == path_sep) n_paths = n_paths + 1
269 allocate(
character(len=MAX_PATH_LEN) :: tmp(n_paths))
274 do i = 1, len(path_env) + 1
275 if (i > len(path_env) .or. path_env(i:i) == path_sep)
then
276 if (i > len(path_env))
then
282 if (end_pos >= start_pos)
then
284 tmp(count) = trim(adjustl(path_env(start_pos:end_pos)))
292 allocate(
character(len=MAX_PATH_LEN) :: paths(count))
293 paths(:) = tmp(1:count)
295 allocate(
character(len=0) :: paths(0))
type(global_settings), public global
The single global instance used throughout fpx Initialized automatically with sensible defaults value...
recursive subroutine, public handle_include(ctx, ounit, preprocess, macros, token)
Process a include directive encountered during preprocessing Resolves the include file name (quoted o...
logical, public verbose
Master switch for verbose diagnostic output Default value is .false. (quiet mode)....
pure logical function is_rooted(filepath)
Returns .true. if the path is rooted (starts with a separator) or is absolute. A rooted path begins w...
pure character(:) function, allocatable dirpath(filepath)
Returns the directory part of a path (everything before the last separator).
character(:) function, allocatable cwd()
Returns the current working directory as a deferred-length character string. Returns empty string on ...
pure character(len_trim(str)) function, public lowercase(str)
Convert string to lower case (respects contents of quotes).
Interface to render diagnostic messages and labels.
Abstract interface for the main preprocessing routine (used for recursion) Allows handle_include to r...
Generic interface for joining two path components Supports all combinations of character and string a...
Return the length of a string.
Return the trimmed string.
Source location and content snapshot for precise diagnostics Instances of this type are created for e...
Definition of diagnostic message.
Represents text as a sequence of ASCII code units. The derived type wraps an allocatable character ar...
Derived type representing a single preprocessor macro Extends string with macro-specific fields: rep...