📄 file.cc
字号:
/* Copyright (C) 1988 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu)This file is part of the GNU C++ Library. This library is freesoftware; you can redistribute it and/or modify it under the terms ofthe GNU Library General Public License as published by the FreeSoftware Foundation; either version 2 of the License, or (at youroption) any later version. This library is distributed in the hopethat it will be useful, but WITHOUT ANY WARRANTY; without even theimplied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULARPURPOSE. See the GNU Library General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA.*/#ifdef __GNUG__#pragma implementation#endif#include <File.h>#include <std.h>#include <stdarg.h>#include <values.h>#include <sys/file.h> // needed to determine values of O_RDONLY...#ifdef VMS#include <errno.h> // needed to get the psect magic loaded#define FP (*fp)#else#define FP fp#endif// error handlersvoid verbose_File_error_handler(const char* msg){ perror(msg); errno = 0;}void quiet_File_error_handler(const char*){ errno = 0;}void fatal_File_error_handler(const char* msg){ perror(msg); exit(1);}one_arg_error_handler_t File_error_handler = verbose_File_error_handler;one_arg_error_handler_t set_File_error_handler(one_arg_error_handler_t f){ one_arg_error_handler_t old = File_error_handler; File_error_handler = f; return old;}/* Opening files. open(filename, io_mode, access_mode) is done via system open command since fopen doesn't handle all of the cases possible with sys open. After a successful open, fdopen is called to attach an _iobuf to the file descriptor. All this requires a few decoding routines that can translate among our enumerated types, system flags, and fopen modes.*/enum sys_open_cmd_io_mode // These should be correct for most systems{ sio_read = O_RDONLY, sio_write = O_WRONLY, sio_readwrite = O_RDWR, sio_append = O_APPEND};enum sys_open_cmd_access_mode{ sa_create = O_CREAT, sa_truncate = O_TRUNC, sa_createonly = O_EXCL | O_CREAT}; static int open_cmd_arg(io_mode i, access_mode a) // decode modes{ int arg; switch(i) { case io_readonly: arg = sio_read; break; case io_writeonly: arg = sio_write; break; case io_readwrite: arg = sio_readwrite; break; case io_appendonly: arg = sio_append | sio_write; break; case io_append: arg = sio_append | sio_readwrite; break; default: return -1; }; switch(a) { case a_createonly: return arg | sa_createonly; case a_create: return arg | sa_create | sa_truncate; case a_useonly: return arg; case a_use: return arg | sa_create; default: return -1; }}static char* fopen_cmd_arg(io_mode i){ switch(i) { case io_readonly: return "r"; case io_writeonly: return "w"; case io_readwrite: return "r+"; case io_appendonly:return "a"; case io_append: return "a+"; default: return 0; }}void File::initialize() { fp = 0; nm = 0; stat = 0; state = _bad; rw = 0;}// reset class vars after open// fp->_flag inspection is isolated herevoid File::reinitialize(const char* filename){ if (filename != 0) setname(filename); else if (fp == stdin) setname("(stdin)"); else if (fp == stdout) setname("(stdout)"); else if (fp == stderr) setname("(stderr)"); else if (rw & 4) setname("(string)"); else setname(0); if (fp != 0) { state = _good; if (FP->_flag & (_IOREAD|_IORW)) rw |= 01; if (FP->_flag & (_IOWRT|_IORW)) rw |= 02; check_state(); } else { set(_fail); set(_bad); error(); }}File& File::open(const char* filename, io_mode m, access_mode a){ close(); int open_arg = open_cmd_arg(m, a); if (open_arg != -1) { int fd = ::open(filename, open_arg, 0666); if (fd >= 0) fp = fdopen(fd, fopen_cmd_arg(m)); } reinitialize(filename); return *this;}File& File::open(const char* filename, const char* m){ close(); fp = fopen(filename, m); reinitialize(filename); return *this;}File& File::open(FILE* fileptr){ close(); fp = fileptr; reinitialize(0); return *this;}File& File::open(int filedesc, io_mode m){ close(); fp = fdopen(filedesc, fopen_cmd_arg(m)); reinitialize(0); return *this;}File& File::close(){ if (fp != 0) {#ifdef VMS if (rw & 4) // we own the iobuf, kill it delete(*fp); // kill the _iobuf#endif if (rw & 4) // we own the iobuf, kill it delete fp; else if (fp == stdin || fp == stdout || fp == stderr) flush(); else fclose(fp); } fp = 0; rw = 0; set(_bad); return *this;}File& File::remove(){ close(); return failif (nm == 0 || unlink(nm) != 0);}File::File(){ initialize(); }File::File(const char* filename, io_mode m, access_mode a) { initialize(); open(filename, m, a); }File::File(const char* filename, const char* m) { initialize(); open(filename, m); }File::File(int filedesc, io_mode m){ initialize(); open(filedesc, m); }File::File(FILE* fileptr){ initialize(); open(fileptr); }File::File(int sz, char* buf, io_mode m){ if (m != io_readonly && m != io_writeonly) (*File_error_handler) ("invalid io_mode for string IO"); initialize(); rw = 4;#ifdef VMS _iobuf *iob; FILE *f; iob = new _iobuf; f = new(FILE); *f = iob; fp = f;#else fp = new _iobuf;#endif#ifndef _NFILE FP->_file = 255; // any illegal value#else FP->_file = _NFILE-1; // The last filedescriptor...#ifdef BUFEND_ENTRY_TYPE _bufendtab[FP->_file] = (BUFEND_ENTRY_TYPE)buf+sz-1;#endif#endif FP->_ptr = FP->_base = buf;#ifdef HAVE_BUFSIZ FP->_bufsiz = sz;#endif if (m == io_readonly) { int len = 0; while (len < sz && buf[len] != 0) ++len; if (len == sz) buf[sz - 1] = 0; // force null-termination! FP->_cnt = len; FP->_flag = _IOREAD | _IOSTRG | _IOMYBUF; } else { bzero(buf, sz); // so any result will be null-terminated FP->_cnt = sz - 1; // leave at least one null at end FP->_flag = _IOWRT | _IOSTRG | _IOMYBUF; } reinitialize(0);}File::~File(){ delete(nm); close();}void File::setname(const char* newname){ if (nm == newname) return; if (nm != 0) delete(nm); if (newname != 0) { nm = new char[strlen(newname) + 1]; strcpy(nm, newname); } else nm = 0;}File& File::setbuf(int buffer_kind){ if (!is_open()) { set(_fail); return *this; } switch(buffer_kind) { case _IOFBF: #ifdef HAVE_SETVBUF setvbuf(fp, 0, _IOFBF, 0);#endif break; case _IONBF: ::setbuf(fp, 0); break; case _IOLBF:#ifdef HAVE_SETLINEBUF setlinebuf(fp);#else#ifdef HAVE_SETVBUF setvbuf(fp, 0, _IOLBF, 0);#endif#endif break; default: break; } return *this;}File& File::setbuf(int size, char* buf){ if (!is_open()) { set(_fail); return *this; }#ifdef HAVE_SETVBUF setvbuf(fp, buf, _IOFBF, size);#else setbuffer(fp, buf, size);#endif return *this;}void File::error(){ check_state(); set(_fail); if (errno != 0) { char error_string[400]; strcpy(error_string, "\nerror in File "); if (nm != 0) strcat(error_string, nm); (*File_error_handler)(error_string); }}//------------------------------------------------------------------void File::check_state() // ensure fp & state agree about eof{ if (fp != 0) { if (feof(fp)) set(_eof); else unset(_eof); if (ferror(fp)) set(_bad); }}File& File::put(const char* s){ return failif(!writable() || fputs(s, fp) == EOF);}File& File::get(char* s, int n, char terminator){ if (!readable()) { set(_fail); return *this; } char ch; stat = --n; if (n > 0 && (get(ch))) { if (ch == terminator) { unget(ch); stat= 0; // This is not an error condition ! } else { *s++ = ch; --n; while (n > 0 && (get(ch))) { if (ch == terminator) { unget(ch); break; } else { *s++ = ch; --n; } } } } *s = 0; return failif((stat != 0) && ((stat -= n) == 0));}File& File::getline(char* s, int n, char terminator){ if (!readable()) { set(_fail); return *this; } char ch; stat = --n; while (n > 0 && (get(ch))) { --n; if ((*s++ = ch) == terminator) break; } *s = 0; return failif((stat != 0) && ((stat -= n) == 0));}// from Doug Schmidt// This should probably be a page size....#define CHUNK_SIZE 512/* Reads an arbitrarily long input line terminated by a user-specified TERMINATOR. Super-nifty trick using recursion avoids unnecessary calls to NEW! */char *File::readline (int chunk_number, char terminator) { char buf[CHUNK_SIZE]; register char *bufptr = buf; register char *ptr; char ch; int continu; while ((continu = !!get(ch)) && ch != terminator) /* fill the current buffer */ { *bufptr++ = ch; if (bufptr - buf >= CHUNK_SIZE) /* prepend remainder to ptr buffer */ { if (ptr = readline (chunk_number + 1, terminator)) for (; bufptr != buf; *--ptr = *--bufptr); return ptr; } } if (!continu && bufptr == buf) return NULL; int size = (chunk_number * CHUNK_SIZE + bufptr - buf) + 1; if (ptr = new char[stat = size]) { for (*(ptr += (size - 1)) = '\0'; bufptr != buf; *--ptr = *--bufptr) ; return ptr; } else return NULL;}/* Reads an arbitrarily long input line terminated by TERMINATOR. This routine allocates its own memory, so the user should only supply the address of a (char *). */File& File::gets(char **s, char terminator){ if (!readable()) { set(_fail); return *this; } return failif(!(*s = readline (0, terminator)));} #ifndef VMSFile& File::scan(const char* fmt ...){ if (readable()) { va_list args; va_start(args, fmt);#ifndef HAVE_VSCANF stat = _doscan(fp, fmt, args);#else stat = vfscanf(fp, fmt, args);#endif va_end(args); failif(stat <= 0); } return *this;}#endifFile& File::form(const char* fmt ...){ va_list args; va_start(args, fmt);#ifndef HAVE_VPRINTF stat = _doprnt(fmt, args, fp);#ifdef HAVE_VOID_DOPRNT stat = ferror(fp) ? -1 : 0;#endif#else stat = vfprintf(fp, fmt, args);#endif va_end(args); failif(stat < 0); return *this;}#ifdef VMSextern "C" { unlink(const char *s) { int remove(const char *); return remove(s); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -