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