1 //===-- runtime/extensions.cpp --------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // These C-coded entry points with Fortran-mangled names implement legacy
10 // extensions that will eventually be implemented in Fortran.
12 #include "flang/Runtime/extensions.h"
13 #include "terminator.h"
15 #include "flang/Runtime/command.h"
16 #include "flang/Runtime/descriptor.h"
17 #include "flang/Runtime/entry-names.h"
18 #include "flang/Runtime/io-api.h"
26 #define WIN32_LEAN_AND_MEAN
32 inline void CtimeBuffer(char *buffer
, size_t bufsize
, const time_t cur_time
,
33 Fortran::runtime::Terminator terminator
) {
34 int error
{ctime_s(buffer
, bufsize
, &cur_time
)};
35 RUNTIME_CHECK(terminator
, error
== 0);
37 #elif _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || \
38 defined(_POSIX_SOURCE)
39 inline void CtimeBuffer(char *buffer
, size_t bufsize
, const time_t cur_time
,
40 Fortran::runtime::Terminator terminator
) {
41 const char *res
{ctime_r(&cur_time
, buffer
)};
42 RUNTIME_CHECK(terminator
, res
!= nullptr);
45 inline void CtimeBuffer(char *buffer
, size_t bufsize
, const time_t cur_time
,
46 Fortran::runtime::Terminator terminator
) {
48 terminator
.Crash("fdate is not supported.");
53 // posix-compliant and has getlogin_r and F_OK
59 namespace Fortran::runtime
{
61 gid_t
RTNAME(GetGID
)() {
63 // Group IDs don't exist on Windows, return 1 to avoid errors
70 uid_t
RTNAME(GetUID
)() {
72 // User IDs don't exist on Windows, return 1 to avoid errors
79 void GetUsernameEnvVar(const char *envName
, char *arg
, std::int64_t length
) {
80 Descriptor name
{*Descriptor::Create(
81 1, std::strlen(envName
) + 1, const_cast<char *>(envName
), 0)};
82 Descriptor value
{*Descriptor::Create(1, length
, arg
, 0)};
84 RTNAME(GetEnvVariable
)
85 (name
, &value
, nullptr, false, nullptr, __FILE__
, __LINE__
);
89 // SUBROUTINE FLUSH(N)
92 void FORTRAN_PROCEDURE_NAME(flush
)(const int &unit
) {
93 Cookie cookie
{IONAME(BeginFlush
)(unit
, __FILE__
, __LINE__
)};
94 IONAME(EndIoStatement
)(cookie
);
99 void FORTRAN_PROCEDURE_NAME(fdate
)(char *arg
, std::int64_t length
) {
100 // Day Mon dd hh:mm:ss yyyy\n\0 is 26 characters, e.g.
101 // Tue May 26 21:51:03 2015\n\0
103 // Insufficient space, fill with spaces and return.
105 std::memset(arg
, ' ', length
);
109 Terminator terminator
{__FILE__
, __LINE__
};
110 std::time_t current_time
;
111 std::time(¤t_time
);
112 CtimeBuffer(str
, sizeof(str
), current_time
, terminator
);
114 // Pad space on the last two byte `\n\0`, start at index 24 included.
115 CopyAndPad(arg
, str
, length
, 24);
118 std::intptr_t RTNAME(Malloc
)(std::size_t size
) {
119 return reinterpret_cast<std::intptr_t>(std::malloc(size
));
123 std::int32_t FORTRAN_PROCEDURE_NAME(iargc
)() { return RTNAME(ArgumentCount
)(); }
125 // CALL GETARG(N, ARG)
126 void FORTRAN_PROCEDURE_NAME(getarg
)(
127 std::int32_t &n
, char *arg
, std::int64_t length
) {
128 Descriptor value
{*Descriptor::Create(1, length
, arg
, 0)};
129 (void)RTNAME(GetCommandArgument
)(
130 n
, &value
, nullptr, nullptr, __FILE__
, __LINE__
);
133 // CALL GETLOG(USRNAME)
134 void FORTRAN_PROCEDURE_NAME(getlog
)(char *arg
, std::int64_t length
) {
135 #if _REENTRANT || _POSIX_C_SOURCE >= 199506L
136 if (length
>= 1 && getlogin_r(arg
, length
) == 0) {
137 auto loginLen
{std::strlen(arg
)};
139 arg
+ loginLen
, ' ', static_cast<std::size_t>(length
) - loginLen
);
144 GetUsernameEnvVar("USERNAME", arg
, length
);
146 GetUsernameEnvVar("LOGNAME", arg
, length
);
150 void RTNAME(Free
)(std::intptr_t ptr
) {
151 std::free(reinterpret_cast<void *>(ptr
));
154 std::int64_t RTNAME(Signal
)(std::int64_t number
, void (*handler
)(int)) {
155 // using auto for portability:
156 // on Windows, this is a void *
157 // on POSIX, this has the same type as handler
158 auto result
= signal(number
, handler
);
160 // GNU defines the intrinsic as returning an integer, not a pointer. So we
161 // have to reinterpret_cast
162 return static_cast<int64_t>(reinterpret_cast<std::uintptr_t>(result
));
165 // CALL SLEEP(SECONDS)
166 void RTNAME(Sleep
)(std::int64_t seconds
) {
167 // ensure that conversion to unsigned makes sense,
168 // sleep(0) is an immidiate return anyway
173 Sleep(seconds
* 1000);
179 // TODO: not supported on Windows
181 std::int64_t FORTRAN_PROCEDURE_NAME(access
)(const char *name
,
182 std::int64_t nameLength
, const char *mode
, std::int64_t modeLength
) {
183 std::int64_t ret
{-1};
184 if (nameLength
<= 0 || modeLength
<= 0 || !name
|| !mode
) {
188 // ensure name is null terminated
189 char *newName
{nullptr};
190 if (name
[nameLength
- 1] != '\0') {
191 newName
= static_cast<char *>(std::malloc(nameLength
+ 1));
192 std::memcpy(newName
, name
, nameLength
);
193 newName
[nameLength
] = '\0';
204 for (std::int64_t i
= 0; i
< modeLength
; ++i
) {
223 if (!read
&& !write
&& !execute
&& !exists
) {
228 if (!read
&& !write
&& !execute
) {
241 ret
= access(name
, imode
);
251 } // namespace Fortran::runtime