Commit 29fc36a8 authored by Bernhard Heinloth's avatar Bernhard Heinloth
Browse files

Vorgabe Aufgabe 0 (Grundgerüst für oostubs)

parents
build/
build-noopt/
build-iso/
dep/
dep-noopt
OOStuBS - Objektorientiertes Studenten Betriebssystem
=====================================================
In diesem Git Quellcodeverzeichnis ist die Vorlage für die
Übungsaufgaben der Veranstaltung Betriebssysteme für das Wintersemester
2018/19 enthalten.
Updaten der Vorlage
-------------------
Bei jeder neuen Aufgabe, bzw. einem Bugfix in der Vorlage, solltet ihr
die Änderungen aus dem Vorlagenrepository in euer Repository übernehmen.
Zunächst müsst ihr sicherstellen, dass das Vorlagen Repository als Git
Remote eingetragen ist. Mit diesem Befehl wird ein neuer Verweis auf
ein entferntes Repository angelegt.
git remote add vorlage https://gitlab.cs.fau.de/i4/bs/oostubs.git
Das hinzufügen des entfernten Repositories ist nur einmal
erforderlich. Danach könnt ihr die Änderungen aus der Vorlage mittels
git pull vorlage master
in euer Repository übernehmen. Es wird dabei ein *merge* Commit
erstellt, der eure Änderungen und die geänderte Vorlage zusammenführt.
// vim: set et ts=4 sw=4:
#include "o_stream.h"
// vim: set et ts=4 sw=4:
/*! \file
* \brief Hier ist die Klasse O_Stream implementiert.
* Neben der Klasse O_Stream sind hier auch die Manipulatoren \c hex , \c dec ,
* \c oct und \c bin für die Wahl der Basis bei der Zahlendarstellung,
* sowie \c endl für den Zeilenumbruch \b deklariert.
* \ingroup io
*
*
* \par Manipulatoren
* Um bei der Textformatierung mit Hilfe der Klasse O_Stream das Zahlensystem
* bequem wählen und Zeilenumbrüche einfügen zu können, sollen sogenannte
* Manipulatoren definiert werden.
* Der Ausdruck <tt>kout << "a = " << dec << a << " ist hexadezimal " << hex << a << endl;</tt>
* soll dann beispielsweise den Wert der Variablen a erst in dezimaler und
* dann in hexadezimaler Schreibweise formatieren und zum Schluss einen
* Zeilenumbruch anfügen.
*
* Die gewünschten Eigenschaften können realisiert werden, wenn hex, dec,
* oct, bin und endl als Funktionen (d.h. nicht als Methoden der Klasse
* O_Stream) definiert werden, die als Parameter und Rückgabewert jeweils
* eine Referenz auf ein O_Stream Objekt erhalten bzw. liefern. Durch diese
* Signatur wird bei dem genannten Ausdruck der bereits erwähnte Operator
* <tt>O_Stream& O_Stream::operator<< ((*fkt*) (O_Stream&))</tt> ausgewählt, der dann
* nur noch die als Parameter angegebene Funktion ausführen muss.
*
* \par Anmerkung
* Der Manipulatorbegriff wurde dem Buch
* <a href="http://www.stroustrup.com/4th.html">The C++ Programming Language</a>
* von Bjarne Stroustrup entnommen.
* Dort finden sich auch weitergehende Erläuterungen dazu.
*/
#pragma once
#include "strbuf.h"
/*! \brief Die Aufgaben der Klasse O_Stream entsprechen im Wesentlichen denen der
* Klasse ostream der bekannten C++ IO-Streams-Bibliothek.
*
* Da die Methode \c Stringbuffer::put(char) der Basisklasse Stringbuffer recht
* unbequem ist, wenn die zusammenzustellenden Texte nicht nur aus einzelnen
* Zeichen, sondern auch aus Zahlen, oder selbst wieder aus Zeichenketten
* bestehen, werden in der Klasse O_Stream Möglichkeiten zum Zusammenstellen
* verschiedener Datentypen realisiert. In Anlehnung an die bekannten
* Ausgabeoperatoren der C++ IO-Streams-Bibliothek wird dazu der
* Shift-Operator \c operator<< verwendet.
*
* Darüberhinaus soll es möglich sein, für die Darstellung ganzer Zahlen
* zwischen dem Dezimal-, dem Binär- dem Oktal- und dem Hexadezimalsystem zu
* wählen. Beachtet dabei bitte die übliche Darstellung negativer Zahlen: Im
* Dezimalsystem mit führendem Minuszeichen, im Oktal- und Hexadezimalsystem
* ohne Minuszeichen, sondern genau so wie sie im Maschinenwort stehen.
* (Intel-CPUs verwenden intern das 2er-Komplement für negative Zahlen. \c -1
* ist Hexadeziamal also \c FFFFFFFF und Oktal \c 37777777777.)
*
* Die öffentlichen Methoden/Operatoren von O_Stream liefern jeweils eine
* Referenz auf ihr eigenes O_Stream Objekt zurück. Dadurch ist es möglich,
* in einem Ausdruck mehrere der Operatoren zu verwenden, z. B.
* <tt>kout << "a = " << a</tt>;
*
* Zur Zeit wird die Darstellung von Zeichen, Zeichenketten und ganzen Zahlen
* unterstützt. Ein weiterer \c << Operator erlaubt die Verwendung von
* Manipulatoren, welche in der o_stream.h-Dokumentation näher
* beschrieben sind.
*/
class O_Stream
//TODO: Hier muss die Vererbungshierarchie vervollständigt werden.
{
O_Stream(const O_Stream&) = delete;
O_Stream& operator=(const O_Stream&) = delete;
public:
/*! \brief Basis des zur Anzeige verwendeten Zahlensystems (z.B. 2, 8, 10 oder 16)
*
*/
int base;
/*! \brief Konstruktor; Initale Zahlenbasis ist das Dezimalsystem.
*
* \todo Konstruktor implementieren
*
*/
O_Stream ()
//TODO: Hier muss noch Code vervollständigt werden.
{}
/*! \brief Destruktor
*/
virtual ~O_Stream () {}
/*! \brief Leert den Puffer.
*
* Rein virtuelle Methode, die erst durch abgeleitete Klassen implementiert
* wird. Darstellung des Pufferinhalts kann so durch unterschiedliche Kindklassen
* variiert werden.
*/
virtual void flush () = 0;
/*! \brief Stellt ein einzelnes Zeichen dar
*
* \todo Operator implementieren
*
* \param c Darzustellendes Zeichen
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& operator << (char c);
/// \copydoc O_Stream::operator<<(char)
O_Stream& operator << (unsigned char c);
/*! \brief Darstellung einer nullterminierten Zeichenkette
*
* \todo Operator implementieren
*
* \param string Darzustellende Zeichenkette.
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& operator << (const char* string);
/*! \brief Stellt ein Boolean dar
*
* \todo Operator implementieren
*
* \param b Darzustellendes Boolean
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& operator << (bool b);
/*! \brief Darstellung ganzer Zahlen im Zahlensystem zur Basis base
*
* \todo Operator implementieren
*
* \param ival Darzustellende Zahl
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& operator << (short ival);
/// \copydoc O_Stream::operator<<(short)
O_Stream& operator << (unsigned short ival);
/// \copydoc O_Stream::operator<<(short)
O_Stream& operator << (int ival);
/// \copydoc O_Stream::operator<<(short)
O_Stream& operator << (unsigned int ival);
/// \copydoc O_Stream::operator<<(short)
O_Stream& operator << (long ival);
/// \copydoc O_Stream::operator<<(short)
O_Stream& operator << (unsigned long ival);
/*! \brief Darstellung eines Zeigers als hexadezimale ganze Zahl
*
* \todo Operator implementieren
*
* \param ptr Darzustellender Pointer
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& operator << (const void* ptr);
/*! \brief Aufruf einer Manipulatorfunktion
*
* Methode sorgt dafür, dass Manipulatorfunktionen aufgerufen werden,
* um Veränderungen an der Klasse (z.B. Änderung der Zahlenbasis) zu
* ermöglichen.
*
* \todo Operator implementieren
*
* \param f Anzuwendende Manipulatorfunktion
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& operator << (O_Stream& (*f) (O_Stream&));
};
/*! \brief Löst explizit ein Leeren (Flush) des Puffers aus.
*
* \todo Modifikator implementieren
*
* \param os Zu modifizierender Stream
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& flush(O_Stream& os);
/*! \brief Fügt einen Zeilenumbruch in die Ausgabe ein und löst ein Leeren (Flush) des Puffers aus.
*
* \todo Modifikator implementieren
*
* \param os Zu modifizierender Stream
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& endl(O_Stream& os);
/*! \brief Wählt das binäre Zahlensystem aus.
*
* \todo Modifikator implementieren
*
* \param os Zu modifizierender Stream
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& bin(O_Stream& os);
/*! \brief Wählt das oktale Zahlensystem aus.
*
* \todo Modifikator implementieren
*
* \param os Zu modifizierender Stream
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& oct(O_Stream& os);
/*! \brief Wählt das dezimale Zahlensystem aus.
*
* \todo Modifikator implementieren
*
* \param os Zu modifizierender Stream
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& dec(O_Stream& os);
/*! \brief Wählt das hexadezimale Zahlensystem aus.
*
* \todo Modifikator implementieren
*
* \param os Zu modifizierender Stream
* \return Referenz auf ein O_Stream Objekt, um Operatoren konkatenieren zu können.
*/
O_Stream& hex(O_Stream& os);
// vim: set et ts=4 sw=4:
#include "strbuf.h"
// vim: set et ts=4 sw=4:
/*! \file
* \brief Enthält die Klasse Stringbuffer
*/
#pragma once
/*! \brief Die Klasse Stringbuffer dient dazu, einzelne Zeichen zu längeren Texten
* zusammenzustellen, die dann an einem Stück verarbeitet werden können.
*
* Damit ein möglichst vielseitiger Einsatz möglich ist, trifft die Klasse
* keine Annahme darüber, was "verarbeiten" in diesem Zusammenhang bedeutet.
* Nur der Zeitpunkt der Verarbeitung steht bereits fest, nämlich immer,
* wenn dies explizit gewünscht wird oder der Text so lang geworden ist,
* dass keine weiteren Zeichen hinzugefügt werden können. Dies geschieht durch
* Aufruf der Methode flush(). Da Stringbuffer geräteunabhängig sein soll,
* ist flush() eine virtuelle Methode, die von den abgeleiteten Klassen
* definiert werden muss.
*
* \par Hinweise zur Implementierung
* Zur Pufferung der Zeichen eignet sich ein fest dimensioniertes Feld, auf
* das die abgeleiteten Klassen zugreifen können müssen. Auch die Anzahl der
* Zeichen oder das zuletzt beschriebene Feldelement sollte in den
* spezialisierten flush() Methoden erkennbar sein.
*
* \par Anmerkung
* Anlass für die Einführung dieser Klasse war die Erkenntnis, dass Ausgaben
* eines Programmes sehr häufig aus vielen kleinen Komponenten bestehen, zum
* Beispiel, wenn die Namen und Inhalte von Variablen dargestellt werden
* sollen. Andererseits können wenige längere Texte meist viel effizienter
* ausgegeben werden als viele kurze. Daher erscheint es sinnvoll, vor der
* Ausgabe die einzelnen Komponenten mit Hilfe eines Stringbuffer Objekts
* zusammenzufügen und erst später, z. B. bei einem Zeilenumbruch, gesammelt
* auszugeben.
*/
class Stringbuffer {
// Verhindere Kopien und Zuweisungen
Stringbuffer(const Stringbuffer&) = delete;
Stringbuffer& operator=(const Stringbuffer&) = delete;
// Alle Variablen und Methoden dieser Klasse sind "protected",
// da die abgeleiteten Klassen einen direkten Zugriff auf den
// Puffer, den Konstruktor, den Destruktor und die Methode put
// benötigen. Die Methode flush() muss sowieso neu definiert
// werden und kann dann auch public werden.
protected:
/// Zeichenpuffer
char buffer[80];
/// Aktuelle Position im Puffer
int pos;
/*! \brief Konstruktor; Markiert Puffer als leer.
*
* \todo Konstruktor vervollständigen
*/
Stringbuffer()
//TODO: Hier muss noch Code vervollständigt werden.
{ }
/*! \brief Fügt das Zeichen c in den Puffer ein.
*
* Wenn der Puffer daraufhin voll ist, wird er durch Aufruf der Methode
* flush() geleert.
*
* \todo Methode implementieren
*
* \param c Einzufügendes Zeichen
*/
void put(char c);
/*! \brief Methode zur Ausgabe des Pufferinhalts
*
* Diese Methode muss in den abgeleiteten Klassen definiert werden,
* denn nur diese wissen, wie die Zeichen ausgegeben werden können.
* flush() muss den Positionszeiger pos zurücksetzen.
*/
virtual void flush() = 0;
public:
/*! \brief Destruktor (hier nichts zu tun)
*/
virtual ~Stringbuffer() { }
};
VERBOSE = @
CXX = g++
CC_SOURCES = $(shell find .. -name "*.cc" -and ! -name '.*' )
CXXFLAGS = -std=c++11 -m32 -I../object -I.
TARGET = test
all: $(TARGET)
$(TARGET): $(CC_SOURCES)
$(VERBOSE) $(CXX) -o $@ $(CXXFLAGS) $^
clean:
$(VERBOSE) rm -f $(TARGET)
.PHONY: all clean
// vim: set et ts=4 sw=4:
#include "console_out.h"
// vim: set et ts=4 sw=4:
/*! \file
* \brief Enthält die Klasse ConsoleOut
*/
#pragma once
#include "o_stream.h"
/*! \brief Ausgabe auf der Konsole
*
* Die Klasse ConsoleOut ermöglicht ein Schreiben auf der Konsole ähnlich std::cout
* aus der C++-Standardsbibliothek. Die Klasse ist von O_Stream abgeleitet.
*/
class ConsoleOut : public O_Stream
{
// Verhindere Kopien und Zuweisungen
ConsoleOut(const ConsoleOut&) = delete;
ConsoleOut& operator=(const ConsoleOut&) = delete;
public:
/*! \brief Konstruktor
*
*/
ConsoleOut();
/*! \brief Ausgabe der Zeichenkette auf dem Bildschirm.
* Die Implementierung soll ausschliesslich `putchar()` verwenden.
*/
virtual void flush();
};
// vim: set et ts=4 sw=4:
#include "file_out.h"
// vim: set et ts=4 sw=4:
/*! \file
* \brief Enthält die Klasse FileOut für die C++ Übungsaufgabe
*/
#pragma once
#include "o_stream.h"
/*! \brief Ausgabe in eine Datei
*
* Die Klasse FileOut ermöglicht eine komfortable Ausgabe in eine Datei nur unter
* zu Hilfenahme der elementaren Systemaufrufe `open()` / `write()` / `close()` .
* Diese Klasse ist von O_Stream abgeleitet.
*/
class FileOut : public O_Stream
{
// Verhindere Kopien und Zuweisungen
FileOut(const FileOut&) = delete;
FileOut& operator=(const FileOut&) = delete;
public:
/*! \brief Konstruktor
* Öffnet die Datei mittels Syscall `open()` zum schreiben.
* \param path Pfad zur Ausgabedatei
*/
FileOut(const char * path);
/*! \brief Destruktor
* Schließt die Datei (mittels `close()`)
*/
virtual ~FileOut();
/*! \brief Rückgabe des Pfades der Ausgabedatei
* \return Pfad der Ausgabedatei (wie im Konstruktor übergeben)
*/
const char * getPath();
/*! \brief Auflisten aller derzeit (mittels dieser Klasse) geöffneten Dateien
*/
static int count();
/*! \brief Schreiben der Zeichenkette in die geöffnete Datei.
* Die Implementierung soll ausschliesslich den Syscall `write()` verwenden.
*/
virtual void flush();
};
#include "console_out.h"
#include "file_out.h"
ConsoleOut cout;
FileOut foo("foo.txt");
int main(){
cout << "Console Test <stream result> -> <expected>" << endl;
cout << " zero: " << 0 << " -> 0" << endl;
cout << " ten: " << (10) << " -> 10" << endl;
cout << " uint max: " << ~((unsigned int)0) << " -> 4294967295" << endl;
cout << " int max: " << ~(1<<31) << " -> 2147483647" << endl;
cout << " int min: " << (1<<31) << " -> -2147483648" << endl;
cout << " some int: " << (123456789) << " -> 123456789" << endl;
cout << " some negative int: " << (-123456789) << " -> -123456789" << endl;
cout << " binary: " << bin << 42 << dec << " -> 0b101010" << endl;
cout << " octal: " << oct << 42 << dec << " -> 052" << endl;
cout << " hex: " << hex << 42 << dec << " -> 0x2a" << endl;
cout << " pointer: " << ((void*)(3735928559u)) << " -> 0xdeadbeef" << endl;
cout << endl;
cout << "File Test" << endl
<< " currently open: " << FileOut::count() << endl
<< " writing into '" << foo.getPath() << "'..." << endl;
foo << "C makes it easy to shoot yourself in the foot;" << endl;
foo << "C++ makes it harder, but when you do it blows your whole leg off." << endl;
{
FileOut bar("bar.txt");
cout << " opened the " << FileOut::count() << ". file, " << endl;
cout << " writing into '" << bar.getPath() << "'..." << endl;
bar << "Anyone who claims to have the perfect programming language is either a fool or a salesman or both" << endl;
}
cout << " having only " << FileOut::count() << " file opened since the other is out of scope" << endl;
return 0;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment