Scarab  v2.4.11
Project 8 C++ Utility Library
version_base.cc
Go to the documentation of this file.
1 /*
2  * version_base.cc
3  *
4  * Created on: Jul 23, 2018
5  * Author: N.S. Oblath
6  */
7 
8 #define SCARAB_API_EXPORTS
9 
10 #include "version_base.hh"
11 
12 #include "logger.hh"
13 #include "path.hh"
14 
15 #include <sstream>
16 
17 #ifdef _WIN32
18 #include <Windows.h> // for extracting the exe name, gethostname and GetUserName
19 #elif __APPLE__
20 #include <mach-o/dyld.h> // for extracting the exe name
21 #include <unistd.h> // for gethostname and getlogin_r
22 #include <pwd.h> // for struct passwd
23 #elif __linux
24 #include <unistd.h> // for readlink, gethostname and getlogin_r
25 #include <pwd.h> // for struct passwd
26 #endif
27 
28 using std::string;
29 
30 namespace scarab
31 {
32  LOGGER( slog, "scarab_version" );
33 
35  {}
36 
38  {}
39 
41  {}
42 
44  {
45  return *this;
46  }
47 
48 
50 
52  version_ifc(),
53  f_major_ver(),
54  f_minor_ver(),
55  f_patch_ver(),
56  f_version(),
57  f_package(),
58  f_commit(),
59  f_exe_name(),
60  f_hostname(),
61  f_username()
62  {
64  }
65 
66  version_semantic::version_semantic( unsigned a_maj_ver, unsigned a_min_ver, unsigned a_patch_ver ) :
67  version_ifc(),
68  f_major_ver( a_maj_ver ),
69  f_minor_ver( a_min_ver ),
70  f_patch_ver( a_patch_ver ),
71  f_version(),
72  f_package(),
73  f_commit(),
74  f_exe_name(),
75  f_hostname(),
76  f_username()
77  {
78  combine( a_maj_ver, a_min_ver, a_patch_ver );
80  }
81 
82  version_semantic::version_semantic( const std::string& a_ver ) :
83  version_ifc(),
84  f_major_ver( 0 ),
85  f_minor_ver( 0 ),
86  f_patch_ver( 0 ),
87  f_version( a_ver ),
88  f_package(),
89  f_commit(),
90  f_exe_name(),
91  f_hostname(),
92  f_username()
93  {
94  parse( a_ver );
96  }
97 
99  version_ifc(),
100  f_major_ver( a_orig.f_major_ver ),
101  f_minor_ver( a_orig.f_minor_ver ),
102  f_patch_ver( a_orig.f_patch_ver ),
103  f_version( a_orig.f_version ),
104  f_package( a_orig.f_package ),
105  f_commit( a_orig.f_commit ),
106  f_exe_name( a_orig.f_exe_name ),
107  f_hostname( a_orig.f_hostname ),
108  f_username( a_orig.f_username )
109  {
110  }
111 
113  {
114  }
115 
117  {
118  this->version_ifc::operator=( a_orig );
119  f_major_ver = a_orig.f_major_ver;
120  f_minor_ver = a_orig.f_minor_ver;
121  f_patch_ver = a_orig.f_patch_ver;
122  f_version = a_orig.f_version;
123  f_package = a_orig.f_package;
124  f_commit = a_orig.f_commit;
125  f_exe_name = a_orig.f_exe_name;
126  f_hostname = a_orig.f_hostname;
127  f_username = a_orig.f_username;
128  return *this;
129  }
130 
132  {
133  if( f_major_ver < a_other.f_major_ver ) return true;
134  if( f_minor_ver < a_other.f_minor_ver ) return true;
135  if( f_patch_ver < a_other.f_patch_ver ) return true;
136  return false;
137  }
138 
140  {
141  return f_major_ver == a_other.f_major_ver &&
142  f_minor_ver == a_other.f_minor_ver &&
143  f_patch_ver == a_other.f_patch_ver;
144  }
145 
146  bool version_semantic::parse( const std::string& a_ver )
147  {
148  if( a_ver == "unknown" )
149  {
150  f_major_ver = 0;
151  f_minor_ver = 0;
152  f_patch_ver = 0;
153  f_version = a_ver;
154  return true;
155  }
156 
157  size_t t_delim_pos_1 = a_ver.find( s_delimeter, 0 );
158  if( t_delim_pos_1 == std::string::npos )
159  {
160  LERROR( slog, "version string <" << a_ver << "> is not in the right format (did not find first delimeter)" );
161  return false;
162  }
163  std::stringstream t_maj_ver_str;
164  t_maj_ver_str << a_ver.substr( 0, t_delim_pos_1 );
165 
166  size_t t_delim_pos_2 = a_ver.find( s_delimeter, t_delim_pos_1 + 1 );
167  if( t_delim_pos_2 == std::string::npos )
168  {
169  LERROR( slog, "version string <" << a_ver << "> is not in the right format (did not find second delimeter)" );
170  return false;
171  }
172  std::stringstream t_min_ver_str;
173  t_min_ver_str << a_ver.substr(t_delim_pos_1 + 1, t_delim_pos_2 );
174 
175  std::stringstream t_patch_ver;
176  t_patch_ver << a_ver.substr( t_delim_pos_2 + 1 );
177 
178  t_maj_ver_str >> f_major_ver;
179  t_min_ver_str >> f_minor_ver;
180  t_patch_ver >> f_patch_ver;
181  f_version = a_ver;
182 
183  return true;
184  }
185 
186  bool version_semantic::combine( unsigned a_maj_ver, unsigned a_min_ver, unsigned a_patch_ver )
187  {
188  std::stringstream t_ver_str;
189  t_ver_str << a_maj_ver << s_delimeter << a_min_ver << s_delimeter << a_patch_ver;
190  f_version = t_ver_str.str();
191  return true;
192  }
193 
195  {
196  const size_t t_bufsize = 1024;
197 
198  // Username
199 #ifdef _WIN32
200  char t_username_buf[ t_bufsize ];
201  DWORD t_bufsize_win = t_bufsize;
202  if( GetUserName( t_username_buf, &t_bufsize_win ) )
203  {
204  f_username = string( t_username_buf );
205  }
206  else
207  {
208 #else
209  //if( getlogin_r( t_username_buf, t_bufsize ) == 0 )
210  passwd* t_passwd = getpwuid( getuid() );
211  if( t_passwd != nullptr )
212  {
213  f_username = string( t_passwd->pw_name );
214  }
215  else
216  {
217  LWARN( slog, "Error reported while getting passwd info: " << strerror( errno ) );
218 #endif
219  LWARN( slog, "Unable to get the username" );
220  }
221 
222  // Hostname
223  char t_hostname_buf[ t_bufsize ];
224 #ifdef _WIN32
225  WSADATA wsaData;
226  WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
227 #endif
228  // gethostname is the same on posix and windows
229  if( gethostname( t_hostname_buf, t_bufsize ) == 0 )
230  {
231  f_hostname = string( t_hostname_buf );
232  }
233  else
234  {
235  LWARN( slog, "Unable to get the hostname" );
236  }
237 #ifdef _WIN32
238  WSACleanup();
239 #endif
240 
241  // name of executable
242  //f_exe_name = t_parser.get_value( t_name_exe, f_exe_name );
243 #ifdef _WIN32
244  TCHAR t_exe_buf[ MAX_PATH ];
245  if( ! GetModuleFileName( NULL, t_exe_buf, MAX_PATH ) )
246 #elif __APPLE__
247  char t_exe_buf[ 2048 ];
248  uint32_t t_exe_bufsize = sizeof( t_exe_buf );
249  if( _NSGetExecutablePath( t_exe_buf, &t_exe_bufsize ) != 0 )
250 #elif __linux
251  const size_t t_exe_bufsize = 2048;
252  char t_exe_buf[ t_exe_bufsize ];
253  ssize_t t_exe_name_len = readlink( "/proc/self/exe", t_exe_buf, t_exe_bufsize );
254  if( t_exe_name_len >= 0 )
255  {
256  t_exe_buf[t_exe_name_len] = '\0';
257  }
258  else
259  //if( readlink( "/proc/self/exe", t_exe_buf, t_exe_bufsize ) < 0 )
260 #endif
261  {
262  LWARN( slog, "Could not retrieve executable file name" );
263 #ifdef __APPLE__
264  LWARN( slog, "Executable name buffer is too small; needs size %u\n" << t_bufsize );
265 #endif
266  }
267  f_exe_name = string( t_exe_buf );
268 
269  return true;
270  }
271 
273  {
274  std::stringstream t_info_stream;
275  path t_exe_path( f_exe_name );
276  t_info_stream << "Executable: " << t_exe_path.filename() << '\n';
277  t_info_stream << "Location: " << t_exe_path.parent_path() << '\n';
278  t_info_stream << "Built with " << f_package << " version " << f_version << '\n';
279  t_info_stream << "Git commit: " << f_commit;
280  std::string t_version_info( t_info_stream.str() );
281  return t_version_info;
282  }
283 
284 } /* namespace scarab */
#define LWARN(...)
Definition: logger.hh:369
fs::path path
Definition: path.hh:25
version_ifc & operator=(const version_ifc &)
Definition: version_base.cc:43
bool combine(unsigned a_maj_ver, unsigned a_min_ver, unsigned a_patch_ver)
LOGGER(mtlog, "authentication")
virtual std::string version_info_string() const
#define LERROR(...)
Definition: logger.hh:370
bool operator<(const version_semantic &a_other)
Less-than operator to compare version information only.
version_semantic & operator=(const version_semantic &a_orig)
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
bool operator==(const version_semantic &a_other)
Equality operator to compare version information only.
virtual ~version_ifc()
Definition: version_base.cc:40
bool parse(const std::string &a_ver)