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