#ifndef ALREADY_INCLUDED_IO_HH
#define ALREADY_INCLUDED_IO_HH
#include "../noallegro/my-allegro.hh"
#include "string.hh"
#ifndef PRINT
#define PRINT(x) \
do { cout << #x << " = " << (x) << endl; } while (false)
#endif
#ifndef PRINT_LINE
#define PRINT_LINE(x) \
do { cout << "----------------------------------------\n"; } while (false)
#endif
#ifndef TELL
#define TELL(x) \
do { cout << "* COMMAND: " << #x << endl; x; } while (false)
#endif
#ifndef END_OF_MAIN
#define END_OF_MAIN
#endif END_OF_MAIN
inline bool strings_equal(const char* s1, const char* s2)
{
if ((s1 == null) && (s2 == null)) {
return true;
} else if ((s1 == null) || (s2 == null)) {
return false;
} else {
return (0 == strcmp(s1,s2));
}
}
ABSTRACT class Writer
{
public:
virtual ~Writer() {}
private:
virtual void write(char ch) = null;
virtual void write(int i) = null;
virtual void write(double d) = null;
virtual void write(const char* s) = null;
virtual string get_file_name() = null;
public:
Writer& operator << (char ch) { this->write(ch); return *this; }
Writer& operator << (int i) { this->write(i); return *this; }
Writer& operator << (double d) { this->write(d); return *this; }
Writer& operator << (const char* s) { this->write(s); return *this; }
Writer& operator << (const string& s) { this->write(s.const_char_star()); return *this; }
};
class File_Writer : public Writer
{
private:
FILE* f;
bool ours_to_close;
string file_name;
public:
File_Writer(string file_name)
{
this->f = fopen(file_name.const_char_star(),"wb");
ASSERT(f != null);
this->ours_to_close = true;
this->file_name = file_name;
}
File_Writer(FILE* f)
{
ASSERT(f != null);
this->f = f;
this->ours_to_close = false;
this->file_name = "<FILE>";
}
~File_Writer()
{
if (ours_to_close) {
fclose(f);
}
}
public:
File_Writer& operator << (char ch) { fprintf(this->f,"%c",ch); return *this; }
File_Writer& operator << (int i) { fprintf(this->f,"%d",i); return *this; }
File_Writer& operator << (double d) { fprintf(this->f,"%g",d); return *this; }
File_Writer& operator << (const char* s) { fprintf(this->f,"%s",s); return *this; }
File_Writer& operator << (const string& s) { *this << s.const_char_star(); return *this; }
string get_file_name()
{
return file_name;
}
private:
virtual void write(char ch) { *this << ch; }
virtual void write(int i) { *this << i; }
virtual void write(double d) { *this << d; }
virtual void write(const char* s) { *this << s; }
};
extern File_Writer cout;
extern File_Writer cerr;
const char endl = '\n';
class string_buffer : public string, public Writer
{
public:
string_buffer() {}
void set_char_at(int i, char ch);
string_buffer& operator << (char ch);
string_buffer& operator << (int i);
string_buffer& operator << (double d);
string_buffer& operator << (const char* s);
string_buffer& operator << (const string& s) { *this << s.const_char_star(); return *this; }
string get_file_name()
{
return "<string_buffer>";
}
private:
virtual void write(char ch) { *this << ch; }
virtual void write(int i) { *this << i; }
virtual void write(double d) { *this << d; }
virtual void write(const char* s) { *this << s; }
};
class string_buffer2 : public string_buffer
{
private:
string_buffer2() {}
public:
friend string_buffer2 operator + (const string& a, const string& b)
{
string_buffer2 result;
result << a;
result << b;
return result;
}
friend string_buffer2 operator + (const string& a, const char ch)
{
string_buffer2 result;
result << a;
result << ch;
return result;
}
friend string_buffer2 operator + (const string& a, const int i)
{
string_buffer2 result;
result << a;
result << i;
return result;
}
friend string_buffer2 operator + (const string& a, const double d)
{
string_buffer2 result;
result << a;
result << d;
return result;
}
friend string_buffer2 operator + (const string& a, const char* s)
{
string_buffer2 result;
result << a;
result << s;
return result;
}
friend string_buffer2& operator + (const string_buffer2& csb, const string& s)
{
string_buffer2& sb = const_cast<string_buffer2&>(csb);
sb << s;
return sb;
}
friend string_buffer2& operator + (const string_buffer2& csb, char ch)
{
string_buffer2& sb = const_cast<string_buffer2&>(csb);
sb << ch;
return sb;
}
friend string_buffer2& operator + (const string_buffer2& csb, int i)
{
string_buffer2& sb = const_cast<string_buffer2&>(csb);
sb << i;
return sb;
}
friend string_buffer2& operator + (const string_buffer2& csb, double d)
{
string_buffer2& sb = const_cast<string_buffer2&>(csb);
sb << d;
return sb;
}
friend string_buffer2& operator + (const string_buffer2& csb, const char* s)
{
string_buffer2& sb = const_cast<string_buffer2&>(csb);
sb << s;
return sb;
}
};
template<class T>
string to_string(const T* t)
{
string_buffer sb;
if (t == null) {
sb << "null";
} else {
sb << *t;
}
return sb;
}
ABSTRACT class Gulper
{
protected:
string file_name;
int file_line;
int current_char;
public:
Gulper(string file_name)
{
this->file_name = file_name;
this->file_line = 1;
this->current_char = EOF;
}
virtual ~Gulper()
{
}
string get_file_name()
{
return file_name;
}
int get_file_line()
{
return file_line;
}
int get_current_char()
{
return current_char;
}
virtual void gulp_char() = null;
};
class File_Gulper : public Gulper
{
private:
FILE* f;
bool saw_line_end;
public:
File_Gulper(string file_name);
~File_Gulper()
{
fclose(f);
}
virtual void gulp_char();
};
class String_Gulper : public Gulper
{
private:
string internal;
int index;
bool saw_line_end;
public:
String_Gulper(string internal);
~String_Gulper()
{
}
virtual void gulp_char();
};
ABSTRACT class Reader_Core
{
private:
enum Return_Values {
Type_Char = 1, Type_Int, Type_Double, Type_Ident, Type_String, Type_Eof
};
char last_char;
int last_int;
double last_double;
string last_ident;
string last_string;
bool last_bool;
Gulper* gulper;
Return_Values current_type;
void skip_whitespace();
int scan_int();
double scan_fraction();
string scan_identifier();
string scan_quoted_string();
void wrong_type(string tname);
virtual void pure_virtual_not_used() = null;
public:
bool currently_char() { return current_type == Type_Char; }
bool currently_int() { return current_type == Type_Int; }
bool currently_double() { return current_type == Type_Double; }
bool currently_identifier() { return current_type == Type_Ident; }
bool currently_string() { return current_type == Type_String; }
bool currently_eof() { return current_type == Type_Eof; }
char peek_char()
{ if (current_type != Type_Char) wrong_type("char"); return last_char; }
int peek_int()
{ if (current_type != Type_Int) wrong_type("int"); return last_int; }
double peek_double()
{ if (current_type != Type_Double) wrong_type("double"); return last_double; }
string peek_identifier()
{ if (current_type != Type_Ident) wrong_type("identifier"); return last_ident; }
string peek_string()
{ if (current_type != Type_String) wrong_type("string"); return last_string; }
void next_token();
int get_file_line() { return gulper->get_file_line(); }
string get_file_name() { return gulper->get_file_name(); }
void error_and_halt(string s);
string debug_say_symbol();
protected:
Reader_Core(Gulper* gulper)
{
this->gulper = gulper;
this->last_char = 0;
this->last_int = 0;
this->last_double = 0;
this->last_ident = "";
this->last_string = "";
next_token();
}
virtual ~Reader_Core()
{
delete gulper;
}
};
ABSTRACT class Reader : public Reader_Core
{
protected:
Reader(Gulper* gulper) : Reader_Core(gulper)
{
}
public:
virtual ~Reader()
{
}
public:
bool looking_at(char ch) {
if (ch != '(' && ch != ')' && ch != '\'') {
const char* error_message = "Reader::looking_at must be given one of '(',')','\\''";
#ifdef ALLEGRO_MESSAGE_AND_EXIT
ALLEGRO_MESSAGE_AND_EXIT((error_message));
#else
printf(error_message);
exit(EXIT_FAILURE);
#endif
}
return (currently_char() && peek_char() == ch); }
bool looking_at(string s) { return (currently_identifier() && peek_identifier().equals(s)); }
friend Reader& operator >> (Reader& r, const char& ch);
friend Reader& operator >> (Reader& r, const char* s);
friend Reader& operator >> (Reader& r, char& ch);
friend Reader& operator >> (Reader& r, int& i);
friend Reader& operator >> (Reader& r, double& d);
friend Reader& operator >> (Reader& r, string& s);
string gulp_quoted_string();
};
class File_Reader : public Reader
{
public:
File_Reader(string file_name) : Reader(new File_Gulper(file_name))
{
}
virtual void pure_virtual_not_used()
{
ASSERT(false);
}
};
class String_Reader : public Reader
{
public:
String_Reader(string readme) : Reader(new String_Gulper(readme))
{
}
virtual void pure_virtual_not_used()
{
ASSERT(false);
}
};
#include "temp-blit.hh"
#include "safe-allegro.hh"
#endif