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