1627a8ac7SPeter Klausler //===-- runtime/extensions.cpp --------------------------------------------===// 2627a8ac7SPeter Klausler // 3627a8ac7SPeter Klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4627a8ac7SPeter Klausler // See https://llvm.org/LICENSE.txt for license information. 5627a8ac7SPeter Klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6627a8ac7SPeter Klausler // 7627a8ac7SPeter Klausler //===----------------------------------------------------------------------===// 8627a8ac7SPeter Klausler 9627a8ac7SPeter Klausler // These C-coded entry points with Fortran-mangled names implement legacy 10627a8ac7SPeter Klausler // extensions that will eventually be implemented in Fortran. 11627a8ac7SPeter Klausler 12627a8ac7SPeter Klausler #include "flang/Runtime/extensions.h" 13959a430aSYi Wu #include "terminator.h" 1418af032cSYi Wu #include "tools.h" 151d4238beSPeixin-Qiao #include "flang/Runtime/command.h" 161d4238beSPeixin-Qiao #include "flang/Runtime/descriptor.h" 17b64c26f3STom Eccles #include "flang/Runtime/entry-names.h" 18627a8ac7SPeter Klausler #include "flang/Runtime/io-api.h" 19b64c26f3STom Eccles #include <chrono> 20668a58b8STom Eccles #include <cstring> 21959a430aSYi Wu #include <ctime> 22afa52de9STom Eccles #include <signal.h> 23b64c26f3STom Eccles #include <thread> 24959a430aSYi Wu 25959a430aSYi Wu #ifdef _WIN32 26227fe1c1SDavid Truby #define WIN32_LEAN_AND_MEAN 27227fe1c1SDavid Truby #define NOMINMAX 28227fe1c1SDavid Truby #include <windows.h> 29227fe1c1SDavid Truby 30227fe1c1SDavid Truby #include <synchapi.h> 31227fe1c1SDavid Truby 32959a430aSYi Wu inline void CtimeBuffer(char *buffer, size_t bufsize, const time_t cur_time, 33959a430aSYi Wu Fortran::runtime::Terminator terminator) { 34959a430aSYi Wu int error{ctime_s(buffer, bufsize, &cur_time)}; 35959a430aSYi Wu RUNTIME_CHECK(terminator, error == 0); 36959a430aSYi Wu } 37959a430aSYi Wu #elif _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || \ 388b6b882fSKelvin Li defined(_POSIX_SOURCE) 39959a430aSYi Wu inline void CtimeBuffer(char *buffer, size_t bufsize, const time_t cur_time, 40959a430aSYi Wu Fortran::runtime::Terminator terminator) { 41959a430aSYi Wu const char *res{ctime_r(&cur_time, buffer)}; 42959a430aSYi Wu RUNTIME_CHECK(terminator, res != nullptr); 43959a430aSYi Wu } 44959a430aSYi Wu #else 45959a430aSYi Wu inline void CtimeBuffer(char *buffer, size_t bufsize, const time_t cur_time, 46959a430aSYi Wu Fortran::runtime::Terminator terminator) { 47959a430aSYi Wu buffer[0] = '\0'; 48959a430aSYi Wu terminator.Crash("fdate is not supported."); 49959a430aSYi Wu } 50959a430aSYi Wu #endif 51627a8ac7SPeter Klausler 520cee8943STom Eccles #ifndef _WIN32 530cee8943STom Eccles // posix-compliant and has getlogin_r and F_OK 5418af032cSYi Wu #include <unistd.h> 555a34e6fdSJean-Didier PAILLEUX #else 565a34e6fdSJean-Didier PAILLEUX #include <direct.h> 5718af032cSYi Wu #endif 5818af032cSYi Wu 59627a8ac7SPeter Klausler extern "C" { 60627a8ac7SPeter Klausler 611d4238beSPeixin-Qiao namespace Fortran::runtime { 6218af032cSYi Wu 63856c38d5SDavid Truby gid_t RTNAME(GetGID)() { 64856c38d5SDavid Truby #ifdef _WIN32 65856c38d5SDavid Truby // Group IDs don't exist on Windows, return 1 to avoid errors 66856c38d5SDavid Truby return 1; 67856c38d5SDavid Truby #else 68856c38d5SDavid Truby return getgid(); 69856c38d5SDavid Truby #endif 70856c38d5SDavid Truby } 71856c38d5SDavid Truby 72856c38d5SDavid Truby uid_t RTNAME(GetUID)() { 73856c38d5SDavid Truby #ifdef _WIN32 74856c38d5SDavid Truby // User IDs don't exist on Windows, return 1 to avoid errors 75856c38d5SDavid Truby return 1; 76856c38d5SDavid Truby #else 77856c38d5SDavid Truby return getuid(); 78856c38d5SDavid Truby #endif 79856c38d5SDavid Truby } 80856c38d5SDavid Truby 814aa04245SPeter Klausler void GetUsernameEnvVar(const char *envName, char *arg, std::int64_t length) { 8218af032cSYi Wu Descriptor name{*Descriptor::Create( 8318af032cSYi Wu 1, std::strlen(envName) + 1, const_cast<char *>(envName), 0)}; 8418af032cSYi Wu Descriptor value{*Descriptor::Create(1, length, arg, 0)}; 8518af032cSYi Wu 8618af032cSYi Wu RTNAME(GetEnvVariable) 8718af032cSYi Wu (name, &value, nullptr, false, nullptr, __FILE__, __LINE__); 8818af032cSYi Wu } 89856c38d5SDavid Truby 901d4238beSPeixin-Qiao namespace io { 91627a8ac7SPeter Klausler // SUBROUTINE FLUSH(N) 92627a8ac7SPeter Klausler // FLUSH N 93627a8ac7SPeter Klausler // END 941d4238beSPeixin-Qiao void FORTRAN_PROCEDURE_NAME(flush)(const int &unit) { 95627a8ac7SPeter Klausler Cookie cookie{IONAME(BeginFlush)(unit, __FILE__, __LINE__)}; 96627a8ac7SPeter Klausler IONAME(EndIoStatement)(cookie); 97627a8ac7SPeter Klausler } 981d4238beSPeixin-Qiao } // namespace io 991d4238beSPeixin-Qiao 100959a430aSYi Wu // CALL FDATE(DATE) 101959a430aSYi Wu void FORTRAN_PROCEDURE_NAME(fdate)(char *arg, std::int64_t length) { 102959a430aSYi Wu // Day Mon dd hh:mm:ss yyyy\n\0 is 26 characters, e.g. 103959a430aSYi Wu // Tue May 26 21:51:03 2015\n\0 104959a430aSYi Wu char str[26]; 105959a430aSYi Wu // Insufficient space, fill with spaces and return. 106959a430aSYi Wu if (length < 24) { 107959a430aSYi Wu std::memset(arg, ' ', length); 108959a430aSYi Wu return; 109959a430aSYi Wu } 110959a430aSYi Wu 111959a430aSYi Wu Terminator terminator{__FILE__, __LINE__}; 112959a430aSYi Wu std::time_t current_time; 113959a430aSYi Wu std::time(¤t_time); 114959a430aSYi Wu CtimeBuffer(str, sizeof(str), current_time, terminator); 115959a430aSYi Wu 116959a430aSYi Wu // Pad space on the last two byte `\n\0`, start at index 24 included. 117959a430aSYi Wu CopyAndPad(arg, str, length, 24); 118959a430aSYi Wu } 119959a430aSYi Wu 12078ccffc0SDavid Truby std::intptr_t RTNAME(Malloc)(std::size_t size) { 12178ccffc0SDavid Truby return reinterpret_cast<std::intptr_t>(std::malloc(size)); 12278ccffc0SDavid Truby } 12378ccffc0SDavid Truby 1241d4238beSPeixin-Qiao // RESULT = IARGC() 1251d4238beSPeixin-Qiao std::int32_t FORTRAN_PROCEDURE_NAME(iargc)() { return RTNAME(ArgumentCount)(); } 1261d4238beSPeixin-Qiao 1271d4238beSPeixin-Qiao // CALL GETARG(N, ARG) 1281d4238beSPeixin-Qiao void FORTRAN_PROCEDURE_NAME(getarg)( 1294aa04245SPeter Klausler std::int32_t &n, char *arg, std::int64_t length) { 1301d4238beSPeixin-Qiao Descriptor value{*Descriptor::Create(1, length, arg, 0)}; 1311d4238beSPeixin-Qiao (void)RTNAME(GetCommandArgument)( 1321d4238beSPeixin-Qiao n, &value, nullptr, nullptr, __FILE__, __LINE__); 1331d4238beSPeixin-Qiao } 13418af032cSYi Wu 13518af032cSYi Wu // CALL GETLOG(USRNAME) 1364aa04245SPeter Klausler void FORTRAN_PROCEDURE_NAME(getlog)(char *arg, std::int64_t length) { 13718af032cSYi Wu #if _REENTRANT || _POSIX_C_SOURCE >= 199506L 1384aa04245SPeter Klausler if (length >= 1 && getlogin_r(arg, length) == 0) { 1394aa04245SPeter Klausler auto loginLen{std::strlen(arg)}; 1404aa04245SPeter Klausler std::memset( 1414aa04245SPeter Klausler arg + loginLen, ' ', static_cast<std::size_t>(length) - loginLen); 1424aa04245SPeter Klausler return; 14318af032cSYi Wu } 1444aa04245SPeter Klausler #endif 1454aa04245SPeter Klausler #if _WIN32 14618af032cSYi Wu GetUsernameEnvVar("USERNAME", arg, length); 14718af032cSYi Wu #else 14818af032cSYi Wu GetUsernameEnvVar("LOGNAME", arg, length); 14918af032cSYi Wu #endif 15018af032cSYi Wu } 15118af032cSYi Wu 15278ccffc0SDavid Truby void RTNAME(Free)(std::intptr_t ptr) { 15378ccffc0SDavid Truby std::free(reinterpret_cast<void *>(ptr)); 15478ccffc0SDavid Truby } 15578ccffc0SDavid Truby 156afa52de9STom Eccles std::int64_t RTNAME(Signal)(std::int64_t number, void (*handler)(int)) { 157afa52de9STom Eccles // using auto for portability: 158afa52de9STom Eccles // on Windows, this is a void * 159afa52de9STom Eccles // on POSIX, this has the same type as handler 160afa52de9STom Eccles auto result = signal(number, handler); 161afa52de9STom Eccles 162afa52de9STom Eccles // GNU defines the intrinsic as returning an integer, not a pointer. So we 163afa52de9STom Eccles // have to reinterpret_cast 164afa52de9STom Eccles return static_cast<int64_t>(reinterpret_cast<std::uintptr_t>(result)); 165afa52de9STom Eccles } 166afa52de9STom Eccles 167b64c26f3STom Eccles // CALL SLEEP(SECONDS) 168b64c26f3STom Eccles void RTNAME(Sleep)(std::int64_t seconds) { 169b64c26f3STom Eccles // ensure that conversion to unsigned makes sense, 170b64c26f3STom Eccles // sleep(0) is an immidiate return anyway 171b64c26f3STom Eccles if (seconds < 1) { 172b64c26f3STom Eccles return; 173b64c26f3STom Eccles } 174227fe1c1SDavid Truby #if _WIN32 175227fe1c1SDavid Truby Sleep(seconds * 1000); 176227fe1c1SDavid Truby #else 177227fe1c1SDavid Truby sleep(seconds); 178227fe1c1SDavid Truby #endif 179b64c26f3STom Eccles } 180b64c26f3STom Eccles 181668a58b8STom Eccles // TODO: not supported on Windows 182668a58b8STom Eccles #ifndef _WIN32 183668a58b8STom Eccles std::int64_t FORTRAN_PROCEDURE_NAME(access)(const char *name, 184668a58b8STom Eccles std::int64_t nameLength, const char *mode, std::int64_t modeLength) { 185668a58b8STom Eccles std::int64_t ret{-1}; 186668a58b8STom Eccles if (nameLength <= 0 || modeLength <= 0 || !name || !mode) { 187668a58b8STom Eccles return ret; 188668a58b8STom Eccles } 189668a58b8STom Eccles 190668a58b8STom Eccles // ensure name is null terminated 191668a58b8STom Eccles char *newName{nullptr}; 192668a58b8STom Eccles if (name[nameLength - 1] != '\0') { 193668a58b8STom Eccles newName = static_cast<char *>(std::malloc(nameLength + 1)); 194668a58b8STom Eccles std::memcpy(newName, name, nameLength); 195668a58b8STom Eccles newName[nameLength] = '\0'; 196668a58b8STom Eccles name = newName; 197668a58b8STom Eccles } 198668a58b8STom Eccles 199668a58b8STom Eccles // calculate mode 200668a58b8STom Eccles bool read{false}; 201668a58b8STom Eccles bool write{false}; 202668a58b8STom Eccles bool execute{false}; 203668a58b8STom Eccles bool exists{false}; 204668a58b8STom Eccles int imode{0}; 205668a58b8STom Eccles 206668a58b8STom Eccles for (std::int64_t i = 0; i < modeLength; ++i) { 207668a58b8STom Eccles switch (mode[i]) { 208668a58b8STom Eccles case 'r': 209668a58b8STom Eccles read = true; 210668a58b8STom Eccles break; 211668a58b8STom Eccles case 'w': 212668a58b8STom Eccles write = true; 213668a58b8STom Eccles break; 214668a58b8STom Eccles case 'x': 215668a58b8STom Eccles execute = true; 216668a58b8STom Eccles break; 217668a58b8STom Eccles case ' ': 218668a58b8STom Eccles exists = true; 219668a58b8STom Eccles break; 220668a58b8STom Eccles default: 221668a58b8STom Eccles // invalid mode 222668a58b8STom Eccles goto cleanup; 223668a58b8STom Eccles } 224668a58b8STom Eccles } 225668a58b8STom Eccles if (!read && !write && !execute && !exists) { 226668a58b8STom Eccles // invalid mode 227668a58b8STom Eccles goto cleanup; 228668a58b8STom Eccles } 229668a58b8STom Eccles 230668a58b8STom Eccles if (!read && !write && !execute) { 231668a58b8STom Eccles imode = F_OK; 232668a58b8STom Eccles } else { 233668a58b8STom Eccles if (read) { 234668a58b8STom Eccles imode |= R_OK; 235668a58b8STom Eccles } 236668a58b8STom Eccles if (write) { 237668a58b8STom Eccles imode |= W_OK; 238668a58b8STom Eccles } 239668a58b8STom Eccles if (execute) { 240668a58b8STom Eccles imode |= X_OK; 241668a58b8STom Eccles } 242668a58b8STom Eccles } 243668a58b8STom Eccles ret = access(name, imode); 244668a58b8STom Eccles 245668a58b8STom Eccles cleanup: 246668a58b8STom Eccles if (newName) { 247668a58b8STom Eccles free(newName); 248668a58b8STom Eccles } 249668a58b8STom Eccles return ret; 250668a58b8STom Eccles } 251668a58b8STom Eccles #endif 252668a58b8STom Eccles 2535a34e6fdSJean-Didier PAILLEUX // CHDIR(DIR) 2545a34e6fdSJean-Didier PAILLEUX int RTNAME(Chdir)(const char *name) { 2555a34e6fdSJean-Didier PAILLEUX // chdir alias seems to be deprecated on Windows. 2565a34e6fdSJean-Didier PAILLEUX #ifndef _WIN32 2575a34e6fdSJean-Didier PAILLEUX return chdir(name); 2585a34e6fdSJean-Didier PAILLEUX #else 2595a34e6fdSJean-Didier PAILLEUX return _chdir(name); 2605a34e6fdSJean-Didier PAILLEUX #endif 2615a34e6fdSJean-Didier PAILLEUX } 2625a34e6fdSJean-Didier PAILLEUX 263*ecc71de5SJean-Didier PAILLEUX int FORTRAN_PROCEDURE_NAME(ierrno)() { return errno; } 264*ecc71de5SJean-Didier PAILLEUX 2651d4238beSPeixin-Qiao } // namespace Fortran::runtime 266627a8ac7SPeter Klausler } // extern "C" 267