1 //===-- runtime/stat.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 "stat.h"
10 #include "terminator.h"
11 #include "flang/Runtime/descriptor.h"
12 
13 namespace Fortran::runtime {
14 const char *StatErrorString(int stat) {
15   switch (stat) {
16   case StatOk:
17     return "No error";
18 
19   case StatBaseNull:
20     return "Base address is null";
21   case StatBaseNotNull:
22     return "Base address is not null";
23   case StatInvalidElemLen:
24     return "Invalid element length";
25   case StatInvalidRank:
26     return "Invalid rank";
27   case StatInvalidType:
28     return "Invalid type";
29   case StatInvalidAttribute:
30     return "Invalid attribute";
31   case StatInvalidExtent:
32     return "Invalid extent";
33   case StatInvalidDescriptor:
34     return "Invalid descriptor";
35   case StatMemAllocation:
36     return "Memory allocation failed";
37   case StatOutOfBounds:
38     return "Out of bounds";
39 
40   case StatFailedImage:
41     return "Failed image";
42   case StatLocked:
43     return "Locked";
44   case StatLockedOtherImage:
45     return "Other image locked";
46   case StatStoppedImage:
47     return "Image stopped";
48   case StatUnlocked:
49     return "Unlocked";
50   case StatUnlockedFailedImage:
51     return "Failed image unlocked";
52 
53   case StatInvalidArgumentNumber:
54     return "Invalid argument number";
55   case StatMissingArgument:
56     return "Missing argument";
57   case StatValueTooShort:
58     return "Value too short";
59 
60   default:
61     return nullptr;
62   }
63 }
64 
65 int ToErrmsg(const Descriptor *errmsg, int stat) {
66   if (stat != StatOk && errmsg && errmsg->raw().base_addr &&
67       errmsg->type() == TypeCode(TypeCategory::Character, 1) &&
68       errmsg->rank() == 0) {
69     if (const char *msg{StatErrorString(stat)}) {
70       char *buffer{errmsg->OffsetElement()};
71       std::size_t bufferLength{errmsg->ElementBytes()};
72       std::size_t msgLength{std::strlen(msg)};
73       if (msgLength >= bufferLength) {
74         std::memcpy(buffer, msg, bufferLength);
75       } else {
76         std::memcpy(buffer, msg, msgLength);
77         std::memset(buffer + msgLength, ' ', bufferLength - msgLength);
78       }
79     }
80   }
81   return stat;
82 }
83 
84 int ReturnError(
85     Terminator &terminator, int stat, const Descriptor *errmsg, bool hasStat) {
86   if (stat == StatOk || hasStat) {
87     return ToErrmsg(errmsg, stat);
88   } else if (const char *msg{StatErrorString(stat)}) {
89     terminator.Crash(msg);
90   } else {
91     terminator.Crash("Invalid Fortran runtime STAT= code %d", stat);
92   }
93   return stat;
94 }
95 } // namespace Fortran::runtime
96