source: libcfa/src/fstream.cfa@ 8eb85de

stuck-waitfor-destruct
Last change on this file since 8eb85de was 39eb23b0, checked in by Peter A. Buhr <pabuhr@…>, 4 weeks ago

for opening a file, change to default initialization of mode parameter from overloaded functions; fix fstream initialization bug by calling default constructor in other constructors

  • Property mode set to 100644
File size: 13.9 KB
RevLine 
[86bd7c1f]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[356189a]7// fstream.c --
[86bd7c1f]8//
[90c3b1c]9// Author : Peter A. Buhr
[86bd7c1f]10// Created On : Wed May 27 17:56:53 2015
[5d125e4]11// Last Modified By : Peter A. Buhr
[39eb23b0]12// Last Modified On : Wed Jan 14 21:12:05 2026
13// Update Count : 596
[86bd7c1f]14//
15
[f451177]16#include "fstream.hfa" // also includes iostream.hfa
[51b73452]17
[90c3b1c]18#include <stdio.h> // vfprintf, vfscanf
19#include <stdlib.h> // exit
20#include <stdarg.h> // varargs
[b431515]21#include <string.h> // strncpy, strerror
[91c389a]22#include <assert.h>
[8a25be9]23#include <errno.h> // errno
[51b73452]24
[cce4648]25#pragma GCC visibility push(default)
26
[7baff35]27
[8d321f9]28// *********************************** ofstream ***********************************
[65240bb]29
30
[53ba273]31#define IO_MSG "I/O error: "
[6ba0659]32
[7ce2483]33// private
34void ?{}( ofstream & os, void * file ) with( os ) {
[3bf3b6b]35 file$ = file;
36 sepDefault$ = true;
37 sepOnOff$ = false;
38 nlOnOff$ = true;
39 prt$ = false;
40 sawNL$ = false;
[6c5d92f]41 sepSetCur$( os, sepGet( os ) );
[5cb2b8c]42 sepSet( os, " " );
43 sepSetTuple( os, ", " );
[65240bb]44} // ?{}
[0583064b]45
[f5d9c37]46inline bool getNL$( ofstream & os ) { return os.sawNL$; }
[d0cfcbe1]47inline bool setNL$( ofstream & os, bool state ) { bool temp = os.sawNL$; os.sawNL$ = state; return temp; }
[f5d9c37]48inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
[d0cfcbe1]49inline bool setANL$( ofstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
[f5d9c37]50
[7ce2483]51inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
52inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
53inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
54inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
55inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
[f5d9c37]56
[7ce2483]57inline bool getPrt$( ofstream & os ) { return os.prt$; }
[d0cfcbe1]58inline bool setPrt$( ofstream & os, bool state ) { bool temp = os.prt$; os.prt$ = state; return temp; }
[7ce2483]59
[c52f033]60inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); }
[7ce2483]61inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
[829c907]62
[9ebd778]63// public
[6c5d92f]64void ?{}( ofstream & os ) { os.file$ = 0p; }
[39eb23b0]65void ?{}( ofstream & os, const char name[], const char mode[] ) { os{}; open( os, name, mode ); }
[7ce2483]66void ^?{}( ofstream & os ) { close( os ); }
[4cae032]67
[f5d9c37]68void nlOn( ofstream & os ) { os.nlOnOff$ = true; }
69void nlOff( ofstream & os ) { os.nlOnOff$ = false; }
[09687aa]70
[f5d9c37]71void sep( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
72void nosep( ofstream & os ) { os.sepOnOff$ = false; }
[6152c81]73
[f5d9c37]74bool sepOn( ofstream & os ) {
[6c5d92f]75 bool temp = os.sepDefault$;
76 os.sepDefault$ = true;
77 if ( os.sepOnOff$ ) sepReset$( os ); // start of line ?
[53ba273]78 return temp;
[f5d9c37]79} // sepOn
[90c3b1c]80
[f5d9c37]81bool sepOff( ofstream & os ) {
82 bool temp = os.sepDefault$;
83 os.sepDefault$ = false;
84 sepReset$( os );
85 return temp;
86} // sepOff
[200fcb3]87
[6c5d92f]88const char * sepGet( ofstream & os ) { return os.separator$; }
[e3fea42]89void sepSet( ofstream & os, const char s[] ) {
[9ebd778]90 assert( s );
[b431515]91 strncpy( os.separator$, s, ofstream_sepSize - 1 );
92 os.separator$[ofstream_sepSize - 1] = '\0';
[9ebd778]93} // sepSet
94
[6c5d92f]95const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; }
[e3fea42]96void sepSetTuple( ofstream & os, const char s[] ) {
[9ebd778]97 assert( s );
[b431515]98 strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 );
99 os.tupleSeparator$[ofstream_sepSize - 1] = '\0';
[9ebd778]100} // sepSet
101
[65240bb]102void ends( ofstream & os ) {
[6c5d92f]103 if ( getANL$( os ) ) nl( os );
104 else setPrt$( os, false ); // turn off
[65240bb]105 if ( &os == &exit ) exit( EXIT_FAILURE );
106 if ( &os == &abort ) abort();
107} // ends
108
[7ce2483]109bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
[768d091]110void clearerr( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
[7ce2483]111int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
[6ba0659]112
[e3fea42]113void open( ofstream & os, const char name[], const char mode[] ) {
[8dcb832]114 FILE * file;
115 for ( cnt; 10 ) {
116 errno = 0;
117 file = fopen( name, mode );
118 if ( file != 0p || errno != EINTR ) break; // timer interrupt ?
119 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
120 } // for
[d1a9ff5]121 if ( file == 0p ) {
[211def2]122 throwResume (open_failure){ os };
[8d321f9]123 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
[93c2e0a]124 } // if
[39eb23b0]125 os{ file }; // initialize
[6ba0659]126} // open
127
[39eb23b0]128//void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
[8da74119]129
[7ce2483]130void close( ofstream & os ) with( os ) {
[3bf3b6b]131 if ( (FILE *)(file$) == 0p ) return;
132 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
[6ba0659]133
[8dcb832]134 int ret;
135 for ( cnt; 10 ) {
136 errno = 0;
137 ret = fclose( (FILE *)(file$) );
138 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ?
139 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
140 } // for
141 if ( ret == EOF ) {
[874b16e]142 throw (close_failure){ os };
[ba0d2ea]143 // abort | IO_MSG "close output" | nl | strerror( errno );
[356189a]144 } // if
[7ce2483]145 file$ = 0p; // safety after close
[6ba0659]146} // close
147
[e3fea42]148ofstream & write( ofstream & os, const char data[], size_t size ) {
[6ba0659]149 if ( fail( os ) ) {
[874b16e]150 throw (write_failure){ os };
[ba0d2ea]151 // abort | IO_MSG "attempt write I/O on failed stream";
[6ba0659]152 } // if
153
[6c5d92f]154 if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) {
[874b16e]155 throw (write_failure){ os };
[ba0d2ea]156 // abort | IO_MSG "write" | nl | strerror( errno );
[839ccbb]157 } // if
[86bd7c1f]158 return os;
[839ccbb]159} // write
[51b73452]160
[09687aa]161int fmt( ofstream & os, const char format[], ... ) {
[5d125e4]162 va_list args;
[829c907]163 va_start( args, format );
[cce4648]164
[8dcb832]165 int len;
166 for ( cnt; 10 ) {
167 errno = 0;
[7a1b7e6]168 disable_interrupts();
[8dcb832]169 len = vfprintf( (FILE *)(os.file$), format, args );
[7a1b7e6]170 enable_interrupts();
[8dcb832]171 if ( len != EOF || errno != EINTR ) break; // timer interrupt ?
172 if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" );
173 } // for
[bbdf954]174 if ( len == EOF ) { // error writing ?
175 abort | IO_MSG "invalid write";
[90c3b1c]176 } // if
[5d125e4]177 va_end( args );
[b72bad4f]178
[6c5d92f]179 setPrt$( os, true ); // called in output cascade
180 sepReset$( os ); // reset separator
[90c3b1c]181 return len;
[829c907]182} // fmt
183
[fd8f88f]184static ofstream soutFile = { (FILE *)stdout };
[a87d40b]185ofstream & sout = soutFile, & stdout = soutFile;
[fd8f88f]186static ofstream serrFile = { (FILE *)stderr };
[a87d40b]187ofstream & serr = serrFile, & stderr = serrFile;
[51b73452]188
[e474cf09]189static ofstream lsoutFile = { (FILE *)stdout };
190ofstream & lsout = lsoutFile;
191
[7968301]192static ofstream exitFile = { (FILE *)stderr };
[65240bb]193ofstream & exit = exitFile;
[fd8f88f]194static ofstream abortFile = { (FILE *)stderr };
[65240bb]195ofstream & abort = abortFile;
[5cb2b8c]196
[f451177]197ofstream & nl( ofstream & os ) {
198 nl$( os ); // call basic_ostream nl
199 flush( os );
200 return os;
201} // nl
[90c3b1c]202
[ae0c1c3]203static basic_ostream_data(ofstream) ofstream_basic_data = {
204 sepPrt$,
205 sepReset$,
206 sepReset$,
207 sepGetCur$,
208 sepSetCur$,
209 getNL$,
210 setNL$,
211 getANL$,
212 setANL$,
213 getPrt$,
214 setPrt$,
215 nlOn,
216 nlOff,
217 sep,
218 nosep,
219 sepOn,
220 sepOff,
221 sepGet,
222 sepSet,
223 sepGetTuple,
224 sepSetTuple,
225 ends,
226 fmt,
227};
228
229basic_ostream_data(ofstream) const & basic_ostream_table = ofstream_basic_data;
230
231static ostream_data(ofstream) ofstream_data;
232
233// This should be an initializer like for the basic table.
234// But, initialization of a structure with an inline structure doesn't work.
235__attribute__((constructor(200)))
236static void __ofstream_data_init__() {
237 basic_ostream_data(ofstream) & basic = ofstream_data;
238 basic.sepPrt$ = sepPrt$;
239 basic.sepReset$ = (void(*)(ofstream&))sepReset$;
240 basic.sepReset$ = (void(*)(ofstream&, bool))sepReset$;
241 basic.sepGetCur$ = sepGetCur$;
242 basic.sepSetCur$ = sepSetCur$;
243 basic.getNL$ = getNL$;
244 basic.setNL$ = setNL$;
245 basic.getANL$ = getANL$;
246 basic.setANL$ = setANL$;
247 basic.getPrt$ = getPrt$;
248 basic.setPrt$ = setPrt$;
249 basic.nlOn = nlOn;
250 basic.nlOff = nlOff;
251 basic.sep = sep;
252 basic.nosep = nosep;
253 basic.sepOn = sepOn;
254 basic.sepOff = sepOff;
255 basic.sepGet = sepGet;
256 basic.sepSet = sepSet;
257 basic.sepGetTuple = sepGetTuple;
258 basic.sepSetTuple = sepSetTuple;
259 basic.ends = ends;
260 basic.fmt = fmt;
261 ofstream_data.fail = fail;
262 ofstream_data.clearerr = clearerr;
263 ofstream_data.flush = flush;
264 ofstream_data.open = open;
265 ofstream_data.close = close;
266 ofstream_data.write = write;
267}
268
269ostream_data(ofstream) const & ostream_table = ofstream_data;
[00e9be9]270
[8d321f9]271// *********************************** ifstream ***********************************
[65240bb]272
[51b73452]273
[09687aa]274// private
[7ce2483]275void ?{}( ifstream & is, void * file ) with( is ) {
[3bf3b6b]276 file$ = file;
[63e129c]277 nlOnOff$ = false; // => skip newlines when reading single characters
[65240bb]278} // ?{}
[09687aa]279
[ae0c1c3]280static basic_istream_data(ifstream) ifstream_basic_data = {
281 getANL$,
282 setANL$,
283 nlOn,
284 nlOff,
285 fmt,
286 ungetc,
287 eof,
288 clearerr,
289};
290
291basic_istream_data(ifstream) const & basic_istream_table = ifstream_basic_data;
292
293static istream_data(ifstream) ifstream_data;
294
295// This should be an initializer like for the basic table.
296// But, initialization of a structure with an inline structure doesn't work.
297__attribute__((constructor(200)))
298static void __ifstream_data_init__() {
299 basic_istream_data(ifstream) & basic = ifstream_data;
300 basic.getANL$ = getANL$;
301 basic.setANL$ = setANL$;
302 basic.nlOn = nlOn;
303 basic.nlOff = nlOff;
304 basic.fmt = fmt;
305 basic.ungetc = ungetc;
306 basic.eof = eof;
307 basic.clearerr = clearerr;
308 ifstream_data.fail = fail;
309 ifstream_data.open = (void(*)(ifstream &, const char *, const char *))open;
[39eb23b0]310// ifstream_data.open = (void(*)(ifstream &, const char *))open;
[ae0c1c3]311 ifstream_data.close = close;
312 ifstream_data.read = read;
313}
314
315istream_data(ifstream) const & istream_table = ifstream_data;
316
[c8371b5]317bool getANL$( ifstream & os ) { return os.nlOnOff$; }
[d0cfcbe1]318bool setANL$( ifstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
[c8371b5]319
[7ce2483]320inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
321inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
322
[09687aa]323// public
[6c5d92f]324void ?{}( ifstream & is ) { is.file$ = 0p; }
[39eb23b0]325void ?{}( ifstream & is, const char name[], const char mode[] ) { is{}; open( is, name, mode ); }
[7ce2483]326void ^?{}( ifstream & is ) { close( is ); }
[4cae032]327
[7ce2483]328bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
[768d091]329void clearerr( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
[00e9be9]330
[c8371b5]331void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
332void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
333
334bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; }
[6ba0659]335
[39eb23b0]336void open( ifstream & is, const char name[], const char mode[] = "r" ) {
[8dcb832]337 FILE * file;
338 for ( cnt; 10 ) {
339 errno = 0;
340 file = fopen( name, mode );
341 if ( file != 0p || errno != EINTR ) break; // timer interrupt ?
342 if ( cnt == 9 ) abort( "ifstream open EINTR spinning exceeded" );
343 } // for
[d1a9ff5]344 if ( file == 0p ) {
[211def2]345 throwResume (open_failure){ is };
[8d321f9]346 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
[93c2e0a]347 } // if
[39eb23b0]348 is{ file }; // initialize
[90c3b1c]349} // open
[6ba0659]350
[39eb23b0]351//void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
[8da74119]352
[7ce2483]353void close( ifstream & is ) with( is ) {
[3bf3b6b]354 if ( (FILE *)(file$) == 0p ) return;
355 if ( (FILE *)(file$) == (FILE *)stdin ) return;
[90c3b1c]356
[8dcb832]357 int ret;
358 for ( cnt; 10 ) {
359 errno = 0;
360 ret = fclose( (FILE *)(file$) );
361 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ?
362 if ( cnt == 9 ) abort( "ifstream close EINTR spinning exceeded" );
363 } // for
364 if ( ret == EOF ) {
[874b16e]365 throw (close_failure){ is };
[ba0d2ea]366 // abort | IO_MSG "close input" | nl | strerror( errno );
[356189a]367 } // if
[8dcb832]368 file$ = 0p; // safety after close
[90c3b1c]369} // close
370
[00e9be9]371ifstream & read( ifstream & is, char data[], size_t size ) {
[6ba0659]372 if ( fail( is ) ) {
[874b16e]373 throw (read_failure){ is };
[ba0d2ea]374 // abort | IO_MSG "attempt read I/O on failed stream";
[6ba0659]375 } // if
376
[6c5d92f]377 if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) {
[874b16e]378 throw (read_failure){ is };
[ba0d2ea]379 // abort | IO_MSG "read" | nl | strerror( errno );
[6ba0659]380 } // if
[86bd7c1f]381 return is;
[6ba0659]382} // read
[356189a]383
[a1a1f37d]384ifstream &ungetc( char c, ifstream & is ) {
[6ba0659]385 if ( fail( is ) ) {
[ff2a33e]386 abort | IO_MSG "attempt ungetc I/O on failed stream";
[6ba0659]387 } // if
[51b73452]388
[6c5d92f]389 if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) {
[ff2a33e]390 abort | IO_MSG "ungetc" | nl | strerror( errno );
[6ba0659]391 } // if
392 return is;
393} // ungetc
[51b73452]394
[09687aa]395int fmt( ifstream & is, const char format[], ... ) {
[5d125e4]396 va_list args;
[829c907]397 va_start( args, format );
[8dcb832]398
[211def2]399 int nargs, tmperrno;
[8dcb832]400 for () { // no check for EINTR limit waiting for keyboard input
[7a1b7e6]401 disable_interrupts();
[211def2]402 errno = 0;
[decd4a6]403 nargs = vfscanf( (FILE *)(is.file$), format, args );
[211def2]404 tmperrno = errno;
[7a1b7e6]405 enable_interrupts();
[decd4a6]406 if ( nargs != EOF || errno != EINTR ) break; // timer interrupt ?
[8dcb832]407 } // for
[decd4a6]408 if ( nargs == EOF ) { // EOF or matching failure ?
[bbdf954]409 if ( ! feof( (FILE *)(is.file$) ) && ferror( (FILE *)(is.file$) ) ) {
[ff2a33e]410 abort | IO_MSG "invalid read";
[90c3b1c]411 } // if
412 } // if
[211def2]413 if ( tmperrno == ERANGE ) throwResume ExceptionInst( data_range );
[5d125e4]414 va_end( args );
[decd4a6]415 return nargs;
[829c907]416} // fmt
[51b73452]417
[fd8f88f]418static ifstream sinFile = { (FILE *)stdin };
[a87d40b]419ifstream & sin = sinFile, & stdin = sinFile;
[86bd7c1f]420
[91e52be]421
[8d321f9]422// *********************************** exceptions ***********************************
[91e52be]423
424
[a5a6a1a8]425// exception I/O constructors
[decd4a6]426void ?{}( open_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]427 virtual_table = &open_failure_vt;
[3bf3b6b]428 ostream = &ostream;
429 tag = 1;
[a5a6a1a8]430} // ?{}
431
[decd4a6]432void ?{}( open_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]433 virtual_table = &open_failure_vt;
[3bf3b6b]434 istream = &istream;
435 tag = 0;
[a5a6a1a8]436} // ?{}
437
438
[ba0d2ea]439// exception I/O constructors
[decd4a6]440void ?{}( close_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]441 virtual_table = &close_failure_vt;
[3bf3b6b]442 ostream = &ostream;
443 tag = 1;
[ba0d2ea]444} // ?{}
445
[decd4a6]446void ?{}( close_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]447 virtual_table = &close_failure_vt;
[3bf3b6b]448 istream = &istream;
449 tag = 0;
[ba0d2ea]450} // ?{}
451
452
453// exception I/O constructors
[decd4a6]454void ?{}( write_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]455 virtual_table = &write_failure_vt;
[3bf3b6b]456 ostream = &ostream;
457 tag = 1;
[ba0d2ea]458} // ?{}
459
[decd4a6]460void ?{}( write_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]461 virtual_table = &write_failure_vt;
[3bf3b6b]462 istream = &istream;
463 tag = 0;
[ba0d2ea]464} // ?{}
465
466
467// exception I/O constructors
[decd4a6]468void ?{}( read_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]469 virtual_table = &read_failure_vt;
[3bf3b6b]470 ostream = &ostream;
471 tag = 1;
[ba0d2ea]472} // ?{}
473
[decd4a6]474void ?{}( read_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]475 virtual_table = &read_failure_vt;
[3bf3b6b]476 istream = &istream;
477 tag = 0;
[ba0d2ea]478} // ?{}
479
[874b16e]480// void throwopen_failure( ofstream & ostream ) {
481// open_failure exc = { ostream };
[ba0d2ea]482// }
483
[874b16e]484// void throwopen_failure( ifstream & istream ) {
485// open_failure exc = { istream };
[ba0d2ea]486// }
[91e52be]487
[86bd7c1f]488// Local Variables: //
489// tab-width: 4 //
490// End: //
Note: See TracBrowser for help on using the repository browser.