1 //===-- runtime/environment.cpp -------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "environment.h"
10 #include "tools.h"
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 #include <limits>
15 
16 namespace Fortran::runtime {
17 
18 ExecutionEnvironment executionEnvironment;
19 
20 std::optional<Convert> GetConvertFromString(const char *x, std::size_t n) {
21   static const char *keywords[]{
22       "UNKNOWN", "NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN", "SWAP", nullptr};
23   switch (IdentifyValue(x, n, keywords)) {
24   case 0:
25     return Convert::Unknown;
26   case 1:
27     return Convert::Native;
28   case 2:
29     return Convert::LittleEndian;
30   case 3:
31     return Convert::BigEndian;
32   case 4:
33     return Convert::Swap;
34   default:
35     return std::nullopt;
36   }
37 }
38 
39 void ExecutionEnvironment::Configure(
40     int ac, const char *av[], const char *env[]) {
41   argc = ac;
42   argv = av;
43   envp = env;
44   listDirectedOutputLineLengthLimit = 79; // PGI default
45   defaultOutputRoundingMode =
46       decimal::FortranRounding::RoundNearest; // RP(==RN)
47   conversion = Convert::Unknown;
48 
49   if (auto *x{std::getenv("FORT_FMT_RECL")}) {
50     char *end;
51     auto n{std::strtol(x, &end, 10)};
52     if (n > 0 && n < std::numeric_limits<int>::max() && *end == '\0') {
53       listDirectedOutputLineLengthLimit = n;
54     } else {
55       std::fprintf(
56           stderr, "Fortran runtime: FORT_FMT_RECL=%s is invalid; ignored\n", x);
57     }
58   }
59 
60   if (auto *x{std::getenv("FORT_CONVERT")}) {
61     if (auto convert{GetConvertFromString(x, std::strlen(x))}) {
62       conversion = *convert;
63     } else {
64       std::fprintf(
65           stderr, "Fortran runtime: FORT_CONVERT=%s is invalid; ignored\n", x);
66     }
67   }
68 
69   // TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
70 }
71 
72 const char *ExecutionEnvironment::GetEnv(
73     const char *name, std::size_t name_length) {
74   if (!envp) {
75     // TODO: Ask std::getenv.
76     return nullptr;
77   }
78 
79   // envp is an array of strings of the form "name=value".
80   for (const char **var{envp}; *var != nullptr; ++var) {
81     const char *eq{std::strchr(*var, '=')};
82     if (!eq) {
83       // Found a malformed environment string, just ignore it.
84       continue;
85     }
86     if (static_cast<std::size_t>(eq - *var) != name_length) {
87       continue;
88     }
89     if (std::memcmp(*var, name, name_length) == 0) {
90       return eq + 1;
91     }
92   }
93   return nullptr;
94 }
95 } // namespace Fortran::runtime
96