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