xref: /llvm-project/flang/runtime/tools.cpp (revision 43fadefb0e77c56de7637c391cf98cf709b27095)
1352d347aSAlexis Perry //===-- runtime/tools.cpp ---------------------------------------*- C++ -*-===//
2352d347aSAlexis Perry //
3352d347aSAlexis Perry // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4352d347aSAlexis Perry // See https://llvm.org/LICENSE.txt for license information.
5352d347aSAlexis Perry // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6352d347aSAlexis Perry //
7352d347aSAlexis Perry //===----------------------------------------------------------------------===//
8352d347aSAlexis Perry 
9352d347aSAlexis Perry #include "tools.h"
10e372e0f9Speter klausler #include "terminator.h"
11231fae90SIsuru Fernando #include <algorithm>
12e372e0f9Speter klausler #include <cstdint>
13352d347aSAlexis Perry #include <cstring>
14352d347aSAlexis Perry 
15352d347aSAlexis Perry namespace Fortran::runtime {
16352d347aSAlexis Perry 
17675ad1bcSpeter klausler std::size_t TrimTrailingSpaces(const char *s, std::size_t n) {
18675ad1bcSpeter klausler   while (n > 0 && s[n - 1] == ' ') {
19675ad1bcSpeter klausler     --n;
20675ad1bcSpeter klausler   }
21675ad1bcSpeter klausler   return n;
22675ad1bcSpeter klausler }
23675ad1bcSpeter klausler 
24352d347aSAlexis Perry OwningPtr<char> SaveDefaultCharacter(
2595696d56Speter klausler     const char *s, std::size_t length, const Terminator &terminator) {
26352d347aSAlexis Perry   if (s) {
27352d347aSAlexis Perry     auto *p{static_cast<char *>(AllocateMemoryOrCrash(terminator, length + 1))};
28352d347aSAlexis Perry     std::memcpy(p, s, length);
29352d347aSAlexis Perry     p[length] = '\0';
30352d347aSAlexis Perry     return OwningPtr<char>{p};
31352d347aSAlexis Perry   } else {
32352d347aSAlexis Perry     return OwningPtr<char>{};
33352d347aSAlexis Perry   }
34352d347aSAlexis Perry }
35352d347aSAlexis Perry 
36352d347aSAlexis Perry static bool CaseInsensitiveMatch(
37352d347aSAlexis Perry     const char *value, std::size_t length, const char *possibility) {
383b635714Speter klausler   for (; length-- > 0; ++possibility) {
393b635714Speter klausler     char ch{*value++};
40352d347aSAlexis Perry     if (ch >= 'a' && ch <= 'z') {
41352d347aSAlexis Perry       ch += 'A' - 'a';
42352d347aSAlexis Perry     }
433b635714Speter klausler     if (*possibility != ch) {
443b635714Speter klausler       if (*possibility != '\0' || ch != ' ') {
45352d347aSAlexis Perry         return false;
46352d347aSAlexis Perry       }
473b635714Speter klausler       // Ignore trailing blanks (12.5.6.2 p1)
483b635714Speter klausler       while (length-- > 0) {
493b635714Speter klausler         if (*value++ != ' ') {
503b635714Speter klausler           return false;
513b635714Speter klausler         }
523b635714Speter klausler       }
533b635714Speter klausler       return true;
543b635714Speter klausler     }
55352d347aSAlexis Perry   }
56352d347aSAlexis Perry   return *possibility == '\0';
57352d347aSAlexis Perry }
58352d347aSAlexis Perry 
59352d347aSAlexis Perry int IdentifyValue(
60352d347aSAlexis Perry     const char *value, std::size_t length, const char *possibilities[]) {
61352d347aSAlexis Perry   if (value) {
62352d347aSAlexis Perry     for (int j{0}; possibilities[j]; ++j) {
63352d347aSAlexis Perry       if (CaseInsensitiveMatch(value, length, possibilities[j])) {
64352d347aSAlexis Perry         return j;
65352d347aSAlexis Perry       }
66352d347aSAlexis Perry     }
67352d347aSAlexis Perry   }
68352d347aSAlexis Perry   return -1;
69352d347aSAlexis Perry }
703b635714Speter klausler 
713b635714Speter klausler void ToFortranDefaultCharacter(
723b635714Speter klausler     char *to, std::size_t toLength, const char *from) {
733b635714Speter klausler   std::size_t len{std::strlen(from)};
743b635714Speter klausler   if (len < toLength) {
75*43fadefbSpeter klausler     std::memcpy(to, from, len);
763b635714Speter klausler     std::memset(to + len, ' ', toLength - len);
77*43fadefbSpeter klausler   } else {
78*43fadefbSpeter klausler     std::memcpy(to, from, toLength);
793b635714Speter klausler   }
803b635714Speter klausler }
813b635714Speter klausler 
82e372e0f9Speter klausler void CheckConformability(const Descriptor &to, const Descriptor &x,
83e372e0f9Speter klausler     Terminator &terminator, const char *funcName, const char *toName,
84e372e0f9Speter klausler     const char *xName) {
85e372e0f9Speter klausler   if (x.rank() == 0) {
86e372e0f9Speter klausler     return; // scalar conforms with anything
87e372e0f9Speter klausler   }
88e372e0f9Speter klausler   int rank{to.rank()};
89e372e0f9Speter klausler   if (x.rank() != rank) {
90e372e0f9Speter klausler     terminator.Crash(
91e372e0f9Speter klausler         "Incompatible array arguments to %s: %s has rank %d but %s has rank %d",
92e372e0f9Speter klausler         funcName, toName, rank, xName, x.rank());
93e372e0f9Speter klausler   } else {
94e372e0f9Speter klausler     for (int j{0}; j < rank; ++j) {
95e372e0f9Speter klausler       auto toExtent{static_cast<std::int64_t>(to.GetDimension(j).Extent())};
96e372e0f9Speter klausler       auto xExtent{static_cast<std::int64_t>(x.GetDimension(j).Extent())};
97e372e0f9Speter klausler       if (xExtent != toExtent) {
98e372e0f9Speter klausler         terminator.Crash("Incompatible array arguments to %s: dimension %d of "
99e372e0f9Speter klausler                          "%s has extent %" PRId64 " but %s has extent %" PRId64,
100e372e0f9Speter klausler             funcName, j, toName, toExtent, xName, xExtent);
101e372e0f9Speter klausler       }
102e372e0f9Speter klausler     }
103e372e0f9Speter klausler   }
104e372e0f9Speter klausler }
105e372e0f9Speter klausler 
106e372e0f9Speter klausler void CheckIntegerKind(Terminator &terminator, int kind, const char *intrinsic) {
107e372e0f9Speter klausler   if (kind < 1 || kind > 16 || (kind & (kind - 1)) != 0) {
108e372e0f9Speter klausler     terminator.Crash("%s: bad KIND=%d argument", intrinsic, kind);
109e372e0f9Speter klausler   }
110e372e0f9Speter klausler }
1111f879005STim Keith } // namespace Fortran::runtime
112