// // aegis - project change supervisor // Copyright (C) 1999, 2002, 2004-2006, 2008 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #ifndef LIBAEGIS_INPUT_H #define LIBAEGIS_INPUT_H #include #include class input; // forward /** * The input_ty abstract class represent a generic input source. */ class input_ty { public: /** * The destructor is used to close the given input, and delete all * resources associated with it. Once this returns, the given * input is no longer available for *any* use. (Think of this * method as "close" if it helps.) */ virtual ~input_ty(); /** * The default constructor. */ input_ty(); /** * The read method is used to read buffered data from the given * input stream. At most \a size bytes will be read into * \a buffer. The number of bytes actually read will be returned. * At end-of-file, a value <=0 will be returned, and \a buffer will * be unchanged. All file read errors or format errors are fatal, * and will cause the method to not return. * * @param data * Where to put the results of the read. * @param nbytes * The maximum number of bytes to read. * @returns * The actual number of bytes read, or zero for end-of-file. */ long read(void *data, size_t nbytes); /** * The read_strictest method is used to read data from the given * input stream. Exactly \a size bytes will be read into * \a buffer. If there are less than \a size bytes available, a * fatal error will result. * * @param data * Where to put the results of the read. * @param size * The number of bytes to read. */ void read_strictest(void *data, size_t size); /** * The read_strict method is used to read data from the given input * stream. Exactly \a size bytes will be read into \a buffer, or * zero bytes at end-of-file. If there are less than \a size bytes * available, a fatal error will result. * * @param data * Where to put the results of the read. * @param size * The number of bytes to read. * @returns * bool; true if data was read, false if end-of-file */ bool read_strict(void *data, size_t size); /** * The skip method is used to read data from the given input * stream and discard it. Exactly \a size bytes will be read. If * there are less than \a size bytes available, a fatal error will * result. * * @param size * The number of bytes to discard. */ void skip(size_t size); /** * The fatal_error method is used to report a fatal error on * an input stream. This method does not return. */ void fatal_error(const char *msg); /** * The one_line method is used to read one line from the input * (up to the next newline character or end of input). * * @param result * Where the text is stored. The newline is not included in the * returned string. * @returns * bool; true if any text was read, false if end-of-file is reached. */ bool one_line(nstring &result); /** * The ftell method is used to determine the current buffered * data position within the input. */ long ftell(); /** * The name method is used to determine the name of the input. */ virtual nstring name() = 0; /** * The length method is used to determine the length of the input. * May return -1 if the length is unknown. */ virtual long length() = 0; /** * The getch method is used to get the next character from * the input. Returns a value<=0 at end-of-file. */ int getch() { if (buffer_position < buffer_end) return *buffer_position++; return getc_complicated(); } /** * The ungetc method is used to push back a character of input. * Think of it as undoing the effects of the getch method. */ void ungetc(int c) { if (c >= 0) { if (buffer_position > buffer) *--buffer_position = c; else ungetc_complicated(c); } } /** * The peek method is used to obtain the value of the next input * character, without advancing the read position. * * @returns * the next character, or -1 if the end of file has been reached. */ int peek() { int c = getch(); ungetc(c); return c; } /** * The keepalive method is used to set the SO_KEEPALIVE socket * option, if the file is a socket. Does nothing otherwise. */ virtual void keepalive(); /** * The pushback_transfer method is used by input filter classes' * destructors to return unused buffeered input. */ void pushback_transfer(input &from); /** * The pullback_transfer method is used by input filter classes' * destructors to return unused buffeered input. */ void pullback_transfer(input_ty *to); /** * The pullback_transfer method is used by input filter classes' * destructors to return unused buffeered input. */ void pullback_transfer(input &to); /** * The unread method may be used to reverse the effects of the read * method. The data is pushed into the buffer. Think of it as a * whole bunhs of ungetc calls (backwards). * * @param data * The base of the array of bytes to be returned. * @param nbytes * The number of bytes to be returned. */ void unread(const void *data, size_t nbytes); /** * The at_end method is used to determine whether or not * this input stream is at the end of input. */ bool at_end(); /** * The is_remote method is used to determine whether or not an * input stream is from a local file or a remote source. This is * only intended to be a generally informative thing, to provide * information to the user, it isn't (and can't be) utterly * precise. */ virtual bool is_remote() const; void reference_count_up(); void reference_count_down(); bool reference_count_valid() const { return (reference_count >= 1); } protected: /** * The read_inner method is used to read unbuffered data from the * given input stream. At most \a nbytes bytes will be read into * \a data. The number of bytes actually read will be returned. * At end-of-file, a value <= 0 will be returned, and \a data will * be unchanged. All file read errors or format errors are fatal, * and will cause the method to not return. * * @param data * Where to put the results of the read. * @param nbytes * The maximum number of bytes to read. * @returns * The actual number of bytes read, or zero for end-of-file. */ virtual long read_inner(void *data, size_t nbytes) = 0; /** * The ftell_inner method is used to determine the unbuffered * current position within the input. */ virtual long ftell_inner() = 0; /** * The getc_complicated method is used to get a character from the * input. Usually users do not call this method directly, but * use the getch method instead. */ int getc_complicated(); /** * The ungetc_complicated method is used to push a character back * onto an input. Usually users do not call this method directly, * but use the input_ungetc macro instead. */ void ungetc_complicated(int c); private: long reference_count; /** * The buffer instance variable is used to remember the base of * a dynamically allocated array used to buffer the data for * buffered input. */ unsigned char *buffer; /** * The buffer_size instance variable is used to remember the * allocation size of the dynamically allocated buffer. */ size_t buffer_size; /** * The buffer_position instance variable is used to remember the * read position of the data within the buffer. */ unsigned char *buffer_position; /** * The buffer_end instance variable is used to remember the * highwater mark of data stored in the buffer. */ unsigned char *buffer_end; }; inline DEPRECATED string_ty * input_name(input_ty *ip) { return ip->name().get_ref(); } inline DEPRECATED void input_delete(input_ty *ip) { ip->reference_count_down(); } inline DEPRECATED int input_getc(input_ty *ip) { return ip->getch(); } inline DEPRECATED void input_ungetc(input_ty *ip, int c) { ip->ungetc(c); } inline DEPRECATED long input_length(input_ty *ip) { return ip->length(); } inline DEPRECATED long input_read(input_ty *ip, void *data, size_t nbytes) { return ip->read(data, nbytes); } inline DEPRECATED void input_fatal_error(input_ty *ip, const char *msg) { ip->fatal_error(msg); } /** * The input class is a so-called smart pointer, which automatically * keeps track of input usage, and deletes the instance once the last * consumer has let it go. */ class input { friend class input_ty; public: /** * The destructor. * * @note * This destructor is not virtual. * DO NOT derive from this class. */ ~input(); /** * The default constructor. * * This is dangerous. The reference will be NULL, so if you try to * dereference it the code will segfault. */ input(); /** * The constructor. * * @param arg * The input stream to be managed. * Its reference count will NOT be incrimented, it is assumed * you are giving the "dumb" pointer to this "smart pointer" to * manage. */ input(input_ty *arg); /** * The copy constructor. */ input(const input &arg); /** * The assignment operator. */ input &operator=(const input &arg); #if 0 /** * The assignment operator. * * @param arg * The input stream to be managed. Its reference count will * NOT be incrimented, it is assumed you are giving the "dumb" * pointer to this "smart pointer" to manage. */ input &operator=(input *arg); #endif /** * The member operator. * * This is why it's called a "smart pointer" when it is actually * neither. Because we return a pointer to the referenced input_ty * object, this class presents what appears to be the same * interface as input_ty to the interface user. */ input_ty *operator->() { return ref; } /** * The member operator. * * This is why it's called a "smart pointer" when it is actually * neither. Because we return a pointer to the referenced input_ty * object, this class presents what appears to be the same * interface as input_ty to the interface user. */ const input_ty *operator->() const { return ref; } /** * The close method may be used to delete (actually, decriment * the reference count and conditionally delete) the managed * input_ty object. Acess to this smart pointer will hereafter get * segfaults until another input is assigned to it. */ void close(); /** * The is_open method may be used to determine if this "smart * pointer" is actuallyt pointing at something. This is an input * source so the open/closed metaphore works for us. */ bool is_open() const { return (ref != 0); } /** * The valid method is used (when debugging) to determine if this * object is in a valid state. */ bool valid() const; private: /** * The ref instance variable is used to remember the location of * the dynamically allocated input object. */ input_ty *ref; }; #endif // LIBAEGIS_INPUT_H