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