Heute machen wir mal etwas lustiges, heute programmieren wir eine Website in COBOL.
So genannte Single Serving Sites habt ihr bestimmt schon mal gesehen, das sind im Wesentlichen Ein-Seiten-Websites, die nur einen einzigen bestimmten Zweck erfüllen, zum Beispiel
purple.com, das euch zeigt, was Lila ist, und
hasthelargehadroncol...royedtheworldyet.com. Ihr seht: Das ist unter Umständen durchaus sinnvoll. Es muss nicht immer ein CMS sein.
COBOL (Common Business Oriented Language) ist eine 1960 erstmals standardisierte Programmiersprache, die seit ihrer ersten Version zusammen mit Fortran (früher: FORTRAN, Formula Translator) die Weltwirtschaft beherrscht und bis heute aktiv weiterentwickelt wird. Wer schon mal eine Bank von innen gesehen hat, der ahnt, dass eine Menge Logik nötig ist, um ein Konto zu verwalten. Es wäre Irrsinn, diese Logik, wenn sie einmal funktioniert, in einer anderen Sprache neu zu programmieren, nur weil die alte Sprache nicht mehr im Trend liegt. Das bedeutet, dass Unternehmen mit viel Geld
dringend Leute suchen, die Software pflegen sollen, die mitunter älter ist als diejenigen, die sie derzeit entwickeln. Ihr ahnt, warum es interessant sein kann, mal was mit COBOL gemacht zu haben. Und was liegt näher als eine Webanwendung in einer solch
rustikalen Sprache zu schreiben?
Eben.
Um ein praxistaugliches Beispiel zu haben: Nehmen wir an, ihr wollt eine Website namens "HalloWelt.coffee" (ist tatsächlich noch frei) erstellen, die deutschsprachige Benutzer mit "Hallo Welt!", anderssprachige Benutzer aber mit "Hello World!" begrüßt. Ein alltägliches Problem, nicht wahr?
Damit ihr anfangen könnt, braucht ihr zunächst einmal ein wenig Software:
- Einen FastCGI-tauglichen Webspace oder Webserver. (Wenn ihr das nicht so genau wisst, fragt euren Hoster. Wenn euer Hoster kein FastCGI anbietet, habt ihr einen schlechten Hoster. Wenn ihr einen schlechten Hoster habt, besorgt euch bitte einen besseren und lest dann hier weiter.) Ich empfehle Uberspace.
- GnuCOBOL oder einen anderen COBOL-Compiler. Es gibt höchstwahrscheinlich auch einen für euer Betriebssystem (wenn ihr nicht gerade RISC OS oder TempleOS einsetzt). Das Kompilat muss später auf eurem Webspace oder Webserver lauffähig sein, wenn ihr also zum Beispiel einen Linux-Webserver habt, müsst ihr auch ein GnuCOBOL unter Linux benutzen. Unter den meisten GNU/Linux-Distributionen und den "großen" BSDs ist GnuCOBOL auch über euren Paketmanager verfügbar.
- Einen Texteditor, am besten einen, der COBOL-Highlighting beherrscht. Notepad funktioniert aber auch. Ihr werdet sehen, dass Highlighting für COBOL nicht so wichtig ist. Unter welchem System ihr den Code schreibt, ist egal, so lange ihr ihn später unter dem "richtigen" System kompiliert.
Erstellt nun mit besagtem Texteditor eine neue Datei namens
hallowelt.cob (oder
hallowelt.cbl, da gibt es keine einheitliche Norm). Wir fangen klein an, wir geben erst mal nur den HTML-Code für die Website aus. Wie ihr den dann in eurem Browser anzeigen könnt, erkläre ich euch weiter unten.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| IDENTIFICATION DIVISION. PROGRAM-ID. Hallo-Entwickler-Ecke.
PROCEDURE DIVISION. * HTML-Text ausgeben: DISPLAY "<!doctype html>" DISPLAY "<html>" DISPLAY " <head>" DISPLAY " <title>HalloWelt.coffee</title>" DISPLAY " </head>" DISPLAY " <body>" DISPLAY " <h1>Hallo Welt!</h1>" DISPLAY " </body>" DISPLAY "</html>" * HTML-Text ist zu Ende.
STOP RUN. |
Ihr seht: COBOL ist eine hübsche Sprache, man versteht sie eigentlich sofort. COBOL-Befehle könnt ihr inzwischen auch in normaler Schreibweise benutzen, also zum Beispiel "Display" statt "DISPLAY", ihr müsst den Code also nicht so "brüllen" wie im Beispiel. Ich finde es so aber übersichtlicher, damit man auch in Editoren, die kein COBOL-Highlighting können, Variablennamen und Strings optisch besser von Anweisungen unterscheiden kann.
Allerdings fängt das Programm absichtlich "eingerückt" an. Die Aufteilung in Spalten hat historische Gründe: COBOL stammt aus einer Zeit, in der man noch "zweidimensional" auf Lochkarten programmiert hat, die ersten sieben Spalten waren dort etwa für die Zeilennummer reserviert. Zwar ist auch die "Freiform" - also das Abweichen von der Lochkartenformatierung, in der das Programm in Spalte 8 anfangen
muss, Kommentare mit einem "*" in Spalte 7 eingeleitet werden
müssen und so weiter - inzwischen Teil des Standards, aber viele Texteditoren, die COBOL-Highlighting beherrschen, legen Wert darauf, dass ihr ebenfalls wenigstens
ein bisschen konservativ programmiert, sonst funktioniert das Highlighting nicht richtig. Wenn ihr euch das von Anfang an angewöhnt, werdet ihr es später auch leichter mit fremdem Code haben, der sich in der Regel an die Konventionen hält. Übrigens: Ein Zeilenumbruch am Ende (den dieses Forum anscheinend verschluckt?) ist zwar nicht zwingend notwendig, wird aber gern gesehen. GnuCOBOL beschwert sich auch, wenn ihr ihn weglasst.
Wenn ihr diesen Code jetzt kompiliert ...
Quelltext
1:
| cobc -x -static hallowelt.cob |
..., bekommt ihr nach einer kurzen Wartezeit ein Programm namens "hallowelt.exe" (oder, wenn ihr auf einem unixoiden Computer arbeitet, "hallowelt") heraus, das nach dem Ausführen den gewünschten HTML-Code ausgibt:
(Wenn sich
cobc beim Kompilierversuch beschwert, dass es
cl.exe nicht finden kann, benutzt ihr offenbar die Windowsversion. Die Windowsversion sucht Microsofts C-Compiler, zum Beispiel aus der Visual-Studio-Community-Edition, in eurem %PATH%. GnuCOBOL wandelt COBOL-Code als Zwischenschritt in C-Code um, wenn ihr also bereits C könnt, kann euch GnuCOBOL auf Wunsch auch nur den erzeugten C-Code ausgeben, den ihr dann weiterbearbeiten und selbst kompilieren könnt. Wenn ihr stattdessen einen anderen C-Compiler nutzen möchtet, müsst ihr GnuCOBOLs
defaults.h.tmpl anpassen und GnuCOBOL neu kompilieren. Nehmt also lieber
cl.exe.)
Nun ist das natürlich noch recht langweilig, denn dafür hättet ihr kein COBOL gebraucht. Wie kriegt ihr denn überhaupt das Programm ins Web und wie kriegt ihr das mit der Mehrsprachigkeit hinein?
Die Lösung heißt FastCGI.
FastCGI ist heute so was wie "ein Standard", es ist nicht unwahrscheinlich, dass auch eure PHP-basierte Website (ihr habt doch sicher eine PHP-basierte Website? Jeder hat eine PHP-basierte Website!

) unter FastCGI läuft. Stark vereinfacht heißt das, dass euer Webserver bei der Abfrage nach "*.php" das zugeordnete Programm, eben den PHP-Interpreter, aufruft und das Ergebnis, also eure "generierte" Website, zurückschickt. Der Trick: Statt eines PHP-Interpreters könnt ihr auch
ein beliebiges anderes Programm starten, etwa ein Perlscript, ein C-Programm oder eben euer "hallowelt".
Ab hier müsst ihr also auf eurem Server/Webspace weitermachen.
- Wenn ihr bei Uberspace seid, erklärt euch deren Wiki, wie ihr FastCGI einrichtet und nutzt. Das FastCGI-Programm ist in diesem Fall euer kompiliertes "hallowelt".
- Auf einem OpenBSD-Server sind folgende zwei Einträge unter server "hallowelt.coffee" nötig:
Zitat: |
root "/irgendein/pfad/hallowelt"
fastcgi |
- Unter Apache braucht ihr mod_fcgid, dann könnt ihr in eurer httpd.conf das "hallowelt"-Programm einfach als Handler festlegen. (Wenn ihr Hilfe braucht: Entschuldigt - Apache habe ich schon zu lange nicht mehr so wirklich benutzt.)
- Unter nginx müsst ihr nur die location ändern, indem ihr mindestens die "root"-Direktive sowie die beiden FastCGI-Parameter "SCRIPT_FILENAME" und "SCRIPT_NAME" (beide müssen auf euer "hallowelt" zeigen) einfügt.
Keine Sorge - das sieht nur so kompliziert aus. Wenn alles so weit funktioniert hat, solltet ihr beim Aufruf eurer Website ein großes "Hallo Welt!" sehen. Wenn nicht, habt ihr etwas falsch eingestellt.
FastCGI gibt also die Ausgabe des zugeteilten Scripts/Programms zurück. Es macht aber noch mehr: Beim Aufruf übergibt es ein paar Umgebungsvariablen (PHP-Programmierern vielleicht als
$_SERVER[] bekannt) an das aufgerufene Script, darunter
HTTP_ACCEPT_LANGUAGE, in das euer Browser ungefähr so was reinschreibt:
Zitat: |
de,de-DE,de-AT;q=0.8,fr;q=0.6,en-US;q=0.4 |
Das ist die Liste eurer "bevorzugten" Sprachen mit ihren Prioritäten, in den meisten Browsern könnt ihr die einfach einstellen. Fest steht: Die ersten 2 Zeichen dieses Wertes sind höchstwahrscheinlich die Muttersprache desjenigen, der gerade den Browser bedient. Und damit
genau das, was wir brauchen!
So, wie kriegen wir das jetzt in unser COBOL-Programm hinein? Um das zu verstehen, müsst ihr Variablen verstehen. Variablen werden in COBOL traditionell (ähnlich wie z.B. unter Delphi) oberhalb des eigentlichen Programmcodes (PROCEDURE DIVISION) definiert, nämlich in der DATA DIVISION. Unterschieden werden hier der "local storage" (Variablen, die für jede Programminstanz definiert werden) und der "working storage" (jede Instanz greift auf dieselben Variablen zurück). Da so eine Website ja durchaus für mehrere Benutzer gleichzeitig funktionieren sollte, greifen wir hier auf den "local storage" zurück.
Der COBOL-
Datentyp für Zeichenketten - denn damit wollen wir hier arbeiten - ist das
PICTURE, kurz "PIC". Unterschieden wird im Wesentlichen zwischen alphabetischen Zeichenketten (A), alphanummerischen Zeichenketten (X), "nationalen" Zeichenketten mit erweitertem Zeichensatz (N), nummerischen Zeichenketten (9) und booleschen Werten (1). Da COBOL nicht nur die Datenlogik, sondern auch die Datenbank selbst enthalten kann, besteht auch die Möglichkeit, Zeichenketten zu gruppieren, etwa "Vorname und Nachname" als "Vollständiger Name" zusammenzufassen; aber dies würde hier den Rahmen sprengen.
Wir brauchen höchstens drei Variablen auf der ersten Ebene:
- Liste aller Sprachen: Eine Zeichenkette von, sagen wir, höchstens 75 Zeichen Länge, in der wir das Ergebnis von HTTP_ACCEPT_LANGUAGE zwischenspeichern können.
- Hauptsprache: Eine Zeichenkette von zwei Zeichen Länge, in der dann entweder "de" oder eben etwas völlig anderes steht.
- Ausgabetext: Der Ausgabetext (also "Hallo Welt!", "Hello World!" oder etwas völlig anderes). Warum wir diese Variable berücksichtigen sollten, werdet ihr noch sehen.
Über der "PROCEDURE DIVISION" ist nun also folgender Code einzufügen:
Quelltext
1: 2: 3: 4: 5:
| DATA DIVISION. LOCAL-STORAGE SECTION. 01 alle-sprachen PIC X(75). 01 hauptsprache PIC A(2). 01 ausgabetext PIC X(20). |
Der erste Teil des Programmcodes ist bis zum
<h1> identisch, aber wir wollen ja nach dem
<h1> einen Text einfügen, der von einer anderen Variable abhängt. Ändert also folgende Zeile
Quelltext
1:
| DISPLAY " <h1>Hallo Welt!</h1>" |
wie folgt:
Quelltext
1:
| DISPLAY " <h1>" WITH NO ADVANCING. |
"WITH NO ADVANCING" sorgt dafür, dass am Ende kein Zeilenumbruch eingefügt wird. Das ist technisch gesehen zwar egal, sieht hinterher im generierten Code aber schöner aus.
Jetzt können wir die Umgebungsvariable
HTTP_ACCEPT_LANGUAGE, die wir von FastCGI "bekommen" haben, auslesen und in unsere Variable "alle-sprachen" schreiben:
Quelltext
1: 2:
| ACCEPT alle-sprachen FROM ENVIRONMENT "HTTP_ACCEPT_LANGUAGE" MOVE alle-sprachen (1:2) TO hauptsprache. |
Was passiert hier? Es wird per
ACCEPT (unter C++ wäre das ungefähr
cin) in die Variable "alle-sprachen" das Ergebnis der Umgebungsvariable "HTTP_ACCEPT_LANGUAGE" geschrieben. Deren erste zwei Zeichen (2 Zeichen ab Zeichen 1) werden anschließend in "hauptsprache" gespeichert.
Jetzt hat die Variable "hauptsprache" drei mögliche Werte: "Leer" beziehungsweise "nicht definiert" (FastCGI hat keine
HTTP_ACCEPT_LANGUAGE gesendet), "de" oder etwas völlig anderes. Das ist genau das, was wir brauchen. Mit einem einfachen Vergleich dieser Variablen können wir jetzt den richtigen Text herausfinden:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| IF hauptsprache = SPACE OR hauptsprache = LOW-VALUE THEN MOVE "HACK0RZ!" TO ausgabetext ELSE IF hauptsprache IS EQUAL TO "de" THEN MOVE "Hallo Welt!" TO ausgabetext ELSE MOVE "Hello World!" TO ausgabetext END-IF END-IF. |
Natürlich könnt ihr den Text auch einfach ändern.
Nun, warum "MOVE" und nicht gleich "DISPLAY"? Das hat kosmetische Gründe: COBOL füllt ein
PICTURE immer bis zur maximalen Länge auf, im HTML-Code stünde also ungefähr so etwas:
Quelltext
Das ist nun nicht
schlimm, aber wir sind ja bekanntlich allesamt Perfektionisten hier. Zum Glück beherrscht GnuCOBOL wie auch andere COBOL-Compiler die intrinsische Funktion
trim(), die wir einfach nutzen können, um Leerzeichen am Ende "abzuschneiden". Das sieht zwar im COBOL-Umfeld etwas merkwürdig aus (es werden Klammern benutzt!), aber es spart uns eine Menge Bastelei. (Natürlich würde das auch mit etwas Bastelei hinzukriegen sein, aber warum das Rad neu erfinden?)
Quelltext
1: 2: 3:
| DISPLAY FUNCTION TRIM (ausgabetext TRAILING) WITH NO ADVANCING END-DISPLAY. |
Hinter dem
<h1> steht nun also eine zurechtgekürzte Version eures Ausgabetextes - wiederum ohne weiteren Zeilenumbruch. Alles Weitere bleibt wie bisher:
</h1> schließen, Rest auch schließen. Hier einmal die vollständige Version mit ein paar Kommentaren:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
| IDENTIFICATION DIVISION. PROGRAM-ID. Hallo-Entwickler-Ecke.
DATA DIVISION. LOCAL-STORAGE SECTION. 01 alle-sprachen PIC X(75). 01 hauptsprache PIC A(2). 01 ausgabetext PIC X(20).
PROCEDURE DIVISION. * HTML-Text oben: DISPLAY "<!doctype html>" DISPLAY "<html>" DISPLAY " <head>" DISPLAY " <title>HalloWelt.coffee</title>" DISPLAY " </head>" DISPLAY " <body>" DISPLAY " <h1>" WITH NO ADVANCING.
* Hauptsprache des Browsers auslesen. * Meist die ersten 2 Zeichen aus HTTP_ACCEPT_LANGUAGE. ACCEPT alle-sprachen FROM ENVIRONMENT "HTTP_ACCEPT_LANGUAGE" MOVE alle-sprachen (1:2) TO hauptsprache.
IF hauptsprache = SPACE OR hauptsprache = LOW-VALUE THEN * HTTP_ACCEPT_LANGUAGE ist nicht gesetzt. MOVE "HACK0RZ!" TO ausgabetext ELSE IF hauptsprache IS EQUAL TO "de" THEN * Hauptsprache ist deutsch. MOVE "Hallo Welt!" TO ausgabetext ELSE * Hauptsprache ist irgendwas anderes. MOVE "Hello World!" TO ausgabetext END-IF END-IF.
* "DISPLAY ausgabetext" würde hier Folgendes tun: * - An "ausgabetext" so viele Leerzeichen hängen, bis die * Maximallänge (20 Zeichen) voll ist. * - Einen Zeilenumbruch anhängen. * Da wir das nicht wollen, müssen wir hier stattdessen die * intrinsische Funktion trim() verwenden, die die meisten * aktuellen COBOL-Implementierungen unterstützen, und * wiederum "WITH NO ADVANCING" anhängen, damit am Ende der * gesamte <h1>-Tag in einer Zeile steht.
DISPLAY FUNCTION TRIM (ausgabetext TRAILING) WITH NO ADVANCING END-DISPLAY.
* HTML-Text unten: * (Wir sind immer noch in der <h1>-Zeile!) DISPLAY "</h1>" DISPLAY " </body>" DISPLAY "</html>"
STOP RUN. |
Wenn ihr das Programm jetzt noch einmal kompiliert und lokal ausführt, ist das Ergebnis
natürlich merkwürdig:
Klar: Ohne Webserver kein
HTTP_ACCEPT_LANGUAGE. Versuchen wir es doch mal hinter unserem FastCGI:
Tatah!
Alles Weitere überlasse ich euch. Ihr wollt eine "richtige" Website mit Routing und allem? Das ist
gar kein Problem.
Diese Anleitung ist übrigens das Ergebnis von einem Tag mit COBOL. Wenn hier jemand mit mehr Erfahrung reinguckt: Entschuldigung! Ergänzungen sind gern gesehen. Sicherlich werde ich auch noch besser.