The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
version.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2016 by Ignacio Riquelme Morelle <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
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 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "desktop/version.hpp"
18 
19 #include "filesystem.hpp"
20 #include "formatter.hpp"
21 #include "gettext.hpp"
22 #include "log.hpp"
23 #include "scoped_resource.hpp"
25 
26 #include <cstring>
27 
28 #if defined(_X11) || defined(__APPLE__)
29 
30 #include <cerrno>
31 #include <sys/utsname.h>
32 
33 #endif
34 
35 #ifdef _WIN32
36 
37 #ifndef UNICODE
38 #define UNICODE
39 #endif
40 #define WIN32_LEAN_AND_MEAN
41 
42 #include <windows.h>
43 
44 #endif
45 
46 static lg::log_domain log_desktop("desktop");
47 #define ERR_DU LOG_STREAM(err, log_desktop)
48 #define LOG_DU LOG_STREAM(info, log_desktop)
49 
50 namespace desktop
51 {
52 
53 namespace
54 {
55 
56 #ifdef _WIN32
57 /**
58  * Detects whether we are running on Wine or not.
59  *
60  * This is for informational purposes only and all Windows code should assume
61  * we are running on the real thing instead.
62  */
63 bool on_wine()
64 {
65  HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
66  if(!ntdll) {
67  return false;
68  }
69 
70  return GetProcAddress(ntdll, "wine_get_version") != nullptr;
71 }
72 #endif
73 
74 #if defined(_X11) || defined(__APPLE__)
75 /**
76  * Release policy for POSIX pipe streams opened with popen(3).
77  */
78 struct posix_pipe_release_policy
79 {
80  void operator()(std::FILE* f) const { if(f != nullptr) { pclose(f); } }
81 };
82 
83 /**
84  * Scoped POSIX pipe stream.
85  *
86  * The stream object type is the same as a regular file stream, but the release
87  * policy is different, as required by popen(3).
88  */
90 
91 /**
92  * Read a single line from the specified pipe.
93  *
94  * @returns An empty string if the pipe is invalid or nothing could be read.
95  */
96 std::string read_pipe_line(scoped_posix_pipe& p)
97 {
98  if(!p.get()) {
99  return "";
100  }
101 
102  std::string ver;
103  int c;
104 
105  ver.reserve(64);
106 
107  // We only want the first line.
108  while((c = std::fgetc(p)) && c != EOF && c != '\n' && c != '\r') {
109  ver.push_back(static_cast<char>(c));
110  }
111 
112  return ver;
113 }
114 #endif
115 
116 } // end anonymous namespace
117 
119 {
120 #if defined(_X11) || defined(__APPLE__)
121 
122 #ifdef __APPLE__
123 
124  //
125  // Standard Mac OSX version
126  //
127 
128  static const std::string version_plist = "/System/Library/CoreServices/SystemVersion.plist";
129  static const std::string defaults_bin = "/usr/bin/defaults";
130 
131  if(filesystem::file_exists(defaults_bin) && filesystem::file_exists(version_plist)) {
132  static const std::string cmdline
133  = defaults_bin + " read " + version_plist + " ProductUserVisibleVersion";
134 
135  scoped_posix_pipe p(popen(cmdline.c_str(), "r"));
136  const std::string& ver = read_pipe_line(p);
137 
138  if(!ver.empty()) {
139  return "Apple OS X " + ver;
140  }
141  }
142 
143 #else
144 
145  //
146  // Linux Standard Base version.
147  //
148 
149  static const std::string lsb_release_bin = "/usr/bin/lsb_release";
150 
151  if(filesystem::file_exists(lsb_release_bin)) {
152  static const std::string cmdline = lsb_release_bin + " -s -d";
153 
154  scoped_posix_pipe p(popen(cmdline.c_str(), "r"));
155  std::string ver = read_pipe_line(p);
156 
157  if(ver.length() >= 2 && ver[0] == '"' && ver[ver.length() - 1] == '"') {
158  ver.erase(ver.length() - 1, 1);
159  ver.erase(0, 1);
160  }
161 
162  // Check this again in case we got "" above for some weird reason.
163  if(!ver.empty()) {
164  return ver;
165  }
166  }
167 #endif
168 
169  //
170  // POSIX uname version.
171  //
172 
173  utsname u;
174 
175  if(uname(&u) != 0) {
176  ERR_DU << "os_version: uname error (" << strerror(errno) << ")\n";
177  }
178 
179  return (formatter() << u.sysname << ' '
180  << u.release << ' '
181  << u.version << ' '
182  << u.machine).str();
183 
184 #elif defined(_WIN32)
185 
186  //
187  // Windows version.
188  //
189 
190  static const std::string base
191  = !on_wine() ? "Microsoft Windows" : "Wine/Microsoft Windows";
192 
193  OSVERSIONINFOEX v = { sizeof(OSVERSIONINFOEX) };
194 
195  if(!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&v))) {
196  ERR_DU << "os_version: GetVersionEx error ("
197  << GetLastError() << ")\n";
198  return base;
199  }
200 
201  const DWORD vnum = v.dwMajorVersion * 100 + v.dwMinorVersion;
203 
204  switch(vnum)
205  {
206  case 500:
207  version = "2000";
208  break;
209  case 501:
210  version = "XP";
211  break;
212  case 502:
213  // This will misidentify XP x64 but who really cares?
214  version = "Server 2003";
215  break;
216  case 600:
217  if(v.wProductType == VER_NT_WORKSTATION) {
218  version = "Vista";
219  } else {
220  version = "Server 2008";
221  }
222  break;
223  case 601:
224  if(v.wProductType == VER_NT_WORKSTATION) {
225  version = "7";
226  } else {
227  version = "Server 2008 R2";
228  }
229  break;
230  case 602:
231  if(v.wProductType == VER_NT_WORKSTATION) {
232  version = "8";
233  } else {
234  version = "Server 2012";
235  }
236  break;
237  case 603:
238  if(v.wProductType == VER_NT_WORKSTATION) {
239  version = "8.1";
240  } else {
241  version = "Server 2012 R2";
242  }
243  break;
244  case 1000:
245  if(v.wProductType == VER_NT_WORKSTATION) {
246  version = "10";
247  break;
248  } // else fallback to default
249  default:
250  if(v.wProductType != VER_NT_WORKSTATION) {
251  version = "Server";
252  }
253  }
254 
255  if(v.szCSDVersion && *v.szCSDVersion) {
256  version += " ";
257  version += unicode_cast<std::string>(std::wstring(v.szCSDVersion));
258  }
259 
260  version += " (";
261  // Add internal version numbers.
262  version += (formatter()
263  << v.dwMajorVersion << '.'
264  << v.dwMinorVersion << '.'
265  << v.dwBuildNumber).str();
266  version += ")";
267 
268  return base + " " + version;
269 
270 #else
271 
272  //
273  // "I don't know where I am" version.
274  //
275 
276  ERR_DU << "os_version(): unsupported platform\n";
277  return _("operating_system^<unknown>");
278 
279 #endif
280 }
281 
282 } // end namespace desktop
283 
static lg::log_domain log_desktop("desktop")
ucs4_convert_impl::enableif< TD, typename TS::value_type >::type unicode_cast(const TS &source)
scoped_resource: class template, functions, helper policies etc. for resource management.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
std::ostringstream wrapper.
Definition: formatter.hpp:32
const GLdouble * v
Definition: glew.h:1359
A class template, scoped_resource, designed to implement the Resource Acquisition Is Initialization (...
GLfloat GLfloat p
Definition: glew.h:12766
Platform identification and version information functions.
#define ERR_DU
Definition: version.cpp:47
std::string os_version()
Returns a string with the running OS name and version information.
Definition: version.cpp:118
Declarations for File-IO.
Standard logging facilities (interface).
#define c
Definition: glew.h:12743
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
const std::string version
Definition: game_config.cpp:48
GLsizei const GLcharARB ** string
Definition: glew.h:4503
GLclampf f
Definition: glew.h:3024