source: libcfa/src/fstream.cfa@ 39eb23b0

stuck-waitfor-destruct
Last change on this file since 39eb23b0 was 39eb23b0, checked in by Peter A. Buhr <pabuhr@…>, 2 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
Line 
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//
7// fstream.c --
8//
9// Author : Peter A. Buhr
10// Created On : Wed May 27 17:56:53 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Wed Jan 14 21:12:05 2026
13// Update Count : 596
14//
15
16#include "fstream.hfa" // also includes iostream.hfa
17
18#include <stdio.h> // vfprintf, vfscanf
19#include <stdlib.h> // exit
20#include <stdarg.h> // varargs
21#include <string.h> // strncpy, strerror
22#include <assert.h>
23#include <errno.h> // errno
24
25#pragma GCC visibility push(default)
26
27
28// *********************************** ofstream ***********************************
29
30
31#define IO_MSG "I/O error: "
32
33// private
34void ?{}( ofstream & os, void * file ) with( os ) {
35 file$ = file;
36 sepDefault$ = true;
37 sepOnOff$ = false;
38 nlOnOff$ = true;
39 prt$ = false;
40 sawNL$ = false;
41 sepSetCur$( os, sepGet( os ) );
42 sepSet( os, " " );
43 sepSetTuple( os, ", " );
44} // ?{}
45
46inline bool getNL$( ofstream & os ) { return os.sawNL$; }
47inline bool setNL$( ofstream & os, bool state ) { bool temp = os.sawNL$; os.sawNL$ = state; return temp; }
48inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
49inline bool setANL$( ofstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
50
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; }
56
57inline bool getPrt$( ofstream & os ) { return os.prt$; }
58inline bool setPrt$( ofstream & os, bool state ) { bool temp = os.prt$; os.prt$ = state; return temp; }
59
60inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); }
61inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
62
63// public
64void ?{}( ofstream & os ) { os.file$ = 0p; }
65void ?{}( ofstream & os, const char name[], const char mode[] ) { os{}; open( os, name, mode ); }
66void ^?{}( ofstream & os ) { close( os ); }
67
68void nlOn( ofstream & os ) { os.nlOnOff$ = true; }
69void nlOff( ofstream & os ) { os.nlOnOff$ = false; }
70
71void sep( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
72void nosep( ofstream & os ) { os.sepOnOff$ = false; }
73
74bool sepOn( ofstream & os ) {
75 bool temp = os.sepDefault$;
76 os.sepDefault$ = true;
77 if ( os.sepOnOff$ ) sepReset$( os ); // start of line ?
78 return temp;
79} // sepOn
80
81bool sepOff( ofstream & os ) {
82 bool temp = os.sepDefault$;
83 os.sepDefault$ = false;
84 sepReset$( os );
85 return temp;
86} // sepOff
87
88const char * sepGet( ofstream & os ) { return os.separator$; }
89void sepSet( ofstream & os, const char s[] ) {
90 assert( s );
91 strncpy( os.separator$, s, ofstream_sepSize - 1 );
92 os.separator$[ofstream_sepSize - 1] = '\0';
93} // sepSet
94
95const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; }
96void sepSetTuple( ofstream & os, const char s[] ) {
97 assert( s );
98 strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 );
99 os.tupleSeparator$[ofstream_sepSize - 1] = '\0';
100} // sepSet
101
102void ends( ofstream & os ) {
103 if ( getANL$( os ) ) nl( os );
104 else setPrt$( os, false ); // turn off
105 if ( &os == &exit ) exit( EXIT_FAILURE );
106 if ( &os == &abort ) abort();
107} // ends
108
109bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
110void clearerr( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
111int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
112
113void open( ofstream & os, const char name[], const char mode[] ) {
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
121 if ( file == 0p ) {
122 throwResume (open_failure){ os };
123 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
124 } // if
125 os{ file }; // initialize
126} // open
127
128//void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
129
130void close( ofstream & os ) with( os ) {
131 if ( (FILE *)(file$) == 0p ) return;
132 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
133
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 ) {
142 throw (close_failure){ os };
143 // abort | IO_MSG "close output" | nl | strerror( errno );
144 } // if
145 file$ = 0p; // safety after close
146} // close
147
148ofstream & write( ofstream & os, const char data[], size_t size ) {
149 if ( fail( os ) ) {
150 throw (write_failure){ os };
151 // abort | IO_MSG "attempt write I/O on failed stream";
152 } // if
153
154 if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) {
155 throw (write_failure){ os };
156 // abort | IO_MSG "write" | nl | strerror( errno );
157 } // if
158 return os;
159} // write
160
161int fmt( ofstream & os, const char format[], ... ) {
162 va_list args;
163 va_start( args, format );
164
165 int len;
166 for ( cnt; 10 ) {
167 errno = 0;
168 disable_interrupts();
169 len = vfprintf( (FILE *)(os.file$), format, args );
170 enable_interrupts();
171 if ( len != EOF || errno != EINTR ) break; // timer interrupt ?
172 if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" );
173 } // for
174 if ( len == EOF ) { // error writing ?
175 abort | IO_MSG "invalid write";
176 } // if
177 va_end( args );
178
179 setPrt$( os, true ); // called in output cascade
180 sepReset$( os ); // reset separator
181 return len;
182} // fmt
183
184static ofstream soutFile = { (FILE *)stdout };
185ofstream & sout = soutFile, & stdout = soutFile;
186static ofstream serrFile = { (FILE *)stderr };
187ofstream & serr = serrFile, & stderr = serrFile;
188
189static ofstream lsoutFile = { (FILE *)stdout };
190ofstream & lsout = lsoutFile;
191
192static ofstream exitFile = { (FILE *)stderr };
193ofstream & exit = exitFile;
194static ofstream abortFile = { (FILE *)stderr };
195ofstream & abort = abortFile;
196
197ofstream & nl( ofstream & os ) {
198 nl$( os ); // call basic_ostream nl
199 flush( os );
200 return os;
201} // nl
202
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;
270
271// *********************************** ifstream ***********************************
272
273
274// private
275void ?{}( ifstream & is, void * file ) with( is ) {
276 file$ = file;
277 nlOnOff$ = false; // => skip newlines when reading single characters
278} // ?{}
279
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;
310// ifstream_data.open = (void(*)(ifstream &, const char *))open;
311 ifstream_data.close = close;
312 ifstream_data.read = read;
313}
314
315istream_data(ifstream) const & istream_table = ifstream_data;
316
317bool getANL$( ifstream & os ) { return os.nlOnOff$; }
318bool setANL$( ifstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
319
320inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
321inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
322
323// public
324void ?{}( ifstream & is ) { is.file$ = 0p; }
325void ?{}( ifstream & is, const char name[], const char mode[] ) { is{}; open( is, name, mode ); }
326void ^?{}( ifstream & is ) { close( is ); }
327
328bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
329void clearerr( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
330
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; }
335
336void open( ifstream & is, const char name[], const char mode[] = "r" ) {
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
344 if ( file == 0p ) {
345 throwResume (open_failure){ is };
346 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
347 } // if
348 is{ file }; // initialize
349} // open
350
351//void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
352
353void close( ifstream & is ) with( is ) {
354 if ( (FILE *)(file$) == 0p ) return;
355 if ( (FILE *)(file$) == (FILE *)stdin ) return;
356
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 ) {
365 throw (close_failure){ is };
366 // abort | IO_MSG "close input" | nl | strerror( errno );
367 } // if
368 file$ = 0p; // safety after close
369} // close
370
371ifstream & read( ifstream & is, char data[], size_t size ) {
372 if ( fail( is ) ) {
373 throw (read_failure){ is };
374 // abort | IO_MSG "attempt read I/O on failed stream";
375 } // if
376
377 if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) {
378 throw (read_failure){ is };
379 // abort | IO_MSG "read" | nl | strerror( errno );
380 } // if
381 return is;
382} // read
383
384ifstream &ungetc( char c, ifstream & is ) {
385 if ( fail( is ) ) {
386 abort | IO_MSG "attempt ungetc I/O on failed stream";
387 } // if
388
389 if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) {
390 abort | IO_MSG "ungetc" | nl | strerror( errno );
391 } // if
392 return is;
393} // ungetc
394
395int fmt( ifstream & is, const char format[], ... ) {
396 va_list args;
397 va_start( args, format );
398
399 int nargs, tmperrno;
400 for () { // no check for EINTR limit waiting for keyboard input
401 disable_interrupts();
402 errno = 0;
403 nargs = vfscanf( (FILE *)(is.file$), format, args );
404 tmperrno = errno;
405 enable_interrupts();
406 if ( nargs != EOF || errno != EINTR ) break; // timer interrupt ?
407 } // for
408 if ( nargs == EOF ) { // EOF or matching failure ?
409 if ( ! feof( (FILE *)(is.file$) ) && ferror( (FILE *)(is.file$) ) ) {
410 abort | IO_MSG "invalid read";
411 } // if
412 } // if
413 if ( tmperrno == ERANGE ) throwResume ExceptionInst( data_range );
414 va_end( args );
415 return nargs;
416} // fmt
417
418static ifstream sinFile = { (FILE *)stdin };
419ifstream & sin = sinFile, & stdin = sinFile;
420
421
422// *********************************** exceptions ***********************************
423
424
425// exception I/O constructors
426void ?{}( open_failure & ex, ofstream & ostream ) with( ex ) {
427 virtual_table = &open_failure_vt;
428 ostream = &ostream;
429 tag = 1;
430} // ?{}
431
432void ?{}( open_failure & ex, ifstream & istream ) with( ex ) {
433 virtual_table = &open_failure_vt;
434 istream = &istream;
435 tag = 0;
436} // ?{}
437
438
439// exception I/O constructors
440void ?{}( close_failure & ex, ofstream & ostream ) with( ex ) {
441 virtual_table = &close_failure_vt;
442 ostream = &ostream;
443 tag = 1;
444} // ?{}
445
446void ?{}( close_failure & ex, ifstream & istream ) with( ex ) {
447 virtual_table = &close_failure_vt;
448 istream = &istream;
449 tag = 0;
450} // ?{}
451
452
453// exception I/O constructors
454void ?{}( write_failure & ex, ofstream & ostream ) with( ex ) {
455 virtual_table = &write_failure_vt;
456 ostream = &ostream;
457 tag = 1;
458} // ?{}
459
460void ?{}( write_failure & ex, ifstream & istream ) with( ex ) {
461 virtual_table = &write_failure_vt;
462 istream = &istream;
463 tag = 0;
464} // ?{}
465
466
467// exception I/O constructors
468void ?{}( read_failure & ex, ofstream & ostream ) with( ex ) {
469 virtual_table = &read_failure_vt;
470 ostream = &ostream;
471 tag = 1;
472} // ?{}
473
474void ?{}( read_failure & ex, ifstream & istream ) with( ex ) {
475 virtual_table = &read_failure_vt;
476 istream = &istream;
477 tag = 0;
478} // ?{}
479
480// void throwopen_failure( ofstream & ostream ) {
481// open_failure exc = { ostream };
482// }
483
484// void throwopen_failure( ifstream & istream ) {
485// open_failure exc = { istream };
486// }
487
488// Local Variables: //
489// tab-width: 4 //
490// End: //
Note: See TracBrowser for help on using the repository browser.