textio.hpp

    1: #ifndef TEXTIO_HPP
    2: #define TEXTIO_HPP
    3: /*------------------------------------------------------------------------------
    4: 
    5:   Author:    Andy Rushton
    6:   Copyright: (c) Andy Rushton, 2004
    7:   License:   BSD License, see ../docs/license.html
    8: 
    9:   ------------------------------------------------------------------------------*/
   10: #include "os_fixes.hpp"
   11: #include "format_types.hpp"
   12: #include <vector>
   13: #include <string>
   14: 
   15: ////////////////////////////////////////////////////////////////////////////////
   16: // Internals
   17: 
   18: class obuff;
   19: class otext;
   20: class ibuff;
   21: class itext;
   22: 
   23: ////////////////////////////////////////////////////////////////////////////////
   24: // Builtin error codes - you can add your own when you create a new derivative
   25: // buffer in which case you may wish to overload the error_string function of
   26: // the buffer to give a textual form to your errors.
   27: // All internal error codes are negative to differentiate them from system error codes.
   28: 
   29: extern const int textio_uninitialised;
   30: extern const int textio_put_failed;
   31: extern const int textio_format_error;
   32: extern const int textio_get_failed;
   33: extern const int textio_open_failed;
   34: 
   35: ////////////////////////////////////////////////////////////////////////////////
   36: // Text Output Device
   37: ////////////////////////////////////////////////////////////////////////////////
   38: 
   39: class otext
   40: {
   41: protected:
   42:   friend class obuff;
   43:   friend class itext;
   44:   obuff* m_buffer;
   45: 
   46: public:
   47:   ////////////////////////////////////////////////////////////////////////////////
   48:   // Local Types
   49:   // These local enumerations are in the otext namespace
   50: 
   51:   // Newline conversion
   52:   // The user of TextIO should always use '\n' for newlines, then TextIO will do the conversions
   53:   // default: native
   54:   // I appended the _mode suffix to avoid conflicts with macros
   55:   enum newline_t
   56:   {
   57:     binary_mode, // no end of line conversion
   58:     unix_mode,   // Unix conversions (LF)
   59:     msdos_mode,  // MS-DOS conversion (CR-LF)
   60:     macos_mode,  // MacOS conversion (CR)
   61:     // the mode of the platform you compiled this on
   62: #ifdef MSWINDOWS
   63:     native_mode = msdos_mode
   64: #else
   65:     native_mode = unix_mode
   66: #endif
   67:   };
   68:   friend std::string to_string(newline_t);
   69: 
   70:   // Open Mode
   71:   // only used for otext devices where the two modes make sense, e.g. files but not pipes
   72:   enum open_t
   73:   {
   74:     overwrite,  // destroy previous contents (default)
   75:     append      // append to previous contents
   76:   };
   77:   friend std::string to_string(open_t);
   78: 
   79:   // profile for function manipulators
   80:   typedef void (*manipulator_function)(otext&);
   81: 
   82:   ////////////////////////////////////////////////////////////////////////////////
   83:   // Member functions
   84: 
   85:   // create an uninitialised otext
   86:   otext(void);
   87: 
   88:   // create an initialised otext by attaching a buffer (any derivative of obuff)
   89:   otext(obuff*);
   90: 
   91:   // close the otext if its open by deleting the buffer (thus calling its destructor)
   92:   virtual ~otext(void);
   93: 
   94:   // test whether this otext has a buffer attached
   95:   bool initialised(void) const;
   96: 
   97:   // initialise otext by attaching a buffer (any derivative of obuff)
   98:   // if a buffer is already attached, delete it first
   99:   void open(obuff*);
  100: 
  101:   // close the otext if its open by deleting the buffer (thus calling its destructor)
  102:   void close(void);
  103: 
  104:   // copy and assign create aliases - no deep copy is available - no deep copy makes sense!
  105:   otext(const otext&);
  106:   otext& operator = (const otext&);
  107: 
  108:   // test the buffer's error function
  109:   bool error(void) const;
  110:   int error_number(void) const;
  111:   std::string error_string(void) const;
  112:   void set_error(int error);
  113:   void clear_error(void);
  114: 
  115:   // newline control
  116:   void set_newline_mode(newline_t newline = native_mode);
  117:   void set_unix_mode(void);
  118:   void set_msdos_mode(void);
  119:   void set_macos_mode(void);
  120:   void set_native_mode(void);
  121:   void set_binary_mode(void);
  122:   newline_t newline_mode(void) const;
  123:   bool is_unix_mode(void) const;
  124:   bool is_msdos_mode(void) const;
  125:   bool is_macos_mode(void) const;
  126:   bool is_native_mode(void) const;
  127:   bool is_binary_mode(void) const;
  128: 
  129:   // integer formatting control
  130:   void set_integer_width(unsigned width = 0);
  131:   unsigned integer_width(void) const;
  132:   void set_integer_radix(unsigned radix = 10);
  133:   unsigned integer_radix(void) const;
  134:   void set_integer_display(radix_display_t display = radix_c_style_or_hash);
  135:   radix_display_t integer_display(void) const;
  136: 
  137:   // floating-point formatting control
  138:   void set_real_width(unsigned width = 0);
  139:   unsigned real_width(void) const;
  140:   void set_real_precision(unsigned width = 6);
  141:   unsigned real_precision(void) const;
  142:   void set_real_display(real_display_t display = display_mixed);
  143:   real_display_t real_display(void) const;
  144: 
  145:   // low-level character write
  146:   // put writes a single character
  147:   // it is an error to put negative values, specifically EOF (-1)
  148:   // the character must be unsigned char, since otherwise there are two definitions of -1
  149:   bool put(int ch);
  150: 
  151:   // composite operations on strings (C and STL) which repeatly call the above
  152:   bool put(const char*);
  153:   bool put(const std::string&);
  154: 
  155:   // number of characters written through the otext member functions
  156:   unsigned long bytes(void) const;
  157:   // line and column for last character written
  158:   // this only really has meaning if you are using text conversion mode (i.e. not binary)
  159:   unsigned line(void) const;
  160:   unsigned column(void) const;
  161: 
  162:   // flush the buffer explicitly (for example to synchronise standard output with standard input)
  163:   void flush(void);
  164: 
  165:   // test whether the device is capable of accepting/not accepting output
  166:   operator bool (void) const;
  167:   bool operator ! (void) const;
  168: 
  169:   // the pipe operators << are the main functions used with otext and its derivates
  170:   // they are used in the form:
  171:   //   device << object1 << object2 << object3;
  172: 
  173:   // single character
  174:   // TODO - wide char
  175:   otext& operator << (char);
  176:   otext& operator << (signed char);
  177:   otext& operator << (unsigned char);
  178: 
  179:   // string output
  180:   otext& operator << (const char*);
  181:   otext& operator << (const std::string&);
  182: 
  183:   // string vector - writes whole array as a series of newline separated strings
  184:   otext& operator << (const std::vector<std::string>&);
  185: 
  186:   // integer output
  187:   otext& operator << (bool);
  188:   otext& operator << (short);
  189:   otext& operator << (unsigned short);
  190:   otext& operator << (int);
  191:   otext& operator << (unsigned int);
  192:   otext& operator << (long);
  193:   otext& operator << (unsigned long);
  194: 
  195:   // floating point output
  196:   otext& operator << (float);
  197:   otext& operator << (double);
  198: 
  199:   // pointer output, compatible with >> operator for void*;
  200:   otext& operator << (const void*);
  201: 
  202:   // manipulator - applies passed function to stream;
  203:   otext& operator << (manipulator_function);
  204: 
  205:   // pipe operator - pours one stream into the other until eof();
  206:   // this is an easy way to copy one device into another
  207:   otext& operator << (itext&);
  208: };
  209: 
  210: // redefine friends for gcc v4.1
  211: std::string to_string(otext::newline_t);
  212: std::string to_string(otext::open_t);
  213: 
  214: ////////////////////////////////////////////////////////////////////////////////
  215: // output manipulators, used in the form: fout << flush << endl;
  216: 
  217: // simply flush the buffer (if any)
  218: void flush(otext&);
  219: 
  220: // write a newline, iostream style
  221: void endl(otext&);
  222: 
  223: // close the device
  224: void close(otext&);
  225: 
  226: // set radix to hex/octal/decimal
  227: void hex(otext&);
  228: void oct(otext&);
  229: void dec(otext&);
  230: 
  231: // the following used to be manipulators, but for efficiency they are now defined as consts;
  232: const char newline = '\n';
  233: const char space = ' ';
  234: const char tab = '\t';
  235: const char null = '\0';
  236: 
  237: ////////////////////////////////////////////////////////////////////////////////
  238: // Text Input Device
  239: ////////////////////////////////////////////////////////////////////////////////
  240: 
  241: class itext
  242: {
  243: protected:
  244:   friend class otext;
  245:   friend class ibuff;
  246:   ibuff* m_buffer;
  247: 
  248: public:
  249:   ////////////////////////////////////////////////////////////////////////////////
  250:   // Newline conversion
  251:   // When conversion is on, all end-of-line conventions (LF, CR-LF, CR) will be converted into a '\n'
  252:   // When conversion is off, data comes in unmodified - note that this can make the eoln() test act strangely
  253:   enum newline_t
  254:   {
  255:     binary_mode,      // no end of line conversion
  256:     convert_mode      // recognise and convert all end-of-line conventions
  257:   };
  258:   friend std::string to_string(newline_t);
  259: 
  260:   typedef void (*manipulator_function)(itext&);
  261: 
  262: public:
  263:   // create an uninitialised itext
  264:   itext(void);
  265: 
  266:   // create an itext and initialise it with a buffer (any derivative of ibuff)
  267:   itext(ibuff*);
  268: 
  269:   // closes the itext if it is open and destroys any structures - including the buffer
  270:   virtual ~itext(void);
  271: 
  272:   // test whether the itext has a buffer attached
  273:   bool initialised(void) const;
  274: 
  275:   // attach a buffer (any derivative of ibuff)
  276:   void open(ibuff*);
  277: 
  278:   // detach the buffer and delete it (causing the destructor and therefore any closedown actions to be called)
  279:   void close(void);
  280: 
  281:   // copy and assignment create aliases - it is not sensible to allow a deep copy (think about it)
  282:   itext(const itext&);
  283:   itext& operator = (const itext&);
  284: 
  285:   // test the buffer's error flag or retrieve its value
  286:   bool error(void) const;
  287:   int error_number(void) const;
  288:   std::string error_string(void) const;
  289:   void set_error(int error);
  290:   void clear_error(void);
  291: 
  292:   // formatting control
  293:   void set_newline_mode(newline_t newline = convert_mode);
  294:   void set_convert_mode(void);
  295:   void set_binary_mode(void);
  296:   newline_t newline_mode(void) const;
  297:   bool is_convert_mode(void);
  298:   bool is_binary_mode(void);
  299: 
  300:   // test for the two special 'characters' end-of-file (-1) and end-of-line (\n) using peek()
  301:   bool eof(void);
  302:   bool eoln(void);
  303: 
  304:   // low-level character access - peek allows one character lookahead, get allows one character to be read
  305:   // Both return -1 to indicate EOF
  306:   int peek(void);
  307:   int get(void);
  308: 
  309:   // number of characters read through the itext member functions
  310:   unsigned long bytes(void) const;
  311:   // line and column for last character read
  312:   // this only really has meaning if you are using text conversion mode (i.e. not binary)
  313:   unsigned line(void) const;
  314:   unsigned column(void) const;
  315: 
  316:   // tests for whether an itext has/hasn't got text to be read
  317:   bool good (void);
  318:   operator bool (void);
  319:   bool operator ! (void);
  320: 
  321:   ////////////////////////////////////////////////////////////////////////////////
  322:   // input-pipe operators are the main usage of itext
  323:   // used in the form:
  324:   //    device >> object1 >> object2 >> object3;
  325:   // device is any derivative of itext, object is any type with a >> operator defined (you can overload)
  326: 
  327:   // just get next character, including any whitespace or end of line character;
  328:   itext& operator >> (char&);
  329:   itext& operator >> (signed char&);
  330:   itext& operator >> (unsigned char&);
  331: 
  332:   // skipwhite before reading then read until a whitespace is found
  333:   // this is a kind of tokenising operator
  334:   itext& operator >> (std::string&);
  335:   // gets the whole line
  336:   bool getline(std::string& line);
  337: 
  338:   // get the whole file as a vector of strings, using newlines to split the input
  339:   itext& operator >> (std::vector<std::string>&);
  340: 
  341:   // integer operations: skipwhite then read an integer in any of the recognised formats:
  342:   // decimal: 12345
  343:   // octal:   012345
  344:   // hex:     0x12345
  345:   // hash:    13#12345
  346:   itext& operator >> (bool&);
  347:   itext& operator >> (short&);
  348:   itext& operator >> (unsigned short&);
  349:   itext& operator >> (int&);
  350:   itext& operator >> (unsigned int&);
  351:   itext& operator >> (long&);
  352:   itext& operator >> (unsigned long&);
  353: 
  354:   // real operations, skipwhite then read floating-point number - fraction and exponent are optional
  355:   itext& operator >> (float&);
  356:   itext& operator >> (double&);
  357: 
  358:   // pointer operator, skipwhite, then reads a pointer written by << operator for void*
  359:   itext& operator >> (void*&);
  360: 
  361:   // manipulator - applies passed manipulator function to stream;
  362:   itext& operator >> (manipulator_function);
  363: 
  364:   // pipe operator - pours one stream into the other until eof();
  365:   // this is the easiest way to make a copy
  366:   itext& operator >> (otext&);
  367: };
  368: 
  369: // redefine friends for gcc v4.1
  370: std::string to_string(itext::newline_t);
  371: 
  372: // manipulators, used in the form: fin >> skipwhite >> ch
  373: 
  374: // skip all whitespace as defined by isspace() in <cctype>
  375: void skipwhite(itext&);
  376: 
  377: // skip up to one whitespace as defined by isspace() in <cctype>
  378: void skiponewhite(itext&);
  379: 
  380: // skip whitespace excluding end of line - i.e. only spacing characters
  381: void skipspaces(itext&);
  382: 
  383: // skip all text until and including the next end-of-line character
  384: void skipline(itext&);
  385: 
  386: // skip all whitespace, but stop after an end-of-line character
  387: void skipendl(itext&);
  388: 
  389: // close the device
  390: void close(itext&);
  391: 
  392: ////////////////////////////////////////////////////////////////////////////////
  393: // Internals
  394: ////////////////////////////////////////////////////////////////////////////////
  395: 
  396: // Output Buffer
  397: 
  398: class obuff
  399: {
  400: public:
  401:   // constructor initialises output buffer with the mode fields - line buffering mode and newline conversion mode
  402:   obuff(bool line_buffer = false, otext::newline_t newline = otext::native_mode);
  403: 
  404:   // Total number of characters written through put()
  405:   // also number of lines and column number of last byte written
  406:   // Note this may not correspond to the number of characters sent to otext due to newline conversion
  407:   void increment(bool newline = false);
  408:   unsigned long bytes(void) const;
  409:   unsigned line(void) const;
  410:   unsigned column(void) const;
  411: 
  412:   // get line buffering mode - the TextIO device calls flush on every newline when in line beffering mode
  413:   void set_line_buffer(bool mode);
  414:   bool line_buffer(void) const;
  415: 
  416:   // get newline handling mode - used by TextIO device to process CR/LF characters
  417:   void set_newline_mode(otext::newline_t newline);
  418:   otext::newline_t newline_mode(void) const;
  419: 
  420:   // Integer formatting fields
  421:   // field width for next formattable integer type, default: 0
  422:   unsigned integer_width(void) const;
  423:   void set_integer_width(unsigned);
  424:   // base for integer display - from 2-36, default: 10
  425:   unsigned integer_radix(void) const;
  426:   void set_integer_radix(unsigned);
  427:   // how to display an integer - see string_utilities, default: c_style_or_hash
  428:   radix_display_t integer_display(void) const;
  429:   void set_integer_display(radix_display_t);
  430: 
  431:   // Real formatting fields
  432:   // field width for next formattable real type, default: 0
  433:   unsigned real_width(void) const;
  434:   void set_real_width(unsigned);
  435:   // number of significant digits
  436:   unsigned real_precision(void) const;
  437:   void set_real_precision(unsigned);
  438:   // how to display a real - see string_utilities, default: display_mixed
  439:   real_display_t real_display(void) const;
  440:   void set_real_display(real_display_t);
  441: 
  442:   // Error number
  443:   // zero if there is no error, any integer for an error
  444:   // this may be any of the definitions defined in <errno.h> or any derivative specific number
  445:   // this is set by otext itself but may also be set in any of your own derivatives
  446:   void set_error(int error);
  447:   void clear_error(void);
  448:   int error_number(void) const;
  449:   virtual std::string error_string(void) const;
  450: 
  451:   // Customisation
  452:   // To create a new output buffer, derive from this and then customise the
  453:   // virtual functions. Also provide sensible constructors - for example FileIO
  454:   // would have a constructor taking a filename and open mode. You only HAVE to
  455:   // provide the abstract function put(char), all others are optional. These
  456:   // functions are implicitly called by the otext class which contains your
  457:   // buffer.
  458: 
  459:   // you should provide a destructor (also virtual) if your buffer needs closedown actions such as closing a file/pipe
  460: 
  461:   // the default flush does nothing
  462:   // use this to flush any internal buffer - not relevant if your device isn't buffered
  463:   // note that if you are buffering, you should not rely on flush being called explicitly when the buffer is full
  464:   // - you need to manage the buffer yourself
  465:   // flush is called from TextIO to synchronise devices e.g. stdin and stdout
  466:   // It will be called on every newline if the buffer is in line buffer mode
  467:   virtual void flush(void);
  468: 
  469:   // the only operation that you must provide
  470:   // sends a single character to the target device
  471:   // returns the number of characters written (0 or 1)
  472:   virtual unsigned put(unsigned char) = 0;
  473: 
  474:   // use this to do any mopping up required on closing a buffer
  475:   // the default destructor does nothing - overload this only if you need to
  476:   virtual ~obuff(void);
  477: 
  478: private:
  479:   // disallow copying
  480:   obuff& operator = (const obuff&);
  481:   obuff(const obuff&);
  482: 
  483: protected:
  484:   friend class otext;
  485:   bool m_line_buffer;
  486:   otext::newline_t m_newline;
  487:   unsigned long m_bytes;
  488:   unsigned m_line;
  489:   unsigned m_column;
  490:   unsigned m_integer_width;
  491:   unsigned m_integer_radix;
  492:   radix_display_t m_integer_display;
  493:   unsigned m_real_width;
  494:   unsigned m_real_precision;
  495:   real_display_t m_real_display;
  496:   int m_error_number;
  497:   int m_aliases;
  498: };
  499: 
  500: // Input Buffer
  501: 
  502: class ibuff
  503: {
  504: public:
  505:   ibuff(itext::newline_t newline = itext::convert_mode);
  506: 
  507:   // Total number of characters read through get()
  508:   // also number of lines and column number of last byte read
  509:   // Note this may not correspond to the number of characters read from the device due to newline conversion
  510:   void increment(bool newline = false);
  511:   unsigned long bytes(void) const;
  512:   unsigned line(void) const;
  513:   unsigned column(void) const;
  514: 
  515:   // get newline handling mode - used by TextIO device to process CR/LF characters
  516:   void set_newline_mode(itext::newline_t newline);
  517:   itext::newline_t newline_mode(void) const;
  518: 
  519:   // Error number
  520:   // zero if there is no error, any integer for an error
  521:   // this may be any of the errno definitions defined in <errno.h> or any derivative specific number
  522:   // this is set by itext itself but may also be set in any of your own derivatives
  523:   void set_error(int error);
  524:   void clear_error(void);
  525:   int error_number(void) const;
  526:   virtual std::string error_string(void) const;
  527: 
  528: 
  529:   // Customisation
  530:   // create a new buffer by customising the following functions
  531:   // you should also provide a destructor (also virtual) if your buffer needs closedown actions
  532:   // it REALLY IS as simple as that - see the existing derivatives for examples
  533: 
  534:   // peek and get are abstract functions, so you must provide them
  535:   // peek gets the next character without consuming it, get gets the same character but also consumes it
  536:   // this means that text input requires one-character lookahead
  537:   virtual int peek(void) = 0;
  538:   virtual int get(void) = 0;
  539: 
  540:   // do any mopping up and close the input
  541:   // default destructor does nothing
  542:   virtual ~ibuff(void);
  543: 
  544: private:
  545:   // disallow copying
  546:   ibuff& operator = (const ibuff&);
  547:   ibuff(const ibuff&);
  548: 
  549: protected:
  550:   friend class itext;
  551:   itext::newline_t m_newline_mode;
  552:   unsigned long m_bytes;
  553:   unsigned m_line;
  554:   unsigned m_column;
  555:   int m_error_number;
  556:   int m_aliases;
  557: };
  558: 
  559: ////////////////////////////////////////////////////////////////////////////////
  560: #endif