1651f58bfSDiana Picus //===-- runtime/tools.cpp -------------------------------------------------===//
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>
13824bf908SDiana Picus #include <cstdlib>
14352d347aSAlexis Perry #include <cstring>
15352d347aSAlexis Perry 
16352d347aSAlexis Perry namespace Fortran::runtime {
17352d347aSAlexis Perry 
TrimTrailingSpaces(const char * s,std::size_t n)18675ad1bcSpeter klausler std::size_t TrimTrailingSpaces(const char *s, std::size_t n) {
19675ad1bcSpeter klausler   while (n > 0 && s[n - 1] == ' ') {
20675ad1bcSpeter klausler     --n;
21675ad1bcSpeter klausler   }
22675ad1bcSpeter klausler   return n;
23675ad1bcSpeter klausler }
24675ad1bcSpeter klausler 
SaveDefaultCharacter(const char * s,std::size_t length,const Terminator & terminator)25352d347aSAlexis Perry OwningPtr<char> SaveDefaultCharacter(
2695696d56Speter klausler     const char *s, std::size_t length, const Terminator &terminator) {
27352d347aSAlexis Perry   if (s) {
28352d347aSAlexis Perry     auto *p{static_cast<char *>(AllocateMemoryOrCrash(terminator, length + 1))};
29352d347aSAlexis Perry     std::memcpy(p, s, length);
30352d347aSAlexis Perry     p[length] = '\0';
31352d347aSAlexis Perry     return OwningPtr<char>{p};
32352d347aSAlexis Perry   } else {
33352d347aSAlexis Perry     return OwningPtr<char>{};
34352d347aSAlexis Perry   }
35352d347aSAlexis Perry }
36352d347aSAlexis Perry 
CaseInsensitiveMatch(const char * value,std::size_t length,const char * possibility)37352d347aSAlexis Perry static bool CaseInsensitiveMatch(
38352d347aSAlexis Perry     const char *value, std::size_t length, const char *possibility) {
393b635714Speter klausler   for (; length-- > 0; ++possibility) {
403b635714Speter klausler     char ch{*value++};
41352d347aSAlexis Perry     if (ch >= 'a' && ch <= 'z') {
42352d347aSAlexis Perry       ch += 'A' - 'a';
43352d347aSAlexis Perry     }
443b635714Speter klausler     if (*possibility != ch) {
453b635714Speter klausler       if (*possibility != '\0' || ch != ' ') {
46352d347aSAlexis Perry         return false;
47352d347aSAlexis Perry       }
483b635714Speter klausler       // Ignore trailing blanks (12.5.6.2 p1)
493b635714Speter klausler       while (length-- > 0) {
503b635714Speter klausler         if (*value++ != ' ') {
513b635714Speter klausler           return false;
523b635714Speter klausler         }
533b635714Speter klausler       }
543b635714Speter klausler       return true;
553b635714Speter klausler     }
56352d347aSAlexis Perry   }
57352d347aSAlexis Perry   return *possibility == '\0';
58352d347aSAlexis Perry }
59352d347aSAlexis Perry 
IdentifyValue(const char * value,std::size_t length,const char * possibilities[])60352d347aSAlexis Perry int IdentifyValue(
61352d347aSAlexis Perry     const char *value, std::size_t length, const char *possibilities[]) {
62352d347aSAlexis Perry   if (value) {
63352d347aSAlexis Perry     for (int j{0}; possibilities[j]; ++j) {
64352d347aSAlexis Perry       if (CaseInsensitiveMatch(value, length, possibilities[j])) {
65352d347aSAlexis Perry         return j;
66352d347aSAlexis Perry       }
67352d347aSAlexis Perry     }
68352d347aSAlexis Perry   }
69352d347aSAlexis Perry   return -1;
70352d347aSAlexis Perry }
713b635714Speter klausler 
ToFortranDefaultCharacter(char * to,std::size_t toLength,const char * from)723b635714Speter klausler void ToFortranDefaultCharacter(
733b635714Speter klausler     char *to, std::size_t toLength, const char *from) {
743b635714Speter klausler   std::size_t len{std::strlen(from)};
753b635714Speter klausler   if (len < toLength) {
7643fadefbSpeter klausler     std::memcpy(to, from, len);
773b635714Speter klausler     std::memset(to + len, ' ', toLength - len);
7843fadefbSpeter klausler   } else {
7943fadefbSpeter klausler     std::memcpy(to, from, toLength);
803b635714Speter klausler   }
813b635714Speter klausler }
823b635714Speter klausler 
CheckConformability(const Descriptor & to,const Descriptor & x,Terminator & terminator,const char * funcName,const char * toName,const char * xName)83e372e0f9Speter klausler void CheckConformability(const Descriptor &to, const Descriptor &x,
84e372e0f9Speter klausler     Terminator &terminator, const char *funcName, const char *toName,
85e372e0f9Speter klausler     const char *xName) {
86e372e0f9Speter klausler   if (x.rank() == 0) {
87e372e0f9Speter klausler     return; // scalar conforms with anything
88e372e0f9Speter klausler   }
89e372e0f9Speter klausler   int rank{to.rank()};
90e372e0f9Speter klausler   if (x.rank() != rank) {
91e372e0f9Speter klausler     terminator.Crash(
92e372e0f9Speter klausler         "Incompatible array arguments to %s: %s has rank %d but %s has rank %d",
93e372e0f9Speter klausler         funcName, toName, rank, xName, x.rank());
94e372e0f9Speter klausler   } else {
95e372e0f9Speter klausler     for (int j{0}; j < rank; ++j) {
96e372e0f9Speter klausler       auto toExtent{static_cast<std::int64_t>(to.GetDimension(j).Extent())};
97e372e0f9Speter klausler       auto xExtent{static_cast<std::int64_t>(x.GetDimension(j).Extent())};
98e372e0f9Speter klausler       if (xExtent != toExtent) {
99e372e0f9Speter klausler         terminator.Crash("Incompatible array arguments to %s: dimension %d of "
100e372e0f9Speter klausler                          "%s has extent %" PRId64 " but %s has extent %" PRId64,
101b910cf98SJean Perier             funcName, j + 1, toName, toExtent, xName, xExtent);
102e372e0f9Speter klausler       }
103e372e0f9Speter klausler     }
104e372e0f9Speter klausler   }
105e372e0f9Speter klausler }
106e372e0f9Speter klausler 
CheckIntegerKind(Terminator & terminator,int kind,const char * intrinsic)107e372e0f9Speter klausler void CheckIntegerKind(Terminator &terminator, int kind, const char *intrinsic) {
108e372e0f9Speter klausler   if (kind < 1 || kind > 16 || (kind & (kind - 1)) != 0) {
109*d4609ae4SPeter Steinfeld     terminator.Crash(
110*d4609ae4SPeter Steinfeld         "not yet implemented: %s: KIND=%d argument", intrinsic, kind);
111e372e0f9Speter klausler   }
112e372e0f9Speter klausler }
1131f879005STim Keith } // namespace Fortran::runtime
114