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  F_STACK_SHOW( stderr );
154  BOOST_THROW_EXCEPTION( ExcXprintfMsg()
155  << EI_XprintfHeader( boost::str(boost::format(mf.head) % xprintf_file % xprintf_func % xprintf_line) )
156  << EI_XprintfMessage( format_message ) );
157  }
158  }
159 
160  //generate barrier and unique ID for MPI messages
161  if (mf.mpi) {
162  ierr = MPI_Barrier(sys_info.comm);
163  if (ierr != MPI_SUCCESS ) {
164  printf("MPI_Barrier() error in xprintf()\n"); //can not call xprintf() when xprintf() is failing
165  exit( EXIT_FAILURE );
166  }
167 
168  // print global msg_id
169  if (screen)
170  fprintf(screen,"[msg_id=%d] ", mpi_msg_id );
171  if (mf.log && sys_info.log)
172  fprintf(sys_info.log,"[msg_id=%d] ", mpi_msg_id );
173  mpi_msg_id++;
174  }
175 #ifndef DEBUG_MESSAGES
176  if (type == Warn) mf.head="\nWarning: ";
177 #endif
178  // print head
179  if (mf.head) {
180  if (screen) fprintf(screen,mf.head,xprintf_file,xprintf_func,xprintf_line);
181  if (mf.log && sys_info.log)
182  fprintf(sys_info.log,mf.head,xprintf_file,xprintf_func,xprintf_line);
183  }
184  // print message
185  {
186  va_list argptr;
187 
188  if (mf.log && sys_info.log)
189  {
190  va_start( argptr, fmt );
191  rc=vfprintf(sys_info.log,fmt,argptr); //rc=char written, <0 if err
192  va_end( argptr );
193  // flush every message (maybe there is a problem in cygwin without that)
194  fflush(sys_info.log);
195  }
196 
197  if (screen)
198  {
199  va_start( argptr, fmt );
200  rc=vfprintf(screen,fmt,argptr);
201  va_end( argptr );
202  // flush every message (maybe there is a problem in cygwin without that)
203  fflush(screen);
204  }
205  }
206 
207  return rc;
208 }
209 
210 
211 /*!
212  * @brief Memory allocation with checking.
213  *
214  * Allocates memory block with checking of correct size and successful allocation.
215  *
216  * @param[in] size New size for the memory block, in bytes.
217  * @return same as ISO C realloc()
218  */
219 void *xmalloc( size_t size )
220 {
221  void *rc;
222 
223 
224  if (size == 0 ) size++;
225  //ASSERT( size != 0 ,"Bad requested size (%u bytes) for memory allocation\n", size );
226  rc = malloc( size );
227  if ( rc == NULL ) xprintf(Err ,"Not enough memory for allocating %u bytes\n", size );
228 
229  return(rc);
230 }
231 
232 /*!
233  * @brief Reallocation of memory block with checking.
234  *
235  * Reallocates memory block with checking of successful reallocation.
236  * The size of the memory block pointed to by the ptr parameter is changed to the size bytes,
237  * expanding or reducing the amount of memory available in the block.
238  *
239  * The function may move the memory block to a new location, in which case the new location
240  * is returned. The content of the memory block is preserved up to the lesser of
241  * the new and old sizes, even if the block is moved. If the new size is larger, the value
242  * of the newly allocated portion is indeterminate.
243  *
244  * In case that ptr is NULL, the function behaves exactly as malloc,
245  * assigning a new block of size bytes and returning a pointer to the beginning of it.
246  *
247  * In case that the size is 0, the memory previously allocated in ptr is deallocated
248  * as if a call to free was made, and a NULL pointer is returned.
249  *
250  * @param[in] ptr Pointer to a memory block previously allocated
251  * @param[in] size New size for the memory block, in bytes.
252  * @return same as ISO C realloc()
253  */
254 void * xrealloc( void * ptr, size_t size )
255 {
256  void * rc;
257 
258  F_ENTRY;
259 
260  rc = realloc( ptr, size );
261  if ( rc == NULL ) xprintf(Err ,"Not enough memory for allocating %u bytes\n", size );
262 
263  return(rc);
264 }
265 
266 /*
267 void *operator new (std::size_t size, const my_new_t &) throw() {
268  return xmalloc(size);
269 }
270 
271 void *operator new[] (std::size_t size, const my_new_t &) throw() {
272  return xmalloc(size);
273 }
274 
275 void operator delete( void *p, const my_new_t &) throw ()
276 {
277  xfree(p);
278 }
279 
280 void operator delete[]( void *p, const my_new_t &) throw ()
281 {
282  xfree(p);
283 }
284 */
285 
286 void *operator new (std::size_t size) OPERATOR_NEW_THROW_EXCEPTION {
287  return xmalloc(size);
288 }
289 
290 void *operator new[] (std::size_t size) OPERATOR_NEW_THROW_EXCEPTION {
291  return xmalloc(size);
292 }
293 
294 void *operator new[] (std::size_t size, const std::nothrow_t& ) throw() {
295  return xmalloc(size);
296 }
297 
298 void operator delete( void *p) throw()
299 {
300  xfree(p);
301 }
302 
303 void operator delete[]( void *p) throw()
304 {
305  xfree(p);
306 }
307 
308 
309 
310 /*!
311  * @brief SYSTEM with err handling
312  */
313 int xsystem( const char *cmd )
314 {
315  int rc;
316 
317  F_ENTRY;
318 
319  rc = system( cmd );
320  INPUT_CHECK(!( rc != 0 ),"Error executing external command: %s\n", cmd );
321  return(rc);
322 }
323 
324 /*!
325  * @brief MAKE BRAND NEW COPY OF STRING
326  */
327 char *xstrcpy( const char *src )
328 {
329  char *rc;
330  size_t length;
331 
332  F_ENTRY;
333 
334  ASSERT(!( src == NULL ),"NULL pointer as argument of function xstrcpy()\n");
335  length = strlen( src ) + 1;
336  rc = (char*) xmalloc(length * sizeof(char));
337  strcpy( rc, src );
338  return(rc);
339 }
340 
341 /*!
342  * @brief STRTOK WITH ERROR HANDLING and whitespace delimiters
343  * @param[in] s strtok string pointer
344  * @param[in] position requested position of the token
345  * @return strtok return
346  */
347 char *xstrtok(char *s, int position)
348 {
349  char *rc;
350  const char * const whitespace_delim=" \t\r\n";
351 
352  F_ENTRY;
353 
354  rc = xstrtok( s, whitespace_delim, position);
355  return(rc);
356 }
357 
358 /*!
359  * @brief STRTOK WITH ERROR HANDLING and user specified delimiters
360  * @param[in] s1 strtok string pointer
361  * @param[in] delim delimiters
362  * @param[in] position requested position of the token
363  * @return strtok return
364  *
365  * Function behaves like original strtok
366  */
367 char *xstrtok( char *s1, const char *delim, int position )
368 {
369  char *rc;
370  static char * full_string = NULL;
371  static int token_count;
372 
373  F_ENTRY;
374 
375  ASSERT(!( delim == NULL ),"NULL pointer as delimiter in xstrtok()\n");
376 
377  if ( s1 )
378  {
379  if ( !full_string )
380  {
381  full_string = (char *)xmalloc( LINE_SIZE );
382  full_string[0] = 0x0;
383  }
384 
385  strncpy( full_string, s1, LINE_SIZE );
386  token_count = 0;
387  }
388 
389  INPUT_CHECK( token_count == position || position < 0, "Requested position %d dosn't match token position %d", position, token_count);
390  rc = strtok( s1, delim );
391  token_count++;
392 
393  INPUT_CHECK(!( rc == NULL ),"Missing token no. %d: original string '%s' with delimiters '%s'\n", token_count, full_string, delim );
394 
395  return(rc);
396 }
397 
398 /*!
399  * @brief Delete trailing whitespace characters (space,tab,CR,NL).
400  * @param[in,out] s string to change
401  * @return number of deleted characters
402  */
403 int xchomp( char * s )
404 {
405  int no_erased = 0;
406  char * p;
407 
408  F_ENTRY;
409 
410  ASSERT( s, "Can not chomp NULL string.");
411 
412  if ( *s ) //string not empty
413  {
414  p = s;
415  while (*p)
416  p++; //find end of string
417  p--; //set p to the last character
418  while ((p >= s) && ((*p == ' ') || (*p == '\t') || (*p == '\r') || (*p == '\n')))
419  {
420  *p = 0x0;
421  no_erased++;
422  p--;
423  }
424  }
425  return(no_erased);
426 }
427 
428 
429 /*!
430  * @brief MKDIR WITH ERROR HANDLING
431  */
432 int xmkdir( const char *s )
433 {
434  int rc;
435 
436  F_ENTRY;
437 
438  ASSERT(!( s == NULL ),"NULL pointer as argument of function xmkdir()\n");
439  rc = mkdir(s, S_IRWXU); // create dir with rwx perm. for user
440  if (errno == EEXIST)
441  rc = 0;
442  INPUT_CHECK(!( rc != 0 ),"Cannot make directory %s\n", s );
443 
444  return(rc);
445 }
446 
447 /*!
448  * @brief RMDIR with err handling
449  */
450 int xrmdir( const char *s )
451 {
452  int rc;
453 
454  F_ENTRY;
455 
456  ASSERT(!( s == NULL ),"NULL pointer as argument of function xrmdir()\n");
457  rc = rmdir( s );
458  INPUT_CHECK(!( rc != 0 ),"Cannot delete directory %s\n", s );
459  return(rc);
460 }
461 
462 /*!
463  * @brief CHDIR WITH ERROR HANDLING
464  */
465 int xchdir( const char *s )
466 {
467  int rc;
468 
469  F_ENTRY;
470 
471  ASSERT(!( s == NULL ),"NULL pointer as argument of function xchdir()\n");
472  rc = chdir( s );
473  INPUT_CHECK(!( rc != 0 ),"Cannot change directory to %s\n", s );
474  return(rc);
475 }
476 
477 /*!
478  * @brief DELETE a FILE with error handling
479  */
480 int xremove( const char *fname )
481 {
482  int rc;
483 
484  F_ENTRY;
485 
486  ASSERT(!( fname == NULL ),"NULL pointer as argument of function xremove()\n");
487  if( access( fname , F_OK ) == 0 )
488  {
489  rc = remove( fname );
490  INPUT_CHECK(!( rc != 0 ),"Cannot remove file %s\n", fname );
491  }
492  else
493  xprintf( Warn, "File '%s' does not exist, can not remove. Ignoring.\n", fname );
494 
495  return(rc);
496 }
497 
498 /*!
499  * @brief GET CURRENT WORKING DIRECTORY with error handling
500  */
501 char *xgetcwd( void )
502 {
503  char tmp[PATH_MAX];
504  char * rc;
505 
506  F_ENTRY;
507 
508  rc = getcwd( tmp, PATH_MAX );
509  ASSERT( rc,"Cannot get name of current working directory\n");
510 
511  return(xstrcpy( tmp ));
512 }
513 
514 
515 
516 /*!
517  * @brief Skip to the first line match @p pattern up to surrounding spaces and case.
518  * @param[in,out] in Input stream to search.
519  * @param[in] pattern String to look for.
520  * @return true - if we have found the section, false otherwise
521  */
522 bool skip_to( istream &in, const string &pattern )
523 {
524  F_ENTRY;
525  if (! in.good()) xprintf(PrgErr, "Input stream is not ready for i/o operations. Perhaps missing check about correct open.\n");
526 
527  for(std::string line; ! in.eof() ; std::getline(in, line) ) {
528  boost::trim(line);
529  if ( boost::iequals( line, pattern ) ) return true;
530  }
531 
532  return false;
533 }
534 
535