xref: /386bsd/usr/src/lib/libg++/libg++/File.cc (revision a2142627)
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