1
Files
lecture-operating-system-de…/c_os/lib/OutStream.h
2022-07-24 21:12:31 +02:00

245 lines
8.2 KiB
C++
Executable File

/*****************************************************************************
* *
* O U T S T R E A M *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Die Klasse OutStream enthaelt die Definition des *
* << Operators fuer die wichtigsten der vordefinierten *
* Datentypen und realisiert somit die bekannte Ausgabe- *
* funktion der C++ iO_Stream Bibliothek. Zur Zeit wird *
* die Darstellung von Zeichen, Zeichenketten und ganzen *
* Zahlen unterstuetzt. Ein weiterer << Operator erlaubt *
* die Verwendung von Manipulatoren. *
* *
* Neben der Klasse OutStream sind hier auch die *
* Manipulatoren hex, dec, oct und bin fuer die Wahl der *
* Basis bei der Zahlendarstellung, sowie endl fuer den *
* Zeilenumbruch definiert. *
* *
* Autor: Olaf Spinczyk, TU Dortmund *
* Aenderungen von Michael Schoettner, HHU, 06.04.20 *
*****************************************************************************/
#ifndef OutStream_include__
#define OutStream_include__
#include "lib/StringBuffer.h"
#include "user/lib/String.h"
// Some basic width formatting
class fillw {
public:
constexpr fillw(const unsigned int w) : w(w) {}
const unsigned int w;
};
class fillc {
public:
constexpr fillc(const char c) : c(c) {}
const char c;
};
class OutStream : public StringBuffer {
private:
// Some stream formatting
unsigned char fill_used; // indicates how many characters are already used by the text internally
unsigned char fill_width; // If input is shorter than fill_width fill remaining space up with fill_char
char fill_char; // fill character for fixed width
int base; // Basis des Zahlensystems: z.B. 2, 8, 10 oder 16
void fill_use_char(); // recognizes that one char from the print width has been used up
void fill_finalize(); // does the filling after text has been written to buffer
public:
OutStream(const OutStream& copy) = delete; // Verhindere Kopieren
OutStream() : fill_used(0), fill_width(0), fill_char(' '), base(10) {}
// ~OutStream() override = default;
// Methode zur Ausgabe des Pufferinhalts der Basisklasse StringBuffer.
void flush() override;
void put(char c) override;
// OPERATOR << : Umwandlung des angegebenen Datentypes in eine
// Zeichenkette.
// NOTE: I changed the stream manipulators to templates to be usable with different streams.
// If a Stream derived from OutStream gets passed to a operator<< the type won't be "lowered".
// This allows chaining of operator<< of different streams.
// Needed because I added operator<< overloads to the CGA_Stream class to change color with manipulators.
// Darstellung eines Zeichens (trivial)
template<typename T>
friend T& operator<<(T& os, char c) {
os.put(c);
if (c != '\n') {
// endl() doesn't has access to StringBuffer::put(), so ignore \n here
os.fill_finalize();
}
return os;
}
template<typename T>
friend T& operator<<(T& os, unsigned char c) { return os << static_cast<char>(c); }
// Darstellung einer nullterminierten Zeichenkette
template<typename T>
friend T& operator<<(T& os, const char* string) {
const char* pos = string;
while (*pos) {
os.put(*pos);
pos++;
}
os.fill_finalize();
return os;
}
// Can not use this exclusively for strings as these are heap allocated
template<typename T>
friend T& operator<<(T& os, const bse::string& string) {
os << static_cast<const char*>(string);
return os;
}
// Darstellung ganzer Zahlen im Zahlensystem zur Basis base
template<typename T>
friend T& operator<<(T& os, short ival) { return os << static_cast<long>(ival); }
template<typename T>
friend T& operator<<(T& os, unsigned short ival) { return os << static_cast<unsigned long>(ival); }
template<typename T>
friend T& operator<<(T& os, int ival) { return os << static_cast<long>(ival); }
template<typename T>
friend T& operator<<(T& os, unsigned int ival) { return os << static_cast<unsigned long>(ival); }
template<typename T>
friend T& operator<<(T& os, long ival) {
// Bei negativen Werten wird ein Minuszeichen ausgegeben.
if (ival < 0) {
os.put('-');
ival = -ival;
}
// Dann wird der Absolutwert als vorzeichenlose Zahl ausgegeben.
return os << static_cast<unsigned long>(ival);
}
template<typename T>
friend T& operator<<(T& os, unsigned long ival) {
unsigned long div;
char digit;
if (os.base == 8) {
os.put('0'); // oktale Zahlen erhalten eine fuehrende Null
} else if (os.base == 16) {
os.put('0'); // hexadezimale Zahlen ein "0x"
os.put('x');
}
// Bestimmung der groessten Potenz der gewaehlten Zahlenbasis, die
// noch kleiner als die darzustellende Zahl ist.
for (div = 1; ival / div >= static_cast<unsigned long>(os.base); div *= os.base) {}
// ziffernweise Ausgabe der Zahl
for (; div > 0; div /= static_cast<unsigned long>(os.base)) {
digit = ival / div;
if (digit < 10) {
os.put('0' + digit);
} else {
os.put('a' + digit - 10);
}
ival %= div;
}
os.fill_finalize();
return os;
}
// Darstellung eines Zeigers als hexadezimale ganze Zahl
template<typename T>
friend T& operator<<(T& os, void* ptr) {
int oldbase = os.base;
os.base = 16;
os << reinterpret_cast<unsigned long>(ptr);
os.base = oldbase;
return os;
}
// Aufruf einer Manipulatorfunktion
template<typename T>
friend T& operator<<(T& os, T& (*f)(T&)) { return f(os); }
// For stream formatting
template<typename T>
friend T& operator<<(T& os, const fillw& w) {
os.flush(); // Flush the buffer to not modify previous output
os.fill_width = w.w;
return os;
}
template<typename T>
friend T& operator<<(T& os, const fillc& c) {
os.flush();
os.fill_char = c.c;
return os;
}
// Allow access to base member
template<typename T> friend T& endl(T& os);
template<typename T> friend T& bin(T& os);
template<typename T> friend T& oct(T& os);
template<typename T> friend T& dec(T& os);
template<typename T> friend T& hex(T& os);
};
//
// Manipulatorfunktionen
//
// Die folgenden Funktionen erhalten und liefern jeweils eine Referenz auf
// ein OutStream Objekt. Da die Klasse OutStream einen Operator << fuer
// derartige Funktionen definiert, koennen sie mit Hilfe dieses Operators
// aufgerufen und sogar in weitere Eingaben eingebettet werden.
// Aufgabe der Manipulatoren ist, die Darstellung der nachfolgenden Ausgaben
// zu beeinflussen, z.B durch die Wahl des Zahlensystems.
// Zeilenumbruch in Ausgabe einfuegen.
template<typename T>
T& endl(T& os) {
// os << '\r';
os << '\n';
os.flush();
return os;
}
// Waehle binaeres Zahlensystem aus.
template<typename T>
T& bin(T& os) {
os.base = 2;
return os;
}
// Waehle oktales Zahlensystem aus.
template<typename T>
T& oct(T& os) {
os.base = 8;
return os;
}
// Waehle dezimales Zahlensystem aus.
template<typename T>
T& dec(T& os) {
os.base = 10;
return os;
}
// Waehle hexadezimales Zahlensystem aus.
template<typename T>
T& hex(T& os) {
os.base = 16;
return os;
}
#endif