Flow123d  release_1.8.2-1603-g0109a2b
system.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file system.cc
15  * @ingroup system
16  * @brief Various system-wide functions
17  */
18 
19 #include <cstring>
20 #include <cstdarg>
21 #include <ctime>
22 #include <cstdlib>
23 #include <sys/stat.h>
24 #include <cerrno>
25 #include <sstream>
26 
27 #include <fstream>
28 #include <string>
29 #include "mpi.h"
30 
31 #include "system/system.hh"
32 #include "system/xio.h"
33 #include "system/file_path.hh"
34 #include "system/sys_profiler.hh"
35 
36 #include <boost/algorithm/string/predicate.hpp>
37 #include <boost/algorithm/string/trim.hpp>
38 #include <boost/format.hpp>
39 
40 
41 
43 
44 
45 /// @brief INTERNAL DEFINITIONS FOR XPRINTF
46 /// @{
47 
48 struct MsgFmt {
49  int num; ///< format number
50  bool log; ///< log the message - YES/NO
51  bool mpi; ///< treat as global message (invoke MPI_Barrier() when printing)
52  int screen; ///< print to stdout,stderr,NULL
53  bool stop; ///< terminate the program
54  const char * head; ///< message formating string
55 };
56 
57 #define SCR_NONE 0
58 #define SCR_STDOUT 1
59 #define SCR_STDERR 2
60 
61 /// configuration table for individual message types defined in system.h
62 /// Msg type Log mpi screen Stop message header
63 #define NUM_OF_FMTS 8
64 static struct MsgFmt msg_fmt[] = {
65  {Msg, true, false, SCR_STDOUT, false, NULL},
66  {MsgDbg, true, false, SCR_STDOUT, false, " DBG (%s, %s(), %d):"},
67  {MsgLog, true, false, SCR_NONE, false, NULL},
68  {MsgVerb, false, false, SCR_STDOUT, false, NULL},
69  {Warn, true, false, SCR_STDERR, false, "\nWarning (%s, %s(), %d):\n"},
70  {UsrErr, true, false, SCR_NONE, true, "\nUser Error (%s, %s(), %d):\n"},
71  {Err, true, false, SCR_NONE, true, "\nError (%s, %s(), %d):\n"},
72  {PrgErr, true, false, SCR_NONE, true, "\nInternal Error (%s, %s(), %d):\n"}
73 };
74 
75 /// @}
76 
77 /*!
78  * @brief Multi-purpose printing routine: messages, warnings, errors
79  * @param[in] xprintf_file current file
80  * @param[in] xprintf_func current function
81  * @param[in] xprintf_line current line number
82  * @param[in] type message type
83  * @param[in] fmt message format
84  * @return Same as printf, what internal printing routine returns.
85  */
86 int _xprintf(const char * const xprintf_file, const char * const xprintf_func, const int xprintf_line, MessageType type, const char * const fmt, ... )
87 {
88  struct MsgFmt mf;
89  int rc;
90  FILE *screen=NULL;
91 
92  static int mpi_msg_id = 0;
93  int ierr;
94 
95  if ((type == MsgVerb) && (sys_info.verbosity <= 0))
96  return 0;
97 
98  if ((type < 0) || (type >= NUM_OF_FMTS))
99  type = Msg;
100  mf = msg_fmt[type];
101 
102  // determine output stream
103  switch (mf.screen) {
104  case SCR_STDOUT : screen=stdout; break;
105  case SCR_STDERR : screen=stderr; break;
106  case SCR_NONE : screen=NULL; break;
107  default: screen=NULL;
108  }
109 
110 
111 #ifdef MPI_PRINTALL
112  //print msg header with mpi_id to distinguish the message origin
113  if (screen)
114  fprintf(screen,"[mpi_id=%d] ", sys_info.my_proc );
115  if (mf.log && sys_info.log)
116  fprintf(sys_info.log,"[mpi_id=%d] ", sys_info.my_proc );
117 #else
118  //if not PRINTALL, allow console output only for MPI master, no need to print mpi_id
119  if ( (screen) && ( sys_info.my_proc != 0 ) )
120  screen = NULL;
121 #endif
122 
123  {
124  va_list argptr;
125  if (mf.stop) {
126  char format_message[1024];
127  va_start( argptr, fmt );
128  vsprintf(format_message, fmt, argptr);
129  va_end( argptr );
130 
131  // explicit flush of all streams
132  fflush(NULL);
133  BOOST_THROW_EXCEPTION( ExcXprintfMsg()
134  << EI_XprintfHeader( boost::str(boost::format(mf.head) % xprintf_file % xprintf_func % xprintf_line) )
135  << EI_XprintfMessage( format_message ) );
136  }
137  }
138 
139  //generate barrier and unique ID for MPI messages
140  if (mf.mpi) {
141  ierr = MPI_Barrier(sys_info.comm);
142  if (ierr != MPI_SUCCESS ) {
143  printf("MPI_Barrier() error in xprintf()\n"); //can not call xprintf() when xprintf() is failing
144  exit( EXIT_FAILURE );
145  }
146 
147  // print global msg_id
148  if (screen)
149  fprintf(screen,"[msg_id=%d] ", mpi_msg_id );
150  if (mf.log && sys_info.log)
151  fprintf(sys_info.log,"[msg_id=%d] ", mpi_msg_id );
152  mpi_msg_id++;
153  }
154 #ifndef FLOW123D_DEBUG_MESSAGES
155  if (type == Warn) mf.head="\nWarning: ";
156 #endif
157  // print head
158  if (mf.head) {
159  if (screen) fprintf(screen,mf.head,xprintf_file,xprintf_func,xprintf_line);
160  if (mf.log && sys_info.log)
161  fprintf(sys_info.log,mf.head,xprintf_file,xprintf_func,xprintf_line);
162  }
163  // print message
164  {
165  va_list argptr;
166 
167  if (mf.log && sys_info.log)
168  {
169  va_start( argptr, fmt );
170  rc=vfprintf(sys_info.log,fmt,argptr); //rc=char written, <0 if err
171  va_end( argptr );
172  // flush every message (maybe there is a problem in cygwin without that)
173  fflush(sys_info.log);
174  }
175 
176  if (screen)
177  {
178  va_start( argptr, fmt );
179  rc=vfprintf(screen,fmt,argptr);
180  va_end( argptr );
181  // flush every message (maybe there is a problem in cygwin without that)
182  fflush(screen);
183  }
184  }
185 
186  return rc;
187 }
188 
189 
190 /*!
191  * @brief Memory allocation with checking.
192  *
193  * Allocates memory block with checking of correct size and successful allocation.
194  *
195  * @param[in] size New size for the memory block, in bytes.
196  * @return same as ISO C realloc()
197  */
198 void *xmalloc( size_t size )
199 {
200  void *rc;
201 
202 
203  if (size == 0 ) size++;
204  rc = malloc( size );
205  if ( rc == NULL ) xprintf(Err ,"Not enough memory for allocating %u bytes\n", size );
206 
207  return(rc);
208 }
209 
210 /*!
211  * @brief Reallocation of memory block with checking.
212  *
213  * Reallocates memory block with checking of successful reallocation.
214  * The size of the memory block pointed to by the ptr parameter is changed to the size bytes,
215  * expanding or reducing the amount of memory available in the block.
216  *
217  * The function may move the memory block to a new location, in which case the new location
218  * is returned. The content of the memory block is preserved up to the lesser of
219  * the new and old sizes, even if the block is moved. If the new size is larger, the value
220  * of the newly allocated portion is indeterminate.
221  *
222  * In case that ptr is NULL, the function behaves exactly as malloc,
223  * assigning a new block of size bytes and returning a pointer to the beginning of it.
224  *
225  * In case that the size is 0, the memory previously allocated in ptr is deallocated
226  * as if a call to free was made, and a NULL pointer is returned.
227  *
228  * @param[in] ptr Pointer to a memory block previously allocated
229  * @param[in] size New size for the memory block, in bytes.
230  * @return same as ISO C realloc()
231  */
232 void * xrealloc( void * ptr, size_t size )
233 {
234  void * rc;
235 
236  rc = realloc( ptr, size );
237  if ( rc == NULL ) xprintf(Err ,"Not enough memory for allocating %u bytes\n", size );
238 
239  return(rc);
240 }
241 
242 /*
243 void *operator new (std::size_t size, const my_new_t &) throw() {
244  return xmalloc(size);
245 }
246 
247 void *operator new[] (std::size_t size, const my_new_t &) throw() {
248  return xmalloc(size);
249 }
250 
251 void operator delete( void *p, const my_new_t &) throw ()
252 {
253  xfree(p);
254 }
255 
256 void operator delete[]( void *p, const my_new_t &) throw ()
257 {
258  xfree(p);
259 }
260 */
261 
262 
263 
264 
265 /*!
266  * @brief SYSTEM with err handling
267  */
268 int xsystem( const char *cmd )
269 {
270  int rc;
271 
272  rc = system( cmd );
273  INPUT_CHECK(!( rc != 0 ),"Error executing external command: %s\n", cmd );
274  return(rc);
275 }
276 
277 /*!
278  * @brief MAKE BRAND NEW COPY OF STRING
279  */
280 char *xstrcpy( const char *src )
281 {
282  char *rc;
283  size_t length;
284 
285  OLD_ASSERT(!( src == NULL ),"NULL pointer as argument of function xstrcpy()\n");
286  length = strlen( src ) + 1;
287  rc = (char*) xmalloc(length * sizeof(char));
288  strcpy( rc, src );
289  return(rc);
290 }
291 
292 /*!
293  * @brief STRTOK WITH ERROR HANDLING and whitespace delimiters
294  * @param[in] s strtok string pointer
295  * @param[in] position requested position of the token
296  * @return strtok return
297  */
298 char *xstrtok(char *s, int position)
299 {
300  char *rc;
301  const char * const whitespace_delim=" \t\r\n";
302 
303  rc = xstrtok( s, whitespace_delim, position);
304  return(rc);
305 }
306 
307 /*!
308  * @brief STRTOK WITH ERROR HANDLING and user specified delimiters
309  * @param[in] s1 strtok string pointer
310  * @param[in] delim delimiters
311  * @param[in] position requested position of the token
312  * @return strtok return
313  *
314  * Function behaves like original strtok
315  */
316 char *xstrtok( char *s1, const char *delim, int position )
317 {
318  char *rc;
319  static char * full_string = NULL;
320  static int token_count;
321 
322  OLD_ASSERT(!( delim == NULL ),"NULL pointer as delimiter in xstrtok()\n");
323 
324  if ( s1 )
325  {
326  if ( !full_string )
327  {
328  full_string = (char *)xmalloc( LINE_SIZE );
329  full_string[0] = 0x0;
330  }
331 
332  strncpy( full_string, s1, LINE_SIZE );
333  token_count = 0;
334  }
335 
336  INPUT_CHECK( token_count == position || position < 0, "Requested position %d dosn't match token position %d", position, token_count);
337  rc = strtok( s1, delim );
338  token_count++;
339 
340  INPUT_CHECK(!( rc == NULL ),"Missing token no. %d: original string '%s' with delimiters '%s'\n", token_count, full_string, delim );
341 
342  return(rc);
343 }
344 
345 /*!
346  * @brief Delete trailing whitespace characters (space,tab,CR,NL).
347  * @param[in,out] s string to change
348  * @return number of deleted characters
349  */
350 int xchomp( char * s )
351 {
352  int no_erased = 0;
353  char * p;
354 
355  OLD_ASSERT( s, "Can not chomp NULL string.");
356 
357  if ( *s ) //string not empty
358  {
359  p = s;
360  while (*p)
361  p++; //find end of string
362  p--; //set p to the last character
363  while ((p >= s) && ((*p == ' ') || (*p == '\t') || (*p == '\r') || (*p == '\n')))
364  {
365  *p = 0x0;
366  no_erased++;
367  p--;
368  }
369  }
370  return(no_erased);
371 }
372 
373 
374 /*!
375  * @brief MKDIR WITH ERROR HANDLING
376  */
377 int xmkdir( const char *s )
378 {
379  int rc;
380 
381  OLD_ASSERT(!( s == NULL ),"NULL pointer as argument of function xmkdir()\n");
382  rc = mkdir(s, S_IRWXU); // create dir with rwx perm. for user
383  if (errno == EEXIST)
384  rc = 0;
385  INPUT_CHECK(!( rc != 0 ),"Cannot make directory %s\n", s );
386 
387  return(rc);
388 }
389 
390 /*!
391  * @brief RMDIR with err handling
392  */
393 int xrmdir( const char *s )
394 {
395  int rc;
396 
397  OLD_ASSERT(!( s == NULL ),"NULL pointer as argument of function xrmdir()\n");
398  rc = rmdir( s );
399  INPUT_CHECK(!( rc != 0 ),"Cannot delete directory %s\n", s );
400  return(rc);
401 }
402 
403 /*!
404  * @brief CHDIR WITH ERROR HANDLING
405  */
406 int xchdir( const char *s )
407 {
408  int rc;
409 
410  OLD_ASSERT(!( s == NULL ),"NULL pointer as argument of function xchdir()\n");
411  rc = chdir( s );
412  INPUT_CHECK(!( rc != 0 ),"Cannot change directory to %s\n", s );
413  return(rc);
414 }
415 
416 /*!
417  * @brief DELETE a FILE with error handling
418  */
419 int xremove( const char *fname )
420 {
421  int rc;
422 
423  OLD_ASSERT(!( fname == NULL ),"NULL pointer as argument of function xremove()\n");
424  if( access( fname , F_OK ) == 0 )
425  {
426  rc = remove( fname );
427  INPUT_CHECK(!( rc != 0 ),"Cannot remove file %s\n", fname );
428  }
429  else
430  xprintf( Warn, "File '%s' does not exist, can not remove. Ignoring.\n", fname );
431 
432  return(rc);
433 }
434 
435 /*!
436  * @brief GET CURRENT WORKING DIRECTORY with error handling
437  */
438 char *xgetcwd( void )
439 {
440  char tmp[PATH_MAX];
441  char * rc;
442 
443  rc = getcwd( tmp, PATH_MAX );
444  OLD_ASSERT( rc,"Cannot get name of current working directory\n");
445 
446  return(xstrcpy( tmp ));
447 }
448 
bool log
log the message - YES/NO
Definition: system.cc:50
#define MPI_SUCCESS
Definition: mpi.c:17
int my_proc
Definition: system.hh:73
Definition: system.hh:59
FILE * log
Definition: system.hh:70
int num
format number
Definition: system.cc:49
int xremove(const char *fname)
DELETE a FILE with error handling.
Definition: system.cc:419
int verbosity
Definition: system.hh:67
#define INPUT_CHECK(i,...)
Debugging macros.
Definition: global_defs.h:51
char * xstrcpy(const char *src)
MAKE BRAND NEW COPY OF STRING.
Definition: system.cc:280
I/O functions with filename storing, able to track current line in opened file. All standard stdio fu...
Definition: system.hh:59
void * xrealloc(void *ptr, size_t size)
Reallocation of memory block with checking.
Definition: system.cc:232
System structure for various global variables.
Definition: system.hh:66
#define OLD_ASSERT(...)
Definition: global_defs.h:128
int xchomp(char *s)
Delete trailing whitespace characters (space,tab,CR,NL).
Definition: system.cc:350
int xrmdir(const char *s)
RMDIR with err handling.
Definition: system.cc:393
Definition: system.hh:59
#define SCR_STDOUT
Definition: system.cc:58
bool stop
terminate the program
Definition: system.cc:53
#define SCR_NONE
Definition: system.cc:57
int xmkdir(const char *s)
MKDIR WITH ERROR HANDLING.
Definition: system.cc:377
int _xprintf(const char *const xprintf_file, const char *const xprintf_func, const int xprintf_line, MessageType type, const char *const fmt,...)
Multi-purpose printing routine: messages, warnings, errors.
Definition: system.cc:86
#define xprintf(...)
Definition: system.hh:87
#define LINE_SIZE
Definition: xio.h:37
int screen
print to stdout,stderr,NULL
Definition: system.cc:52
Definition: system.hh:59
void * xmalloc(size_t size)
Memory allocation with checking.
Definition: system.cc:198
INTERNAL DEFINITIONS FOR XPRINTF.
Definition: system.cc:48
Definition: system.hh:59
MessageType
Identifiers for various output messages.
Definition: system.hh:58
int xchdir(const char *s)
CHDIR WITH ERROR HANDLING.
Definition: system.cc:406
Definition: system.hh:59
static struct MsgFmt msg_fmt[]
Definition: system.cc:64
char * xstrtok(char *s, int position)
STRTOK WITH ERROR HANDLING and whitespace delimiters.
Definition: system.cc:298
SystemInfo sys_info
Definition: system.cc:42
#define NUM_OF_FMTS
Definition: system.cc:63
Definition: system.hh:59
const char * head
message formating string
Definition: system.cc:54
char * xgetcwd(void)
GET CURRENT WORKING DIRECTORY with error handling.
Definition: system.cc:438
#define MPI_Barrier(comm)
Definition: mpi.h:531
MPI_Comm comm
Definition: system.hh:75
int xsystem(const char *cmd)
SYSTEM with err handling.
Definition: system.cc:268
#define SCR_STDERR
Definition: system.cc:59
bool mpi
treat as global message (invoke MPI_Barrier() when printing)
Definition: system.cc:51