Also, wie soll der Textformatierer funktionieren? Wir lesen zeichenweise ein und ignorieren die störenden Steuerzeichen. In einer Variable Einrückung wird festgehalten, wie weit der Absatz am Anfang der Zeile eingerückt werden soll. Bei rechtsbündigem Satz wird am rechten Rand eingerückt, oder doch lieber am linken? Am linken würde man die Einrückung nicht so schön erkennen, da der Text links sowie so flattert. Es steht ein Eingabepuffer der Länge einer Ausgabezeile bereit. In diesen Eingabepuffer wird geschrieben, bis er voll ist oder ein Absatzende (\n\n, \n\t, EOF, ...) erkannt wurde. Dann muß er nämlcih erst entleert werden. Beim Einlesen eines \n, das keinen Absatz bricht, ist zu testen, ob das letzte Wort der oberen Zeile auf .- (Zeichen,Bindestrich) endet. Ist dies der Fall, dann kann das betreffende Wort wieder zusammengesetzt werden. Ist der Eingabepuffer voll, dann werde geguckt, ob wir bereits mehrere Worte auf der Zeile stehen haben. Wenn ein Wort bereits den ganzen Platz ausfüllt, dann muß es mit einer Warnungsmeldung abgeschnitten werden. Ist es nicht der Fall, wird gesehen, wie weit wir schon in das letzte Wort eingedrungen sind, denn diese Zahl ergibt die Zahl der Füller im Blocksatz bzw. die Länge des Lochs im Flattersatz. Ist die Zahl groß, dann wird das letzte Wort rückwarts nach einem '-' durchsucht. ungetc() eignet sich nicht dafür, mehrere Zeichen zurück in den Eingabestrom zu drücken, da es nur die erfolgreiche Rückgabe eines einzelnen Zeichens garantiert. Findet sich auch keine Trennmöglichkeit, dann ist auch hier gegebenenfalls eine Warnung auszugeben. Danach wissen wir, welche Worte in die Ausgabezeile formatiert werden sollen. Es gilt nun nur noch, die entsprechenden Leerzeichen einzufügen. Das braucht nicht im Puffer zu geschehen, sondern mit einer Hilfsfunktion ala leer (Einrueckung); puts (Wort [1]); leer (1); und so weiter. Dazu sollten zwischen den Worten Nullbytes im Eingabepuffer stehen und eine dynamische Struktur existieren, die die Adresse und Länge und Bindestrichvorkommen jedes Wortes vermerkt, hierbei kann ruhig jedesmal realloc() aufgerufen werden. Ich habe erst überlegt, ob es nicht besser wäre, in gröberen Schritten Speicher zu alloziieren, doch genau das tut realloc ja. Das einzige Problem, daß es ab einer bestimmten Größe schwierig wird, ein zusammmenhängendes Gebiet anzubieten, ist ja bei diesem kleinen Beispiel, das nicht einmal die zehnfache Spaltenbreite belegt, kein Problem. Beim Blocksatz lassen sich / und % wunderbar dazu gebrauchen, die Unregelmäßigkeiten gleichmäßig zu verteilen (abwechselnd vorwärts und rückwärts. Flattersatz ist eh billig. Das Ergebnis wird in ein Tempfile geschrieben. Dann muß eventuell noch das halbfertige letzte gelesene Wort an den Anfang des Eingabepuffers kopiert werden und dann kann dort weiter gelesen werden. Am Ende eines Absatzes wird einach geflusht, wenn überhaupt was sinnvolles in der Zeile steht. Gut, damit ziehen wir ein mal durch den Eingabefile. Währenddessen laufen Zählvariablen über die Zahl der eingelesenen Zeichen und Zeilen, damit bei Warnungen genau angegeben werden kann, wo der Fehler aufgetreten ist, und bei unzureichendem Platz geantwortet werden kann, zu wieviel Prozent der Text auf die vorgegebene Seitenzahl passt. Leere Zeilen am Ende des Textes sollten ruhig vergessen werden, dann kann man mit tippe auf 0 Seiten testen, ob eine Datei etwas sinnvolles enthält. Außerdem muß natürlich gezählt werden, wieviele Zeilen die Druckfahne lang ist, damit man entscheiden kann, ob die Seitenzahl ausreicht und wo die Spalten auf der letzten Seite enden, das soll ja möglichst ausgeglichen aussehen. Dann geht der Umbruch in Spalten vor sich, dazu brauchen wir bei 1-spaltigem Satz keine weitere Zwischendatei. Bei zweispaltigem Satz könnte man die Zwischendatei noch mal mit einem zweiten Read/Write-Offset zum Lesen öffnen, und dann gleichzeitig an verschiedenen Stellen aus ihr lesen, nur hat man dann das Problem, daß es schwierig ist, die Positionen zu berechnen, die per fseek() auf die richtigen Zeilen zeigen. Man könnte hierzu die Positionen auf dem Heap oder noch einer Datei abgespeichert haben. Eigentlich gar nicht so eine schlechte Idee. Die andere Möglichkeit wäre, noch zwei Zwischendateien zu haben und nur einmal durch die Fahne zu brausen und folgendermaßen zu schreiben: 1. von der Fahne nach A, bis die erste Spalte voll ist, 2. Zeilen zusammenzusetzen, indem man die erste Spalte aus A liest und dann aus der Fahne eine Zeile anhängt und dann das Ergebnis in B speichert, sofern dies noch nicht die letzte Spalte War, dann geht es nämlich ab in die Ausgabe. Wenn die Spalte voll ist, kommt die nächste Spalte dran, dazu wird die Bedeutung von A und B einfach vertauscht, denn aller Text aus A ist ja in B gespeichert und A kann als Speichergebraucht werden. Also noch mal in der Übersicht: es gäbe die Methode mit einer Fahnendatei, für jede Spalte einmal geöffnet. Ich schreibe gleich mal ein Programm, das testet, ob überhaupt genügend viele Dateien gleichzeitig geöffnet werden dürfen. Abhilfe würde hier schaffen, die Datei nur einmal zu öffnen und dann wie wild hin und her zu seeken, das wird unter Umständen langsamer, da vielleicht nach jeder Zeile der gesamte Puffer überschrieben wird. Die Methode mit zwei zusätzlichen Zwischendateien hat den Nachteil, daß hier die erste Spalte Spaltenzahl Male kopiert wird und zwei Seiten zusätzlicher Plattenplatz verbraucht werden. Dann bestünde noch die Möglichkeit, den ganzen Text oder zumindest eine ganze Seite im Speicher abzulegen. Das ist prinzipiell in Ordnung, da unter SunOS durch Swapping ja praktisch unbegrenzt Speicherplatz zur Verfügung steht, der, bis die ersten 16 MB voll sind, auch wesentlich schneller erreichbar ist. Nur wissen wir leider nicht, wie groß unsere Seiten sind. Es ist grundsätzlich möglich auf 30 Spalten zu tippen, bei einer Spaltenbreite von 255 und 100 Seiten der Länge 10000 Zeilen. Aber erstens wäre der Speicher dadurch überhaupt schon überfordert und ist das nicht reichlich unrealistisch für eine solch kleine Anwendung? Warum gebrauchen dann professionelle Programme wie xrn Temporärdateien? Andererseits: Wir können doch davon ausgehen, daß der Text mit einem Editor erstellt wurde, der den ganzen Text in den Speicher laden konnte, bzw. daß Splittools existieren, die man vorschalten könnte, wenn tatsächlich Speicherprobleme existieren. Dann stellt sich nachher bei der Ausgabe die Frage, was tun mit Leerzeilen, die dadurch überflüssig werden, daß in ihnen gerade ein Spaltenumbruch fällt. Ich würde aus ästhetischen Gründen gerne jede Spalte mit Text beginnen lassen, aber aus praktischen Gründen darauf verzichten, die Spalten bis zum unteren Rand aufzufüllen, das heißt, sie unten ein wenig flattern lassen, Das kann jedoch arg ins Auge gehen. Algorithmen, die dieses Problem befriedigend lösen, erscheinen mir zu schwer, um sie eben mal zu finden. Und eine interaktive Einstellung ist leichter vorzustellen, aber auch nicht einfach zu programmieren.