#ifndef LINE_HH /* * Name: Geoff Kuenning * Course: CS 70, Fall 2000 * Assignment #5 * * This file defines the interface to the LineGetter and Line classes. * * The LineGetter class provides a simple facility for getting Lines * from a file. The Line class stores and manipulates lines of * information that (might) have been read from a text file. Both * classes are very simple class, so simple that they probably * wouldn't be used in a non-instructional setting. In addition, Line * duplicates some of the functionality of the STL string class. */ /* * Since the LineGetter class refers to cin, we must include iostream * to get the definition of that stream. Otherwise, we could just * list istream and ostream in the "used but not defined" section. */ #include /* * Table of Contents: the following classes are defined in this file. */ class LineGetter; class Line; /* * The following classes are used but not defined in this file. */ // (none) /* * The LineGetter class. This class provides only a constructor, * destructor, and getLine function. The constructor automatically * attaches the LineGetter to a specified input stream. * * The heart of the class is the getLine function, which is a factory * function that produces Lines. Each time getLine is called, a line * is read from the input stream specified when the LineGetter was * constructed. (A "line" is defined as all characters up to the next * newline; the newline is swallowed as well.) The line that was read * is numbered and used to construct a Line, which is returned to the * caller. The Line is allocated with "new", and it is the caller's * responsibility to delete it later. * * When EOF is reached, getLine will return a NULL pointer to indicate * that fact. */ class LineGetter { public: /* * Standard functions */ explicit LineGetter(istream& fromStream_ = cin); // Construction from a stream // ..also serves as default constructor // ..because a default value is given // ..for fromStream, so it can be // ..called with no arguments ~LineGetter(); /* * Factory functions */ const Line* getLine(); // Create and return a line private: /* * Disable copy and assignment. It doesn't make sense to copy * a LineGetter, because then if you got something from one * LineGetter, the other one would wind up with incorrect line * numbering. Disabling copy and assignment isn't perfect, * because somebody could still construct two LineGetters from * the same input stream, but it's better than nothing. There * are ways to make the LineGetter handle the problem of * multiple streams (and to allow copying and assignment), but * they would complicate the class a LOT. "Object-oriented * programming protects you from Murphy, not Machiavelli." */ LineGetter(const LineGetter& source); // Copy constructor const LineGetter& operator=(const LineGetter& source); // Copy-assignment operator /* * Private functions */ char* expand(char* oldString, unsigned int oldSize, unsigned int newSize) const; // Expand an array /* * Private data */ istream& fromStream; // Stream we take input from. unsigned int nextNumber; // Number of next line to read /* * Internal constants * * Note: g++ now insists on using "static const unsigned int". * Some older compilers don't like that construct, and instead * insist on using the enum. If your compiler complains about * "static const int", try changing the 1 to a 0 in the * following line. */ #if 1 static const unsigned int INITIAL_LENGTH = 16; // Initial length of a line, including // ..space for the NUL byte #else // 1 enum { INITIAL_LENGTH = 16 // Initial length of a line, including // ..space for the NUL byte }; #endif // 1 }; /* * The Line class. This class holds lines read from a file. As well * as the contents of the line (stored as a C-style string), it tracks * the line number and whether the line originally ended in a newline. * The newline is never stored internally, but it will be * reconstructed on output if necessary. * * Because the Line class is intended for instructional purposes, it * is very simple and doesn't provide very many functions. Besides * the constructors, destructor, and the copy-assignment operator, the * only function is a print routine that displays the line on a * stream. The print function can optionally prefix the line with its * line number, and can be told to print a newline after the line even * if it didn't originally end with a newline. (This latter option is * the default). */ class Line { /* * Friends * * LineGetter::getLine is a friend so that it can use a * special internal constructor that is not available to * outsiders. This is an example of encapsulation: by making * the internal constructor private, outsiders can't know how * the line number and newline status are stored, and can't * accidentally call the constructor with a string that wasn't * allocated by "new[]". */ friend const Line* LineGetter::getLine(); public: /* * Standard functions. There is also a private constructor, * listed below, for use by LineGetter::getLine(). */ Line(); // Default constructor Line(const Line& source); // Copy constructor ~Line(); const Line& operator=(const Line& source); // Copy-assignment operator /* * Other public functions */ ostream& print(ostream& stream, bool withNumber = false, bool forceNewline = true) const; // Print the line on a stream private: /* * Private constructor for use by LineGetter::getline */ Line(int lineNumber_, const char* contents_, bool hadNewline_); /* * Helper function that copies strings. This is identical to * the C library "strdup" function, except that it uses * "new[]" instead of "malloc". Most C++ libraries provide a * C++-style "strdup", but we will use our own anyway just in * case. */ static const char* duplicate(const char* source); // Create a duplicate of a string /* * Private data */ unsigned int lineNumber; // The line number in the source file const char* contents; // The actual contents of the line, // ..with the trailing newline // (if any) deleted bool hadNewline; // True if line ended with a newline // ..when we read it in }; #endif // LINE_HH