1 /*
2 Copyright (C) 1988 Free Software Foundation
3 written by Doug Lea (dl@rocky.oswego.edu)
4
5 This file is part of GNU CC.
6
7 GNU CC is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY. No author or distributor
9 accepts responsibility to anyone for the consequences of using it
10 or for whether it serves any particular purpose or works at all,
11 unless he says so in writing. Refer to the GNU CC General Public
12 License for full details.
13
14 Everyone is granted permission to copy, modify and redistribute
15 GNU CC, but only under the conditions described in the
16 GNU CC General Public License. A copy of this license is
17 supposed to have been given to you along with GNU CC so you
18 can know your rights and responsibilities. It should be in a
19 file named COPYING. Among other things, the copyright notice
20 and this notice must be preserved on all copies.
21 */
22
23 #ifdef __GNUG__
24 #pragma implementation
25 #endif
26 #include <File.h>
27 #include <std.h>
28 #include <stdarg.h>
29 #include <values.h>
30 #include <sys/file.h> // needed to determine values of O_RDONLY...
31 #include <open.h>
32
33 #ifdef VMS
34 #include <errno.h> // needed to get the psect magic loaded
35 #define FP (*fp)
36 #else
37 #define FP fp
38 #endif
39
40
41 // error handlers
42
verbose_File_error_handler(const char * msg)43 void verbose_File_error_handler(const char* msg)
44 {
45 perror(msg);
46 errno = 0;
47 }
48
quiet_File_error_handler(const char *)49 void quiet_File_error_handler(const char*)
50 {
51 errno = 0;
52 }
53
fatal_File_error_handler(const char * msg)54 void fatal_File_error_handler(const char* msg)
55 {
56 perror(msg);
57 exit(1);
58 }
59
60 one_arg_error_handler_t File_error_handler = verbose_File_error_handler;
61
62
set_File_error_handler(one_arg_error_handler_t f)63 one_arg_error_handler_t set_File_error_handler(one_arg_error_handler_t f)
64 {
65 one_arg_error_handler_t old = File_error_handler;
66 File_error_handler = f;
67 return old;
68 }
69
70
71
initialize()72 void File::initialize()
73 {
74 fp = 0; nm = 0; stat = 0; state = _bad; rw = 0;
75 }
76
77 // reset class vars after open
78 // fp->_flag inspection is isolated here
79
reinitialize(const char * filename)80 void File::reinitialize(const char* filename)
81 {
82 if (filename != 0) setname(filename);
83 else if (fp == stdin) setname("(stdin)");
84 else if (fp == stdout) setname("(stdout)");
85 else if (fp == stderr) setname("(stderr)");
86 else if (rw & 4) setname("(string)");
87 else setname(0);
88
89 if (fp != 0)
90 {
91 state = _good;
92 #if 1 /* bsd 4.4 */
93 if (FP->_flags & (__SRD|__SRW))
94 rw |= 01;
95 if (FP->_flags & (__SWR|__SRW|__SAPP))
96 rw |= 02;
97 #else
98 if (FP->_flag & (_IOREAD|_IORW))
99 rw |= 01;
100 if (FP->_flag & (_IOWRT|_IORW|_IOAPPEND))
101 rw |= 02;
102 #endif
103 check_state();
104 }
105 else
106 {
107 set(_fail); set(_bad);
108 error();
109 }
110 }
111
112
open(const char * filename,io_mode m,access_mode a)113 File& File::open(const char* filename, io_mode m, access_mode a)
114 {
115 close();
116 int open_arg = open_cmd_arg(m, a);
117 if (open_arg != -1)
118 {
119 int fd = ::open(filename, open_arg, 0666);
120 if (fd >= 0)
121 fp = fdopen(fd, fopen_cmd_arg(m));
122 }
123 reinitialize(filename);
124 return *this;
125 }
126
open(const char * filename,const char * m)127 File& File::open(const char* filename, const char* m)
128 {
129 close();
130 fp = fopen(filename, m);
131 reinitialize(filename);
132 return *this;
133 }
134
open(FILE * fileptr)135 File& File::open(FILE* fileptr)
136 {
137 close();
138 fp = fileptr;
139 reinitialize(0);
140 return *this;
141 }
142
open(int filedesc,io_mode m)143 File& File::open(int filedesc, io_mode m)
144 {
145 close();
146 fp = fdopen(filedesc, fopen_cmd_arg(m));
147 reinitialize(0);
148 return *this;
149 }
150
close()151 File& File::close()
152 {
153 if (fp != 0)
154 {
155 #ifdef VMS
156 if (rw & 4) // we own the iobuf, kill it
157 delete(*fp); // kill the _iobuf
158 #endif
159 if (rw & 4) // we own the iobuf, kill it
160 delete fp;
161 else if (fp == stdin || fp == stdout || fp == stderr)
162 flush();
163 else
164 fclose(fp);
165 }
166 fp = 0;
167 rw = 0;
168 set(_bad);
169 return *this;
170 }
171
remove()172 File& File::remove()
173 {
174 close();
175 return failif (nm == 0 || unlink(nm) != 0);
176 }
177
178
File()179 File::File()
180 {
181 initialize();
182 }
183
File(const char * filename,io_mode m,access_mode a)184 File::File(const char* filename, io_mode m, access_mode a)
185 {
186 initialize();
187 open(filename, m, a);
188 }
189
File(const char * filename,const char * m)190 File::File(const char* filename, const char* m)
191 {
192 initialize();
193 open(filename, m);
194 }
195
File(int filedesc,io_mode m)196 File::File(int filedesc, io_mode m)
197 {
198 initialize();
199 open(filedesc, m);
200 }
201
File(FILE * fileptr)202 File::File(FILE* fileptr)
203 {
204 initialize();
205 open(fileptr);
206 }
207
208
~File()209 File::~File()
210 {
211 delete(nm);
212 close();
213 }
214
setname(const char * newname)215 void File::setname(const char* newname)
216 {
217 if (nm == newname) return;
218
219 if (nm != 0)
220 delete(nm);
221 if (newname != 0)
222 {
223 nm = new char[strlen(newname) + 1];
224 strcpy(nm, newname);
225 }
226 else
227 nm = 0;
228 }
229
230
setbuf(int buffer_kind)231 File& File::setbuf(int buffer_kind)
232 {
233 if (!is_open())
234 {
235 set(_fail);
236 return *this;
237 }
238 switch(buffer_kind)
239 {
240 case _IOFBF:
241 #ifdef HAVE_SETVBUF
242 setvbuf(fp, 0, _IOFBF, 0);
243 #endif
244 break;
245 case _IONBF:
246 ::setbuf(fp, 0);
247 break;
248 case _IOLBF:
249 #ifdef HAVE_SETLINEBUF
250 setlinebuf(fp);
251 #else
252 #ifdef HAVE_SETVBUF
253 setvbuf(fp, 0, _IOLBF, 0);
254 #endif
255 #endif
256 break;
257 default:
258 break;
259 }
260 return *this;
261 }
262
setbuf(int size,char * buf)263 File& File::setbuf(int size, char* buf)
264 {
265 if (!is_open())
266 {
267 set(_fail);
268 return *this;
269 }
270 #ifdef HAVE_SETVBUF
271 setvbuf(fp, buf, _IOFBF, size);
272 #else
273 setbuffer(fp, buf, size);
274 #endif
275 return *this;
276 }
277
error()278 void File::error()
279 {
280 check_state();
281 set(_fail);
282 if (errno != 0)
283 {
284 char error_string[400];
285 strcpy(error_string, "\nerror in File ");
286 if (nm != 0)
287 strcat(error_string, nm);
288 (*File_error_handler)(error_string);
289 }
290 }
291
292
293 //------------------------------------------------------------------
294
check_state()295 void File::check_state() // ensure fp & state agree about eof
296 {
297 if (fp != 0)
298 {
299 if (feof(fp))
300 set(_eof);
301 else
302 unset(_eof);
303 if (ferror(fp))
304 set(_bad);
305 }
306 }
307
put(const char * s)308 File& File::put(const char* s)
309 {
310 return failif(!writable() || fputs(s, fp) == EOF);
311 }
312
get(char * s,int n,char terminator)313 File& File::get(char* s, int n, char terminator)
314 {
315 if (!readable())
316 {
317 set(_fail);
318 return *this;
319 }
320
321 char ch;
322 stat = --n;
323
324 if (n > 0 && (get(ch)))
325 {
326 if (ch == terminator) {
327 unget(ch);
328 stat= 0; // This is not an error condition !
329 }
330 else
331 {
332 *s++ = ch; --n;
333 while (n > 0 && (get(ch)))
334 {
335 if (ch == terminator)
336 {
337 unget(ch);
338 break;
339 }
340 else
341 {
342 *s++ = ch; --n;
343 }
344 }
345 }
346 }
347
348 *s = 0;
349 return failif((stat != 0) && ((stat -= n) == 0));
350 }
351
getline(char * s,int n,char terminator)352 File& File::getline(char* s, int n, char terminator)
353 {
354 if (!readable())
355 {
356 set(_fail);
357 return *this;
358 }
359
360 char ch;
361 stat = --n;
362
363 while (n > 0 && (get(ch)))
364 {
365 --n;
366 if ((*s++ = ch) == terminator)
367 break;
368 }
369
370 *s = 0;
371 return failif((stat != 0) && ((stat -= n) == 0));
372 }
373
374 // from Doug Schmidt
375
376 // This should probably be a page size....
377 #define CHUNK_SIZE 512
378
379 /* Reads an arbitrarily long input line terminated by a user-specified
380 TERMINATOR. Super-nifty trick using recursion avoids unnecessary calls
381 to NEW! */
382
readline(int chunk_number,char terminator)383 char *File::readline (int chunk_number, char terminator)
384 {
385 char buf[CHUNK_SIZE];
386 register char *bufptr = buf;
387 register char *ptr;
388 char ch;
389 int continu;
390
391 while ((continu = !!get(ch)) && ch != terminator) /* fill the current buffer */
392 {
393 *bufptr++ = ch;
394 if (bufptr - buf >= CHUNK_SIZE) /* prepend remainder to ptr buffer */
395 {
396 if (ptr = readline (chunk_number + 1, terminator))
397
398 for (; bufptr != buf; *--ptr = *--bufptr);
399
400 return ptr;
401 }
402 }
403 if (!continu && bufptr == buf)
404 return NULL;
405
406 int size = (chunk_number * CHUNK_SIZE + bufptr - buf) + 1;
407
408 if (ptr = new char[stat = size])
409 {
410
411 for (*(ptr += (size - 1)) = '\0'; bufptr != buf; *--ptr = *--bufptr)
412 ;
413
414 return ptr;
415 }
416 else
417 return NULL;
418 }
419
420 /* Reads an arbitrarily long input line terminated by TERMINATOR.
421 This routine allocates its own memory, so the user should
422 only supply the address of a (char *). */
423
gets(char ** s,char terminator)424 File& File::gets(char **s, char terminator)
425 {
426 if (!readable())
427 {
428 set(_fail);
429 return *this;
430 }
431
432 return failif(!(*s = readline (0, terminator)));
433 }
434
435 #ifndef VMS
scan(const char * fmt...)436 File& File::scan(const char* fmt ...)
437 {
438 if (readable())
439 {
440 va_list args;
441 va_start(args, fmt);
442 #ifndef HAVE_VSCANF
443 stat = _doscan(fp, fmt, args);
444 #else
445 stat = vfscanf(fp, fmt, args);
446 #endif
447 va_end(args);
448 failif(stat <= 0);
449 }
450 return *this;
451 }
452 #endif
453
form(const char * fmt...)454 File& File::form(const char* fmt ...)
455 {
456 va_list args;
457 va_start(args, fmt);
458 #ifndef HAVE_VPRINTF
459 stat = _doprnt(fmt, args, fp);
460 #ifdef HAVE_VOID_DOPRNT
461 stat = ferror(fp) ? -1 : 0;
462 #endif
463 #else
464 stat = vfprintf(fp, fmt, args);
465 #endif
466 va_end(args);
467 failif(stat < 0);
468 return *this;
469 }
470
471 #ifdef VMS
472 extern "C" {
unlink(const char * s)473 unlink(const char *s)
474 {
475 int remove(const char *);
476
477 return remove(s);
478 }
479 }
480 #endif
481
482