Added a File type that wraps around QFile and provides stuff like a null file and range-for-iterating

Fri, 14 Jun 2013 19:34:30 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Fri, 14 Jun 2013 19:34:30 +0300
changeset 287
3fcccd8c3357
parent 286
7a562bf3d829
child 288
2980d7fd948e

Added a File type that wraps around QFile and provides stuff like a null file and range-for-iterating

src/common.h file | annotate | diff | comparison | revisions
src/config.cpp file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/types.cpp file | annotate | diff | comparison | revisions
src/types.h file | annotate | diff | comparison | revisions
--- a/src/common.h	Fri Jun 14 16:00:54 2013 +0300
+++ b/src/common.h	Fri Jun 14 19:34:30 2013 +0300
@@ -59,9 +59,8 @@
 # define devf(...)
 #endif // RELEASE
 
-class QFile;
-extern QFile g_file_stdout;
-extern QFile g_file_stderr;
+extern File g_file_stdout;
+extern File g_file_stderr;
 
 void doDevf (const char* func, const char* fmtstr, ...);
 
@@ -149,10 +148,10 @@
 #define fprint(F, ...) doPrint (F, {__VA_ARGS__})
 #else
 void print (const char* fmtstr, ...);
-void fprint (QFile& f, const char* fmtstr, ...);
+void fprint (File& f, const char* fmtstr, ...);
 #endif
-void doPrint (QFile& f, initlist<StringFormatArg> args);
-void doPrint (FILE* f, initlist<StringFormatArg> args);
+void doPrint (File& f, initlist<StringFormatArg> args);
+void doPrint (FILE* f, initlist<StringFormatArg> args); // heh
 
 // Replace assert with a version that shows a GUI dialog if possible
 #ifdef assert
@@ -168,9 +167,6 @@
 #define fatal(MSG) \
 	fatalError (__FILE__, __LINE__, FUNCNAME, MSG)
 
-// Null pointer
-static const std::nullptr_t null = nullptr;
-
 // Main and edge color identifiers
 static const short maincolor = 16;
 static const short edgecolor = 24;
--- a/src/config.cpp	Fri Jun 14 16:00:54 2013 +0300
+++ b/src/config.cpp	Fri Jun 14 19:34:30 2013 +0300
@@ -46,16 +46,14 @@
 	// Locale must be disabled for atof
 	setlocale (LC_NUMERIC, "C");
 	
-	QFile f (filepath ());
-	if (!f.open (QIODevice::ReadOnly))
+	File f (filepath (), File::Read);
+	if (!f)
 		return false;
 	
-	QTextStream input (&f);
 	size_t ln = 0;
 	
 	// Read the values.
-	while (!input.atEnd ()) {
-		str line = input.readLine ().simplified ();
+	for (str line : f) {
 		ln++;
 		
 		if (line.isEmpty () || line[0] == '#')
@@ -141,10 +139,10 @@
 		}
 	}
 	
-	QFile f (filepath ());
-	print ("writing cfg to %1\n", qchars (filepath ()));
+	File f (filepath (), File::Write);
+	print ("writing cfg to %1\n", filepath ());
 	
