1//============================================================================
2//
3// BBBBB SSSS PPPPP FFFFFF
4// BB BB SS SS PP PP FF
5// BB BB SS PP PP FF
6// BBBBB SSSS PPPPP FFFF -- "Brad's Simple Portability Framework"
7// BB BB SS PP FF
8// BB BB SS SS PP FF
9// BBBBB SSSS PP FF
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef BSPF_HXX
19#define BSPF_HXX
20
21/**
22 This file defines various basic data types and preprocessor variables
23 that need to be defined for different operating systems.
24
25 @author Bradford W. Mott and Stephen Anthony
26*/
27
28#include <climits>
29#include <cstdint>
30// Types for 8/16/32/64-bit signed and unsigned integers
31using Int8 = int8_t;
32using uInt8 = uint8_t;
33using Int16 = int16_t;
34using uInt16 = uint16_t;
35using Int32 = int32_t;
36using uInt32 = uint32_t;
37using Int64 = int64_t;
38using uInt64 = uint64_t;
39
40// The following code should provide access to the standard C++ objects and
41// types: cout, cerr, string, ostream, istream, etc.
42#include <array>
43#include <algorithm>
44#include <iostream>
45#include <fstream>
46#include <iomanip>
47#include <memory>
48#include <string>
49#include <sstream>
50#include <cstring>
51#include <cctype>
52#include <cstdio>
53#include <ctime>
54#include <utility>
55#include <vector>
56
57using std::cin;
58using std::cout;
59using std::cerr;
60using std::endl;
61using std::string;
62using std::istream;
63using std::ostream;
64using std::fstream;
65using std::iostream;
66using std::ifstream;
67using std::ofstream;
68using std::ostringstream;
69using std::istringstream;
70using std::stringstream;
71using std::unique_ptr;
72using std::shared_ptr;
73using std::make_unique;
74using std::make_shared;
75using std::array;
76using std::vector;
77using std::runtime_error;
78
79// Common array types
80using IntArray = std::vector<Int32>;
81using uIntArray = std::vector<uInt32>;
82using BoolArray = std::vector<bool>;
83using ByteArray = std::vector<uInt8>;
84using ShortArray = std::vector<uInt16>;
85using StringList = std::vector<std::string>;
86using ByteBuffer = std::unique_ptr<uInt8[]>;
87
88// We use KB a lot; let's make a literal for it
89constexpr uInt32 operator "" _KB(unsigned long long size)
90{
91 return static_cast<uInt32>(size * 1024);
92}
93
94static const string EmptyString("");
95
96// This is defined by some systems, but Stella has other uses for it
97#undef PAGE_SIZE
98#undef PAGE_MASK
99
100namespace BSPF
101{
102 static constexpr float PI_f = 3.141592653589793238462643383279502884f;
103 static constexpr double PI_d = 3.141592653589793238462643383279502884;
104
105 // CPU architecture type
106 // This isn't complete yet, but takes care of all the major platforms
107 #if defined(__i386__) || defined(_M_IX86)
108 static const string ARCH = "i386";
109 #elif defined(__x86_64__) || defined(_WIN64)
110 static const string ARCH = "x86_64";
111 #elif defined(__powerpc__) || defined(__ppc__)
112 static const string ARCH = "ppc";
113 #elif defined(__arm__) || defined(__thumb__)
114 static const string ARCH = "arm32";
115 #elif defined(__aarch64__)
116 static const string ARCH = "arm64";
117 #else
118 static const string ARCH = "NOARCH";
119 #endif
120
121 // Combines 'max' and 'min', and clamps value to the upper/lower value
122 // if it is outside the specified range
123 template<class T> inline T clamp(T val, T lower, T upper)
124 {
125 return (val < lower) ? lower : (val > upper) ? upper : val;
126 }
127 template<class T> inline void clamp(T& val, T lower, T upper, T setVal)
128 {
129 if(val < lower || val > upper) val = setVal;
130 }
131
132 // Convert string to given case
133 inline const string& toUpperCase(string& s)
134 {
135 transform(s.begin(), s.end(), s.begin(), ::toupper);
136 return s;
137 }
138 inline const string& toLowerCase(string& s)
139 {
140 transform(s.begin(), s.end(), s.begin(), ::tolower);
141 return s;
142 }
143
144 // Compare two strings, ignoring case
145 inline int compareIgnoreCase(const string& s1, const string& s2)
146 {
147 #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
148 return _stricmp(s1.c_str(), s2.c_str());
149 #else
150 return strcasecmp(s1.c_str(), s2.c_str());
151 #endif
152 }
153 inline int compareIgnoreCase(const char* s1, const char* s2)
154 {
155 #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
156 return _stricmp(s1, s2);
157 #else
158 return strcasecmp(s1, s2);
159 #endif
160 }
161
162 // Test whether the first string starts with the second one (case insensitive)
163 inline bool startsWithIgnoreCase(const string& s1, const string& s2)
164 {
165 #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
166 return _strnicmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
167 #else
168 return strncasecmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
169 #endif
170 }
171 inline bool startsWithIgnoreCase(const char* s1, const char* s2)
172 {
173 #if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
174 return _strnicmp(s1, s2, strlen(s2)) == 0;
175 #else
176 return strncasecmp(s1, s2, strlen(s2)) == 0;
177 #endif
178 }
179
180 // Test whether two strings are equal (case insensitive)
181 inline bool equalsIgnoreCase(const string& s1, const string& s2)
182 {
183 return compareIgnoreCase(s1, s2) == 0;
184 }
185
186 // Find location (if any) of the second string within the first,
187 // starting from 'startpos' in the first string
188 inline size_t findIgnoreCase(const string& s1, const string& s2, size_t startpos = 0)
189 {
190 auto pos = std::search(s1.cbegin()+startpos, s1.cend(),
191 s2.cbegin(), s2.cend(), [](char ch1, char ch2) {
192 return toupper(uInt8(ch1)) == toupper(uInt8(ch2));
193 });
194 return pos == s1.cend() ? string::npos : pos - (s1.cbegin()+startpos);
195 }
196
197 // Test whether the first string ends with the second one (case insensitive)
198 inline bool endsWithIgnoreCase(const string& s1, const string& s2)
199 {
200 if(s1.length() >= s2.length())
201 {
202 const char* end = s1.c_str() + s1.length() - s2.length();
203 return compareIgnoreCase(end, s2.c_str()) == 0;
204 }
205 return false;
206 }
207
208 // Test whether the first string contains the second one (case insensitive)
209 inline bool containsIgnoreCase(const string& s1, const string& s2)
210 {
211 return findIgnoreCase(s1, s2) != string::npos;
212 }
213
214 // Test whether the first string matches the second one (case insensitive)
215 // - the first character must match
216 // - the following characters must appear in the order of the first string
217 inline bool matches(const string& s1, const string& s2)
218 {
219 if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1)))
220 {
221 size_t pos = 1;
222 for(uInt32 j = 1; j < s2.size(); ++j)
223 {
224 size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos);
225 if(found == string::npos)
226 return false;
227 pos += found + 1;
228 }
229 return true;
230 }
231 return false;
232 }
233
234 // C++11 way to get local time
235 // Equivalent to the C-style localtime() function, but is thread-safe
236 inline std::tm localTime()
237 {
238 std::time_t currtime;
239 std::time(&currtime);
240 std::tm tm_snapshot;
241 #if (defined BSPF_WINDOWS || defined __WIN32__) && (!defined __GNUG__ || defined __MINGW32__)
242 localtime_s(&tm_snapshot, &currtime);
243 #else
244 localtime_r(&currtime, &tm_snapshot);
245 #endif
246 return tm_snapshot;
247 }
248} // namespace BSPF
249
250#endif
251