Cppcheck
platform.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2023 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "platform.h"
20 
21 #include "path.h"
22 
23 #include <cstring>
24 #include <iostream>
25 #include <limits>
26 #include <vector>
27 
28 #include "xml.h"
29 
31 {
32  set(Type::Native);
33 }
34 
35 
37 {
38  switch (t) {
39  case Type::Unspecified: // unknown type sizes (sizes etc are set but are not known)
40  case Type::Native: // same as system this code was compile on
41  type = t;
42  sizeof_bool = sizeof(bool);
43  sizeof_short = sizeof(short);
44  sizeof_int = sizeof(int);
45  sizeof_long = sizeof(long);
46  sizeof_long_long = sizeof(long long);
47  sizeof_float = sizeof(float);
48  sizeof_double = sizeof(double);
49  sizeof_long_double = sizeof(long double);
50  sizeof_wchar_t = sizeof(wchar_t);
51  sizeof_size_t = sizeof(std::size_t);
52  sizeof_pointer = sizeof(void *);
53  if (type == Type::Unspecified) {
54  defaultSign = '\0';
55  } else {
56  defaultSign = std::numeric_limits<char>::is_signed ? 's' : 'u';
57  }
58  char_bit = 8;
63  return true;
64  case Type::Win32W:
65  case Type::Win32A:
66  type = t;
67  sizeof_bool = 1; // 4 in Visual C++ 4.2
68  sizeof_short = 2;
69  sizeof_int = 4;
70  sizeof_long = 4;
71  sizeof_long_long = 8;
72  sizeof_float = 4;
73  sizeof_double = 8;
75  sizeof_wchar_t = 2;
76  sizeof_size_t = 4;
77  sizeof_pointer = 4;
78  defaultSign = '\0';
79  char_bit = 8;
84  return true;
85  case Type::Win64:
86  type = t;
87  sizeof_bool = 1;
88  sizeof_short = 2;
89  sizeof_int = 4;
90  sizeof_long = 4;
91  sizeof_long_long = 8;
92  sizeof_float = 4;
93  sizeof_double = 8;
95  sizeof_wchar_t = 2;
96  sizeof_size_t = 8;
97  sizeof_pointer = 8;
98  defaultSign = '\0';
99  char_bit = 8;
104  return true;
105  case Type::Unix32:
106  type = t;
107  sizeof_bool = 1;
108  sizeof_short = 2;
109  sizeof_int = 4;
110  sizeof_long = 4;
111  sizeof_long_long = 8;
112  sizeof_float = 4;
113  sizeof_double = 8;
114  sizeof_long_double = 12;
115  sizeof_wchar_t = 4;
116  sizeof_size_t = 4;
117  sizeof_pointer = 4;
118  defaultSign = '\0';
119  char_bit = 8;
124  return true;
125  case Type::Unix64:
126  type = t;
127  sizeof_bool = 1;
128  sizeof_short = 2;
129  sizeof_int = 4;
130  sizeof_long = 8;
131  sizeof_long_long = 8;
132  sizeof_float = 4;
133  sizeof_double = 8;
134  sizeof_long_double = 16;
135  sizeof_wchar_t = 4;
136  sizeof_size_t = 8;
137  sizeof_pointer = 8;
138  defaultSign = '\0';
139  char_bit = 8;
144  return true;
145  case Type::File:
146  // sizes are not set.
147  return false;
148  }
149  // unsupported platform
150  return false;
151 }
152 
153 bool Platform::set(const std::string& platformstr, std::string& errstr, const std::vector<std::string>& paths, bool verbose)
154 {
155  if (platformstr == "win32A")
156  set(Type::Win32A);
157  else if (platformstr == "win32W")
158  set(Type::Win32W);
159  else if (platformstr == "win64")
160  set(Type::Win64);
161  else if (platformstr == "unix32")
162  set(Type::Unix32);
163  else if (platformstr == "unix64")
164  set(Type::Unix64);
165  else if (platformstr == "native")
166  set(Type::Native);
167  else if (platformstr == "unspecified")
168  set(Type::Unspecified);
169  else if (paths.empty()) {
170  errstr = "unrecognized platform: '" + platformstr + "' (no lookup).";
171  return false;
172  }
173  else {
174  bool found = false;
175  for (const std::string& path : paths) {
176  if (verbose)
177  std::cout << "looking for platform '" + platformstr + "' in '" + path + "'" << std::endl;
178  if (loadFromFile(path.c_str(), platformstr, verbose)) {
179  found = true;
180  break;
181  }
182  }
183  if (!found) {
184  errstr = "unrecognized platform: '" + platformstr + "'.";
185  return false;
186  }
187  }
188 
189  return true;
190 }
191 
192 bool Platform::loadFromFile(const char exename[], const std::string &filename, bool verbose)
193 {
194  // TODO: only append .xml if missing
195  // TODO: use native separators
196  std::vector<std::string> filenames{
197  filename,
198  filename + ".xml",
199  "platforms/" + filename,
200  "platforms/" + filename + ".xml"
201  };
202  if (exename && (std::string::npos != Path::fromNativeSeparators(exename).find('/'))) {
203  filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + filename);
204  filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + "platforms/" + filename);
205  filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + "platforms/" + filename + ".xml");
206  }
207 #ifdef FILESDIR
208  std::string filesdir = FILESDIR;
209  if (!filesdir.empty() && filesdir[filesdir.size()-1] != '/')
210  filesdir += '/';
211  filenames.push_back(filesdir + ("platforms/" + filename));
212  filenames.push_back(filesdir + ("platforms/" + filename + ".xml"));
213 #endif
214 
215  // open file..
216  tinyxml2::XMLDocument doc;
217  bool success = false;
218  for (const std::string & f : filenames) {
219  if (verbose)
220  std::cout << "try to load platform file '" << f << "' ... ";
221  if (doc.LoadFile(f.c_str()) == tinyxml2::XML_SUCCESS) {
222  if (verbose)
223  std::cout << "Success" << std::endl;
224  success = true;
225  break;
226  }
227  if (verbose)
228  std::cout << doc.ErrorStr() << std::endl;
229  }
230  if (!success)
231  return false;
232 
233  return loadFromXmlDocument(&doc);
234 }
235 
236 static unsigned int xmlTextAsUInt(const tinyxml2::XMLElement* node, bool& error)
237 {
238  unsigned int retval = 0;
239  if (node->QueryUnsignedText(&retval) != tinyxml2::XML_SUCCESS)
240  error = true;
241  return retval;
242 }
243 
244 bool Platform::loadFromXmlDocument(const tinyxml2::XMLDocument *doc)
245 {
246  const tinyxml2::XMLElement * const rootnode = doc->FirstChildElement();
247 
248  if (!rootnode || std::strcmp(rootnode->Name(), "platform") != 0)
249  return false;
250 
251  bool error = false;
252  for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
253  if (std::strcmp(node->Name(), "default-sign") == 0) {
254  const char* str = node->GetText();
255  if (str)
256  defaultSign = *str;
257  else
258  error = true;
259  } else if (std::strcmp(node->Name(), "char_bit") == 0)
260  char_bit = xmlTextAsUInt(node, error);
261  else if (std::strcmp(node->Name(), "sizeof") == 0) {
262  for (const tinyxml2::XMLElement *sz = node->FirstChildElement(); sz; sz = sz->NextSiblingElement()) {
263  if (std::strcmp(sz->Name(), "short") == 0)
265  else if (std::strcmp(sz->Name(), "bool") == 0)
267  else if (std::strcmp(sz->Name(), "int") == 0)
269  else if (std::strcmp(sz->Name(), "long") == 0)
271  else if (std::strcmp(sz->Name(), "long-long") == 0)
273  else if (std::strcmp(sz->Name(), "float") == 0)
275  else if (std::strcmp(sz->Name(), "double") == 0)
277  else if (std::strcmp(sz->Name(), "long-double") == 0)
279  else if (std::strcmp(sz->Name(), "pointer") == 0)
281  else if (std::strcmp(sz->Name(), "size_t") == 0)
283  else if (std::strcmp(sz->Name(), "wchar_t") == 0)
285  }
286  }
287  }
288 
293 
294  type = Type::File;
295  return !error;
296 }
297 
298 std::string Platform::getLimitsDefines(bool c99) const
299 {
300  std::string s;
301 
302  // climits / limits.h
303  s += "CHAR_BIT=";
304  s += std::to_string(char_bit);
305  s += ";SCHAR_MIN=";
306  s += std::to_string(min_value(char_bit));
307  s += ";SCHAR_MAX=";
308  s += std::to_string(max_value(char_bit));
309  s += ";UCHAR_MAX=";
310  s += std::to_string(max_value(char_bit+1));
311  s += ";CHAR_MIN=";
312  if (defaultSign == 'u')
313  s += std::to_string(min_value(char_bit));
314  else
315  s += std::to_string(0);
316  s += ";CHAR_MAX=";
317  if (defaultSign == 'u')
318  s += std::to_string(max_value(char_bit+1));
319  else
320  s += std::to_string(max_value(char_bit));
321  // TODO
322  //s += ";MB_LEN_MAX=";
323  s += ";SHRT_MIN=";
324  s += std::to_string(min_value(short_bit));
325  s += ";SHRT_MAX=";
326  s += std::to_string(max_value(short_bit));
327  s += ";USHRT_MAX=";
328  s += std::to_string(max_value(short_bit+1));
329  s += ";INT_MIN=";
330  s += std::to_string(min_value(int_bit));
331  s += ";INT_MAX=";
332  s += std::to_string(max_value(int_bit));
333  s += ";UINT_MAX=";
334  s += std::to_string(max_value(int_bit+1));
335  s += ";LONG_MIN=";
336  s += std::to_string(min_value(long_bit));
337  s += ";LONG_MAX=";
338  s += std::to_string(max_value(long_bit));
339  s += ";ULONG_MAX=";
340  s += std::to_string(max_value(long_bit+1));
341  if (c99) {
342  s += ";LLONG_MIN=";
343  s += std::to_string(min_value(long_long_bit));
344  s += ";LLONG_MAX=";
345  s += std::to_string(max_value(long_long_bit));
346  s += ";ULLONG_MAX=";
347  s += std::to_string(max_value(long_long_bit + 1));
348  }
349 
350  // cstdint / stdint.h
351  // FIXME: these are currently hard-coded in std.cfg
352  /*
353  INTMAX_MIN
354  INTMAX_MAX
355  UINTMAX_MAX
356  INTN_MIN
357  INTN_MAX
358  UINTN_MAX
359  INT_LEASTN_MIN
360  INT_LEASTN_MAX
361  UINT_LEASTN_MAX
362  INT_FASTN_MIN
363  INT_FASTN_MAX
364  UINT_FASTN_MAX
365  INTPTR_MIN
366  INTPTR_MAX
367  UINTPTR_MAX
368  SIZE_MAX
369  PTRDIFF_MIN
370  PTRDIFF_MAX
371  SIG_ATOMIC_MIN
372  SIG_ATOMIC_MAX
373  WCHAR_MIN
374  WCHAR_MAX
375  WINT_MIN
376  WINT_MAX
377 
378  // function-like macros
379  // implemented in std.cfg
380  INTMAX_C
381  UINTMAX_C
382  INTN_C
383  UINTN_C
384  */
385 
386  // cfloat / float.h
387  /*
388  // TODO: implement
389  FLT_RADIX
390 
391  FLT_MANT_DIG
392  DBL_MANT_DIG
393  LDBL_MANT_DIG
394 
395  FLT_DIG
396  DBL_DIG
397  LDBL_DIG
398 
399  FLT_MIN_EXP
400  DBL_MIN_EXP
401  LDBL_MIN_EXP
402 
403  FLT_MIN_10_EXP
404  DBL_MIN_10_EXP
405  LDBL_MIN_10_EXP
406 
407  FLT_MAX_EXP
408  DBL_MAX_EXP
409  LDBL_MAX_EXP
410 
411  FLT_MAX_10_EXP
412  DBL_MAX_10_EXP
413  LDBL_MAX_10_EXP
414 
415  FLT_MAX
416  DBL_MAX
417  LDBL_MAX
418 
419  FLT_EPSILON
420  DBL_EPSILON
421  LDBL_EPSILON
422 
423  FLT_MIN
424  DBL_MIN
425  LDBL_MIN
426 
427  FLT_ROUNDS
428 
429  // C99 / C++11 only
430  FLT_EVAL_METHOD
431 
432  DECIMAL_DIG
433  */
434 
435  return s;
436 }
437 
439 {
440  return getLimitsDefines(cstd >= Standards::cstd_t::C99);
441 }
442 
444 {
445  return getLimitsDefines(cppstd >= Standards::cppstd_t::CPP11);
446 }
static std::string fromNativeSeparators(std::string path)
Convert path to use internal path separators.
Definition: path.cpp:75
static std::string getPathFromFilename(const std::string &filename)
Lookup the path part from a filename (e.g., '/tmp/a.h' -> '/tmp/', 'a.h' -> '')
Definition: path.cpp:88
nonneg int short_bit
bits in char
Definition: platform.h:86
nonneg int int_bit
bits in short
Definition: platform.h:87
std::size_t sizeof_bool
bits in long long
Definition: platform.h:92
std::size_t sizeof_long_long
Definition: platform.h:96
char defaultSign
Definition: platform.h:104
std::size_t sizeof_long_double
Definition: platform.h:99
nonneg int long_bit
bits in int
Definition: platform.h:88
Platform()
Definition: platform.cpp:30
std::size_t sizeof_short
Definition: platform.h:93
std::size_t sizeof_int
Definition: platform.h:94
std::size_t sizeof_pointer
Definition: platform.h:102
static long long max_value(int bit)
Definition: platform.h:51
bool loadFromXmlDocument(const tinyxml2::XMLDocument *doc)
load platform from xml document, primarily for testing
Definition: platform.cpp:244
bool loadFromFile(const char exename[], const std::string &filename, bool verbose=false)
load platform file
Definition: platform.cpp:192
std::size_t sizeof_size_t
Definition: platform.h:101
nonneg int char_bit
Definition: platform.h:85
std::size_t sizeof_float
Definition: platform.h:97
std::string getLimitsDefines(bool c99) const
provides list of defines specified by the limit.h/climits includes
Definition: platform.cpp:298
nonneg int long_long_bit
bits in long
Definition: platform.h:89
Type type
platform type
Definition: platform.h:118
std::size_t sizeof_double
Definition: platform.h:98
std::size_t sizeof_long
Definition: platform.h:95
std::size_t sizeof_wchar_t
Definition: platform.h:100
static long long min_value(int bit)
Definition: platform.h:45
bool set(Type t)
set the platform type for predefined platforms - deprecated use set(const std::string&,...
Definition: platform.cpp:36
Information about a class type.
@ error
Programming error.
static unsigned int xmlTextAsUInt(const tinyxml2::XMLElement *node, bool &error)
Definition: platform.cpp:236
cstd_t
C code standard.
Definition: standards.h:40
cppstd_t
C++ code standard.
Definition: standards.h:43