/** \file G3D/TextOutput.h \maintainer Morgan McGuire, http://graphics.cs.williams.edu \created 2004-06-21 \edited 2011-05-24 Copyright 2000-2012, Morgan McGuire. All rights reserved. */ #ifndef G3D_TextOutput_h #define G3D_TextOutput_h #include "G3D/platform.h" #include "G3D/Array.h" #include namespace G3D { /** Convenient formatting of ASCII text written to a file.

The core writeString, writeNumber, and writeSymbol methods map to TextInput's methods. Number and Symbol each print an additional space that is used to separate adjacent tokens. TextOutput::printf allows arbitrary text to be conveniently dumped en-masse. Use [de]serialize(bool, TextOutput) and other overloads to read/write primitive types in a standardized manner and

When a word-wrap line break occurs, all whitespace between words is replaced with a single newline (the newline may be two characters-- see G3D::TextOutput::Options::NewlineStyle). Word wrapping occurs against the number of columns specified by Options::numColumns, minus the current indent level. Indenting adds the specified number of spaces immediately after a newline. If a newline was followed by spaces in the original string, these are added to the indent spaces. Indenting will indent blank lines and will leave indents after the last newline of a file (if the indent level is non-zero at the end).

Serialization/Marshalling

Text serialization is accomplished using TextOutput by defining the pair of methods:
  void serialize(TextOutput& to) const;
  void deserialize(TextInput& ti);
  
See also G3D::TextInput.

BETA API

This API is subject to change in future versions. */ class TextOutput { public: class Settings { public: /** WRAP_NONE Word wrapping is disabled WRAP_WITHOUT_BREAKING Word-wrap, but don't break continuous lines that are longer than numColumns (default) WRAP_ALWAYS Wrap even if it means breaking a continuous line or a quoted string. Word wrapping is only allowed at whitespaces ('\\n', '\\r', '\\t', ' '); it will not occur after commas, punctuation, minus signs, or any other characters */ enum WordWrapMode {WRAP_NONE, WRAP_WITHOUT_BREAKING, WRAP_ALWAYS}; /** Defaults to WRAP_WITHOUT_BREAKING */ WordWrapMode wordWrap; /** Is word-wrapping allowed to insert newlines inside double quotes? Default: false */ bool allowWordWrapInsideDoubleQuotes; /** Number of columns for word wrapping. Default: 8 */ int numColumns; /** Number of spaces in each indent. Default: 4 */ int spacesPerIndent; /** Style of newline used by word wrapping and by (optional) conversion. default: Windows: NEWLINE_WINDOWS, Linux, OS X: NEWLINE_UNIX. */ enum NewlineStyle {NEWLINE_WINDOWS, NEWLINE_UNIX}; NewlineStyle newlineStyle; /** If true, all newlines are converted to NewlineStyle regardless of how they start out. Default: true. */ bool convertNewlines; /** Used by writeBoolean */ std::string trueSymbol; /** Used by writeBoolean */ std::string falseSymbol; Settings() : wordWrap(WRAP_WITHOUT_BREAKING), allowWordWrapInsideDoubleQuotes(false), numColumns(80), spacesPerIndent(4), convertNewlines(true), trueSymbol("true"), falseSymbol("false") { #ifdef G3D_WINDOWS newlineStyle = NEWLINE_WINDOWS; #else newlineStyle = NEWLINE_UNIX; #endif } }; private: /** Used by indentAndAppend to tell when we are writing the first character of a new line. So that push/popIndent work correctly, we cannot indent immediately after writing a newline. Instead we must indent on writing the first character after that newline. */ bool startingNewLine; /** Number of characters at the end of the buffer since the last newline */ int currentColumn; /** True if we have seen an open " and no close ".*/ bool inDQuote; /** Empty if there is none */ std::string filename; Array data; Settings option; /** Number of indents to prepend before each line. Always set using setIndentLevel.*/ int indentLevel; void setIndentLevel(int i); /** Actual number of spaces to indent. */ int indentSpaces; /** the newline character(s) */ std::string newline; /** Starts at 1 */ int m_currentLine; void setOptions(const Settings& _opt); /** Converts to the desired newlines. Called from vprintf */ void convertNewlines(const std::string& in, std::string& out); /** Called from vprintf */ void wordWrapIndentAppend(const std::string& str); /** Appends the character to data, indenting whenever a newline is encountered. Called from wordWrapIndentAppend */ void indentAppend(char c); public: explicit TextOutput(const std::string& filename, const Settings& options = Settings()); /** Constructs a text output that can later be commited to a string instead of a file.*/ explicit TextOutput(const Settings& options = Settings()); /** Returns one plus the number of newlines written since the output was created. */ int line() const { return m_currentLine; } /** Commit to the filename specified on the constructor. Not called from the destructor; you must call it yourself. @param flush If true (default) the file is ready for reading when the method returns, otherwise the method returns immediately and writes the file in the background.*/ void commit(bool flush = true); /** Commits to this string */ void commitString(std::string& string); /** Increase indent level by 1 */ void pushIndent(); void popIndent(); /** Produces a new string that contains the output */ std::string commitString(); /** Writes a quoted string. Special characters in the string (e.g., \\, \\t, \\n) are escaped so that TextInput will produce the identical string on reading.*/ void writeString(const std::string& string); void writeBoolean(bool b); void writeNumber(double n); void writeNumber(int n); void writeNewline(); void writeNewlines(int numLines); /** If the most recently written character was a space, remove it and return true. Can be called repeatedly to back up over multiple spaces. */ bool deleteSpace(); /** The symbol is written without quotes. Symbols are required to begin with a letter or underscore and contain only letters, underscores, and numbers or be a C++ symbol (e.g. "{", "(", "++", etc.) so that they may be properly parsed by TextInput::readSymbol. Symbols are printed with a trailing space.*/ void writeSymbol(const std::string& string); void writeSymbol(char s); /** Convenient idiom for writing multiple symbols in a row, e.g. writeSymbols("name", "="); The empty symbols are not written. */ void writeSymbols( const std::string& a, const std::string& b = "", const std::string& c = "", const std::string& d = "", const std::string& e = "", const std::string& f = ""); /** Normal printf conventions. Note that the output will be reformatted for word-wrapping and newlines */ void __cdecl printf(const char* fmt, ...) G3D_CHECK_PRINTF_METHOD_ARGS; // Can't pass by reference because that confuses va_start void __cdecl printf(const std::string fmt, ...); void __cdecl vprintf(const char* fmt, va_list argPtr) G3D_CHECK_VPRINTF_METHOD_ARGS; }; // Primitive serializers void serialize(const bool& b, TextOutput& to); void serialize(const int& b, TextOutput& to); void serialize(const uint8& b, TextOutput& to); void serialize(const double& b, TextOutput& to); void serialize(const float& b, TextOutput& to); void serialize(const std::string& b, TextOutput& to); void serialize(const char* b, TextOutput& to); } #endif