-	if (!f.open (QIODevice::WriteOnly)) {
+	if (!f) {
 		critical (fmt ("Cannot save configuration, cannot open %1 for writing\n", filepath ()));
 		return false;
 	}
--- a/src/main.cpp	Fri Jun 14 16:00:54 2013 +0300
+++ b/src/main.cpp	Fri Jun 14 19:34:30 2013 +0300
@@ -20,6 +20,7 @@
 #include <QMessageBox>
 #include <QAbstractButton>
 #include <qfile.h>
+#include <QTextStream>
 #include "gui.h"
 #include "file.h"
 #include "bbox.h"
@@ -33,14 +34,15 @@
 ForgeWindow* g_win = null; 
 bbox g_BBox;
 const QApplication* g_app = null;
-QFile g_file_stdout, g_file_stderr;
+File g_file_stdout (stdout, File::Write);
+File g_file_stderr (stderr, File::Write);
 
 const vertex g_origin (0.0f, 0.0f, 0.0f);
 const matrix g_identity ({1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f});
 
-void doPrint (QFile& f, initlist<StringFormatArg> args) {
+void doPrint (File& f, initlist<StringFormatArg> args) {
 	str msg = DoFormat (args);
-	f.write (msg.toUtf8 (), msg.length ());
+	f.write (msg.toUtf8 ());
 	f.flush ();
 }
 
@@ -57,12 +59,9 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 int main (int argc, char* argv[]) {
-	g_file_stdout.open (stdout, QIODevice::WriteOnly);
-	g_file_stderr.open (stderr, QIODevice::WriteOnly);
-	
 	const QApplication app (argc, argv);
 	g_app = &app;
-	g_curfile = NULL;
+	g_curfile = null;
 	
 	// Load or create the configuration
 	if (!config::load ()) {
--- a/src/types.cpp	Fri Jun 14 16:00:54 2013 +0300
+++ b/src/types.cpp	Fri Jun 14 19:34:30 2013 +0300
@@ -18,11 +18,15 @@
 
 #include <QObject>
 #include <QStringList>
+#include <QTextStream>
+#include <qfile.h>
 #include <assert.h>
 #include "common.h"
 #include "types.h"
 #include "misc.h"
 
+const File nullfile (null);
+
 str DoFormat (vector<StringFormatArg> args) {
 	assert (args.size () >= 1);
 	str text = args[0].value ();
@@ -269,4 +273,126 @@
 
 StringFormatArg::StringFormatArg (const floatconfig& v) {
 	m_val.number (v.value);
+}
+
+// =============================================================================
+File::File (const std::nullptr_t&) {
+	// Make a null file
+	m_file = null;
+	m_textstream = null;
+}
+
+File::File (str path, OpenType rtype) {
+	m_file = null;
+	open (path, rtype);
+}
+
+File::File (FILE* fp, OpenType rtype) {
+	m_file = null;
+	open (fp, rtype);
+}
+
+File::~File () {
+	if (m_file) {
+		m_file->close ();
+		delete m_file;
+		
+		if (m_textstream)
+			delete m_textstream;
+	}
+}
+
+bool File::open (FILE* fp, OpenType rtype) {
+	return open ("", rtype, fp);
+}
+
+bool File::open (str path, OpenType rtype, FILE* fp) {
+	close ();
+	
+	if (!m_file)
+		m_file = new QFile;
+	
+	m_file->setFileName (path);
+	
+	bool result;
+	
+	QIODevice::OpenMode mode =
+		(rtype == Read) ? QIODevice::ReadOnly :
+		(rtype == Write) ? QIODevice::WriteOnly :
+		QIODevice::Append;
+	
+	if (fp)
+		result = m_file->open (fp, mode);
+	else
+		result = m_file->open (mode);
+	
+	if (result) {
+		m_textstream = new QTextStream (m_file);
+		return true;
+	}
+	
+	delete m_file;
+	m_file = null;
+	return false;
+}
+
+File::iterator File::begin() {
+	return iterator (this);
+}
+
+File::iterator& File::end () {
+	return m_endIterator;
+}
+
+void File::write (str msg) {
+	m_file->write (msg.toUtf8 (), msg.length ());
+}
+
+str File::readLine () {
+	return m_textstream->readLine ();
+}
+
+bool File::atEnd () const {
+	 return m_textstream->atEnd ();
+}
+
+bool File::isNull () const {
+	return m_file == null;
+}
+
+bool File::operator!() const {
+	return isNull ();
+}
+
+void File::close () {
+	if (!m_file)
+		return;
+	
+	delete m_file;
+	m_file = null;
+	
+	if (m_textstream) {
+		delete m_textstream;
+		m_textstream = null;
+	}
+}
+
+bool File::flush () {
+	return m_file->flush ();
+}
+
+void File::iterator::operator++() {
+	m_text = m_file->readLine ();
+}
+
+str File::iterator::operator*() {
+	return m_text;
+}
+
+bool File::iterator::operator== (File::iterator& other) {
+	return (other.m_file == null && m_file->atEnd ());
+}
+
+bool File::iterator::operator!= (File::iterator& other) {
+	return !operator== (other);
 }
\ No newline at end of file
--- a/src/types.h	Fri Jun 14 16:00:54 2013 +0300
+++ b/src/types.h	Fri Jun 14 19:34:30 2013 +0300
@@ -23,6 +23,9 @@
 #include <vector>
 #include "common.h"
 
+// Null pointer
+static const std::nullptr_t null = nullptr;
+
 typedef QChar qchar;
 typedef QString str;
 template<class T> class ConstVectorReverser;
@@ -30,6 +33,8 @@
 class strconfig;
 class intconfig;
 class floatconfig;
+class QFile;
+class QTextStream;
 
 typedef unsigned int uint;
 typedef unsigned short ushort;
@@ -125,13 +130,12 @@
 	double m_coords[3];
 };
 
-
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 // vector
 // 
-// Array class that wraps around vector
+// Array class that wraps around std::vector
 // =============================================================================
 template<class T> class vector {
 public:
@@ -277,6 +281,13 @@
 	std::vector<T> m_vect;
 };
 
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+// VectorReverser (aka rev)
+// 
+// Helper class used to reverse-iterate vectors in range-for-loops.
+// =============================================================================
 template<class T> class VectorReverser {
 public:
 	typedef typename vector<T>::r_it it;
@@ -297,6 +308,13 @@
 	vector<T>* m_vect;
 };
 
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+// ConstVectorReverser (aka c_rev)
+// 
+// Like VectorReverser, except works on const vectors.
+// =============================================================================
 template<class T> class ConstVectorReverser {
 public:
 	typedef typename vector<T>::cr_it it;
@@ -321,6 +339,13 @@
 template<class T> using c_rev = ConstVectorReverser<T>;
 
 // =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+// StringFormatArg
+// 
+// Converts a given value into a string that can be retrieved with ::value ().
+// Used as the argument type to the formatting functions, hence its name.
+// =============================================================================
 class StringFormatArg {
 public:
 	StringFormatArg (const str& v);
@@ -356,11 +381,68 @@
 	str m_val;
 };
 
-str DoFormat (vector< StringFormatArg > args);
+// Formatter function
+str DoFormat (vector<StringFormatArg> args);
 #ifndef IN_IDE_PARSER
 #define fmt(...) DoFormat ({__VA_ARGS__})
 #else
 str fmt (const char* fmtstr, ...);
 #endif
 
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+// File
+// 
+// A file interface with simple interface and support for range-for-loops.
+// =============================================================================
+class File {
+public:
+	// Iterator class to enable range-for-loop support. Rough hack.. don't use directly!
+	class iterator {
+	public:
+		iterator () : m_file (null) {} // end iterator has m_file == null
+		iterator (File* f) : m_file (f), m_text (m_file->readLine ()) {}
+		void operator++ ();
+		str  operator* ();
+		bool operator== (iterator& other);
+		bool operator!= (iterator& other);
+	
+	private:
+		File* m_file;
+		str m_text;
+	};
+	
+	enum OpenType {
+		Read,
+		Write,
+		Append
+	};
+	
+	File (const std::nullptr_t&);
+	File (str path, File::OpenType rtype);
+	File (FILE* fp, File::OpenType rtype);
+	~File ();
+	
+	bool         atEnd         () const;
+	iterator     begin         ();
+	void         close         ();
+	iterator&    end           ();
+	bool         flush         ();
+	bool         isNull        () const;
+	str          readLine      ();
+	bool         open          (FILE* fp, OpenType rtype);
+	bool         open          (str path, OpenType rtype, FILE* fp = null);
+	bool         operator!     () const;
+	void         write         (str msg);
+	
+private:
+	QFile*       m_file;
+	QTextStream* m_textstream;
+	iterator     m_endIterator;
+};
+
+// Null-file, equivalent to a null FILE*
+extern const File nullfile;
+
 #endif // TYPES_H
\ No newline at end of file

mercurial