Flow123d
xio.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  *
26  * @file xio.cc
27  * @ingroup system
28  * @brief I/O functions with filename storing, able to track current line in opened file. All standard
29  * stdio functions working with files (not stdin, stdout, stderr) should be replaced
30  * by their equivalents from XIO library.
31  *
32  * @date 6.4.2010
33  * @author Jiri Jenicek
34  * @todo Better error handling ( perror()? strerror()? )
35  *
36  */
37 
38 
39 
40 #include <string.h>
41 #include <strings.h>
42 #include <stdarg.h>
43 #include <errno.h>
44 #include <limits.h>
45 
46 #include <iostream>
47 #include <algorithm>
48 #include <iterator>
49 
50 #include "xio.h"
51 
52 using namespace std;
53 
54 
55 //! @brief basic definitions
56 /// @{
57 static XFILE xstdin = {"stdin","r",0};
58 static XFILE xstdout = {"stdout","w",0};
59 static XFILE xstderr = {"stderr","w",0};
60 //! @}
61 
62 static XFILE * xio_getfptr( FILE * f );
63 
64 #define XIO_WARN(f) xprintf(Warn, "File pointer '%p' not in xfiles_map. Opened with regular fopen() or already closed?\n", (f) )
65 #define XIO_PRINT_INFO(f) printf( "XIO: In function '%s', %s\n", __func__, xio_getfulldescription( f ) )
66 #define XIO_DEBUG(f) do { if ( Xio::get_instance()->get_verbosity() > 0 ) XIO_PRINT_INFO(f); } while (0)
67 
68 
69 /*******************************************************************
70  * implementation of Xio
71  */
72 
73 Xio * Xio::instance = NULL;
74 
76 : verbosity_(0)
77 {
78  xfiles_map_[stdin] = &xstdin;
79  xfiles_map_[stdout] = &xstdout;
80  xfiles_map_[stderr] = &xstderr;
81 }
82 
84 {
85  ASSERT( instance , "XIO library not initialized yet.\n");
86  return instance;
87 }
88 
89 void Xio::init()
90 {
91  if (instance == NULL) {
92  instance = new Xio();
93  } else {
94  xprintf(Warn, "The XIO library already initialized.\n");
95  }
96 }
97 
98 void Xio::set_verbosity( int verb )
99 {
100  verbosity_ = verb;
101 }
102 
104 {
105  return verbosity_;
106 }
107 
109 {
110  return xfiles_map_;
111 }
112 
113 
114 
115 /*!
116  * @brief Get file name from pointer to FILE structure.
117  * @param[in] f pointer to FILE structure
118  * @return pointer to file name if OK, NULL if file stream is not known
119  */
120 char * xio_getfname( FILE * f )
121 {
122  XFILE * xf;
123  char * rs = NULL;
124 
125  xf = xio_getfptr(f);
126  if ( xf )
127  {
128  rs = xf->filename;
129  }
130  else
131  {
132  XIO_WARN(f);
133  }
134 
135  return rs;
136 }
137 
138 /*!
139  * @brief Get file mode from file stream
140  * @param[in] f pointer to FILE structure
141  * @return pointer to file opening mode if OK, NULL if file stream is not known
142  */
143 char * xio_getfmode( FILE * f )
144 {
145  XFILE * xf;
146  char * rs = NULL;
147 
148  xf = xio_getfptr(f);
149  if ( xf )
150  {
151  rs = xf->mode;
152  }
153  else
154  {
155  XIO_WARN(f);
156  }
157 
158  return rs;
159 }
160 
161 /*!
162  * @brief Get number of lines that were completely read from file since fopen() or rewind()
163  * @param[in] f pointer to FILE structure
164  * @return number of lines read if OK, -1 if file stream is not known
165  */
166 int xio_getlinesread( FILE * f )
167 {
168  XFILE * xf;
169  int lines = -1;
170 
171  xf = xio_getfptr(f);
172  if ( xf )
173  {
174  lines = xf->lineno;
175  }
176  else
177  {
178  XIO_WARN(f);
179  }
180 
181  return lines;
182 }
183 
184 /*!
185  * @brief Get pointer to string with full file description
186  * @param[in] f pointer to FILE structure
187  * @return pointer to string with description, null terminated, no LF
188  */
189 char * xio_getfulldescription( FILE * f )
190 {
191  const char prn_format_long[] = "FILE ptr %p: x->name '%s', x->mode '%s', x->line '%d'";
192  const char prn_format_short[] = "FILE ptr %p: unknown FILE pointer";
193  static char * rs = NULL;
194  static int maxlen = 0;
195  int len;
196  XFILE * xf;
197 
198  if (!rs)
199  {
200  maxlen = LINE_SIZE;
201  rs = (char *)xmalloc( maxlen );
202  }
203 
204  xf = xio_getfptr(f);
205  if ( xf )
206  {
207  len = snprintf( rs, maxlen, prn_format_long, f, xf->filename, xf->mode, xf->lineno );
208  if ( len >= maxlen ) //string overflow?
209  {
210  maxlen = len + 1;
211  rs = (char *)xrealloc( rs, maxlen );
212  snprintf( rs, maxlen, prn_format_long, f, xf->filename, xf->mode, xf->lineno );
213  }
214  }
215  else
216  {
217  len = snprintf( rs, maxlen, prn_format_short, f );
218  if ( len >= maxlen ) //string overflow?
219  {
220  maxlen = len + 1;
221  rs = (char *)xrealloc( rs, maxlen );
222  snprintf( rs, maxlen, prn_format_short, f );
223  }
224  }
225 
226  return rs;
227 }
228 
229 /*!
230  * @brief Internal XIO locator
231  * @param[in] f pointer to FILE structure
232  * @return pointer to XFILE structure if OK, NULL if file stream is not known
233  */
234 static XFILE * xio_getfptr( FILE * f )
235 {
236  XFILE * xf = NULL;
237 
238  if ( Xio::get_instance()->get_xfile_map().find(f) != Xio::get_instance()->get_xfile_map().end() )
239  {
240  xf = Xio::get_instance()->get_xfile_map()[f];
241  }
242 
243  return xf;
244 }
245 
246 FILE *xfopen( const std::string& fname, const char *mode )
247 {
248  const char *fnamec = fname.c_str();
249  return xfopen(fnamec,mode);
250 }
251 
252 /*!
253  * @brief fopen() with error handling and filename store
254  * @param[in] fname filename to open
255  * @param[in] mode opening mode
256  * @return same as ISO C fopen()
257  */
258 FILE *xfopen( const char *fname, const char *mode )
259 {
260  XFILE * xf;
261  FILE *rc;
262 
263  F_ENTRY;
264 
265  ASSERT(!( (fname == NULL) || (mode == NULL) ),"NULL pointer as argument of function xfopen()\n");
266  xprintf(MsgLog,"Opening file: '%s'\n", fname);
267  rc = fopen( fname, mode );
268  INPUT_CHECK( rc != NULL ,"Cannot open file '%s' with permissions %s\n", fname, mode );
269 
270  //store file name and file opening mode
271  xf = (XFILE *)xmalloc(sizeof(XFILE));
272  xf->filename = (char *)xmalloc(strlen(fname)+1);
273  strcpy( xf->filename, fname );
274  xf->mode = (char *)xmalloc(strlen(mode)+1);
275  strcpy(xf->mode, mode);
276  xf->lineno = 0;
277  Xio::get_instance()->get_xfile_map()[rc] = xf;
278 
279  XIO_DEBUG( rc );
280 
281  return(rc);
282 }
283 
284 /*!
285  * @brief Flush file stream
286  * @param[in,out] f pointer to FILE structure
287  * @return same as ISO C fflush()
288  */
289 int xfflush( FILE * f )
290 {
291  XFILE * xf;
292 
293  ASSERT(!(f == NULL),"NULL as input argument\n");
294 
295  XIO_DEBUG( f );
296 
297  xf = xio_getfptr(f);
298  if ( !xf )
299  {
300  XIO_WARN(f);
301  }
302 
303  return fflush ( f );
304 }
305 
306 /*!
307  * @brief FCLOSE WITH ERROR HANDLING
308  * @param[in,out] stream pointer to FILE structure
309  * @return same as ISO C fclose()
310  */
311 int xfclose( FILE *stream )
312 {
313  XFILE * xf;
314  int rc;
315 
316  F_ENTRY;
317 
318  ASSERT(!( stream == NULL ),"NULL pointer as argument of function xfclose()\n");
319 
320  XIO_DEBUG( stream );
321 
322  rc = fclose( stream );
323 
324  INPUT_CHECK(!( rc == EOF ),"Cannot close file %s\n", xio_getfname(stream) );
325 
326  if ( rc != EOF )
327  {
328  xf = xio_getfptr(stream);
329  if ( xf )
330  {
331  Xio::get_instance()->get_xfile_map().erase(stream);
332  xfree( xf->filename );
333  xfree( xf->mode );
334  xfree( xf );
335  }
336  else
337  {
338  XIO_WARN(stream);
339  }
340  }
341 
342  return(rc);
343 }
344 
345 /*!
346  * @brief Reopen stream with different file or mode
347  * @param[in] filename Name of the file to be opened
348  * @param[in] mode File access mode
349  * @param[in,out] stream Pointer to a FILE object that identifies the stream to be reopened
350  * @return Same as ISO C freopen()
351  */
352 FILE * xfreopen( const char * filename, const char * mode, FILE * stream )
353 {
354  XFILE * xf;
355  FILE *rc;
356 
357  F_ENTRY;
358  ASSERT(!( (mode == NULL) || (stream == NULL)),"Wrong arguments\n");
359 
360  rc = freopen( filename, mode, stream );
361 
362  INPUT_CHECK( rc != NULL ,"Cannot reopen file %s with permissions %s\n", filename, mode );
363 
364  //store file name and file opening mode
365  xf = xio_getfptr(rc);
366  if (xf)
367  {
368  //replace filename, if enough space
369  if ( strlen(filename) > strlen(xf->filename) )
370  xf->filename = (char *)xrealloc(xf->filename, strlen(filename)+1 );
371  strcpy(xf->filename, filename);
372 
373  //replace filemode, if enough space
374  if ( strlen(mode) > strlen(xf->mode) )
375  xf->mode = (char *)xrealloc( xf->mode, strlen(mode)+1 );
376  strcpy(xf->mode, mode);
377 
378  xf->lineno = 0;
379  }
380  else
381  {
382  //new file
383  xf = (XFILE *)xmalloc(sizeof(XFILE));
384  xf->filename = (char *)xmalloc(strlen(filename));
385  strcpy(xf->filename, filename);
386  xf->mode = (char *)xmalloc(strlen(mode));
387  strcpy(xf->mode, mode);
388  xf->lineno = 0;
389  Xio::get_instance()->get_xfile_map()[rc] = xf;
390  }
391 
392  XIO_DEBUG( rc );
393 
394  return(rc);
395 }
396 
397 /*!
398  * @brief FPRINTF WITH ERROR HANDLING
399  */
400 int xfprintf( FILE *out, const char *fmt, ... )
401 {
402  va_list argptr;
403  int rc;
404 
405  F_ENTRY;
406 
407  ASSERT(!( (out == NULL) || (fmt == NULL) ),"NULL pointer as argument of function xfprintf()\n");
408  va_start( argptr, fmt );
409  rc = vfprintf( out, fmt, argptr );
410  va_end( argptr );
411  INPUT_CHECK(!( rc == EOF ),"Cannot write to file %s\n", xio_getfname(out) );
412 
413  return rc;
414 }
415 
416 /*!
417  * @brief FSCANF WITH ERROR HANDLING
418  */
419 int xfscanf( FILE *in, const char *fmt, ... )
420 {
421  va_list argptr;
422  int rc;
423 
424  F_ENTRY;
425 
426  ASSERT(!( (in == NULL) || (fmt == NULL) ),"NULL pointer as argument of function xfscanf()\n");
427  va_start( argptr , fmt );
428  rc = vfscanf( in, fmt, argptr );
429  va_end( argptr );
430  INPUT_CHECK(!( (rc == EOF) || (rc == 0) ),"Cannot read from file %s\n", xio_getfname(in) );
431 
432  return(rc);
433 }
434 
435 /*!
436  * @brief getc() with error handling and line count
437  * @param[in,out] f pointer to FILE structure
438  * @return same as ISO C getc()
439  */
440 int xgetc( FILE * f )
441 {
442  int rc;
443 
444  F_ENTRY;
445  ASSERT(!(f == NULL), "NULL file\n");
446 
447  rc = xfgetc( f );
448  XIO_DEBUG( f );
449 
450  return( rc );
451 }
452 
453 /*!
454  * @brief fgetc() with error handling and line count
455  * @param[in,out] f pointer to FILE structure
456  * @return same as ISO C fgetc()
457  */
458 int xfgetc( FILE * f )
459 {
460  int rc;
461  XFILE * xf;
462 
463  F_ENTRY;
464  ASSERT(!(f == NULL), "NULL file\n");
465 
466  rc = fgetc( f );
467 
468  //update line count
469  xf = xio_getfptr( f );
470  if ( xf )
471  {
472  if ( rc == '\n' )
473  xf->lineno++;
474  }
475  else
476  {
477  XIO_WARN( f );
478  }
479 
480  XIO_DEBUG( f );
481 
482  INPUT_CHECK(!( (rc == EOF) && (!feof(f))),"Cannot read from file '%s'\n", xio_getfname( f ) );
483 
484  return(rc);
485 }
486 
487 /*!
488  * @brief ungetc() with error handling and line count
489  * @param[in] c character to push back
490  * @param[in,out] f pointer to FILE structure with INPUT stream
491  * @return same as ISO C ungetc()
492  */
493 int xungetc( int c, FILE * f )
494 {
495  int rc;
496  XFILE * xf;
497 
498  F_ENTRY;
499  ASSERT(!(f == NULL), "NULL file\n");
500 
501  rc = ungetc( c, f );
502 
503  //update line count
504  xf = xio_getfptr( f );
505  if ( xf )
506  {
507  if ( ( rc == '\n' ) && ( xf->lineno > 0 ) )
508  xf->lineno--;
509  }
510  else
511  {
512  XIO_WARN( f );
513  }
514 
515  XIO_DEBUG( f );
516 
517  INPUT_CHECK(!(rc == EOF), "Unable to push back character '%c' to file '%s'.\n", c, xio_getfname(f) );
518  return( rc );
519 }
520 
521 /*!
522  * @brief Changes the name of the file or directory specified by oldname to newname
523  * @param[in] oldname name of the file to be renamed and/or moved
524  * @param[in] newname new name
525  * @return same as ISO C rename()
526  */
527 int xrename ( const char * oldname, const char * newname )
528 {
529  int rc;
530 
531  F_ENTRY;
532  ASSERT(!(( oldname == NULL) || (newname == NULL)), "NULL file name\n");
533 
534  rc = rename( oldname, newname );
535 
536  INPUT_CHECK( rc != 0,"Failed when renaming '%s' to '%s'\n", oldname, newname );
537  return( rc );
538 }
539 
540 /*!
541  * @brief Read block of data from stream, handle errors
542  * @param[out] ptr Pointer to a block of memory with a minimum size of (size*count) bytes.
543  * @param[in] size Size in bytes of each element to be read.
544  * @param[in] count Number of elements, each one with a size of size bytes.
545  * @param[in,out] stream Pointer to a FILE object that specifies an input stream.
546  * @return same as ISO C fread()
547  */
548 size_t xfread( void * ptr, size_t size, size_t count, FILE * stream )
549 {
550  size_t rc;
551 
552  F_ENTRY;
553  ASSERT(!( (ptr == NULL) || ( stream == NULL) ),"Incorrect arguments\n");
554 
555  rc = fread( ptr, size, count, stream );
556 
557  XIO_DEBUG( stream );
558 
559  INPUT_CHECK(!( (rc != count) && (!feof(stream))),"Cannot read from file '%s'\n", xio_getfname(stream) );
560 
561  return(rc);
562 }
563 
564 /*!
565  * @brief Write block of data to stream, handle errors
566  * @param[in] ptr Pointer to a block of memory with a minimum size of (size*count) bytes.
567  * @param[in] size Size in bytes of each element to be written.
568  * @param[in] count Number of elements, each one with a size of size bytes.
569  * @param[in,out] stream Pointer to a FILE object that specifies an output stream.
570  * @return same as ISO C fwrite()
571  */
572 size_t xfwrite( const void * ptr, size_t size, size_t count, FILE * stream )
573 {
574  size_t rc;
575 
576  F_ENTRY;
577  ASSERT(!( (ptr == NULL) || (stream == NULL) ),"Incorrect arguments\n");
578 
579  rc = fwrite( ptr, size, count, stream );
580 
581  XIO_DEBUG( stream );
582 
583  INPUT_CHECK(!( (rc != count) ),"Cannot write to file '%s'\n", xio_getfname(stream) );
584 
585  return(rc);
586 }
587 
588 /*!
589  * @brief FGETS WITH ERROR HANDLING and line count
590  * @param[out] s Pointer to an array of chars where the string read is stored
591  * @param[in] n Maximum number of characters to be read (including the final null-character)
592  * @param[in,out] in Pointer to a FILE
593  * @return same as ISO C fgets()
594  */
595 char *xfgets( char *s, int n, FILE *in )
596 {
597  XFILE * xf;
598  char *rc = NULL;
599 
600  F_ENTRY;
601 
602  ASSERT(!( (s == NULL) || (in == NULL) ),"Incorrect arguments of function xfgets()\n");
603  rc = fgets( s, n, in );
604 
605  //update line count
606  xf = xio_getfptr(in);
607  if ( xf )
608  {
609  //check if complete line is read
610  if ( rc )
611  {
612  char c;
613  c = s[strlen(s)-1];
614  if ( c == '\n' )
615  {
616  xf->lineno++;
617  }
618  }
619  }
620  else
621  {
622  XIO_WARN(in);
623  }
624 
625  XIO_DEBUG( in );
626 
627  INPUT_CHECK(!( (rc == NULL) && (!feof(in))),"Cannot read from file '%s'\n", xio_getfname(in) );
628 
629  return(rc);
630 }
631 
632 /*!
633  * @brief Rewind file, handle line count
634  * @param[in,out] f pointer to FILE structure
635  */
636 void xrewind( FILE * f )
637 {
638  XFILE * xf;
639 
640  ASSERT(!(f == NULL),"NULL file argument in xrewind()\n");
641 
642  xf = xio_getfptr(f);
643  if ( xf )
644  {
645  xf->lineno = 0;
646  }
647  else
648  {
649  XIO_WARN(f);
650  }
651 
652  rewind( f );
653 
654  XIO_DEBUG( f );
655 }
656 
657 /*!
658  * @brief Check END OF FILE
659  * @param[in] f pointer to FILE structure
660  * @return same as ISO C feof()
661  */
662 int xfeof ( FILE * f )
663 {
664  XFILE * xf;
665  int rc;
666 
667  xf = xio_getfptr(f);
668  if ( !xf )
669  {
670  XIO_WARN(f);
671  }
672 
673  rc = feof ( f );
674 
675  XIO_DEBUG( f );
676 
677  return rc;
678 }