EFEU Programmierung

Werbung
EFEU Programmierung
E
rühstück
rich
E F
Erich Frühstück
ntwicklungs
U
mgebung
Programmentwicklung mit EFEU
Vorwort
Dieses Buch wendet sich an Programmentwickler und Anwender unter UNIX, die für ihre Arbeit
die Werkzeuge und Programmbibliotheken von EFEU nutzen wollen.
Bei EFEU1 Erich Frühstück Entwicklungs-Umgebung handelt es sich um eine Entwicklungsumgebung zur Bildung von Programmbibliotheken und Anwenderprogrammen sowie eine Reihe von
Hilfswerkzeugen für die tägliche Arbeit.
Besondere Eigenschaften:
• Umfangreiche C-Programmbibliotheken;
• Makefilegenerierung mit C-Preprozessor aus einem Imakefile oder direkt aus dem Sourcebaum;
• Mathematische Funktionen zum Arbeiten mit Datenwürfeln (beliebigdimensional), Polynomen und Zeitreihen;
• Befehlsinterpreter mit C++-ähnlicher Syntax;
• Generierung von Sourcecode aus Schablonendateien;
• Handbuchgenerierung aus Sourcefiles;
• Dokumentsprache mit einfacher Syntax, komplexen Einbindemöglichkeiten und verschiedenen Ausgabeformaten (LATEX, HTML, roff, . . . ).
Die EFEU-Implementierung bei Synthesis enthält zusätzlich noch eine Reihe von Programmbibliotheken und Kommandos zur Auswertung und Verwaltung von administrativen Daten und für
Modellrechnungen. Diese zum Teil sehr umfangreichen Module werden in eigenen Handbüchern
behandelt.
In der ursprünglichen Form sollte dieses Handbuch den Schwerpunkt C-Programmierung haben,
nach Rücksprache mit Mitarbeitern des Instiutes habe ich den EFEU-Interpreter in den Vordergrund gestellt.
Trotzdem werden weiterhin einige Ausführungen zur C-Programmierung ins Handbuch einfließen.
Zum einen weist der EFEU-Interpreter eine starke Affinität zu C/C++ auf, zum anderen ergeben
sich dadurch tiefere Einblicke in die zugrundeliegenden Programmbibliotheken.
Erich Frühstück
Wördern, Mai 2001
1
1
Inhaltsverzeichnis
1 Einleitung
4
1.1
Entwicklung des EFEU-Interpreters . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.2
Verwendung als Tischrechner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.2.1
Editieren der Befehlszeilen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.3.1
7
1.3
Ausführbarkeit von Skripts . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Programmkonfiguration
8
2.1
Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.2
Konfigurierbare Version von Hello World . . . . . . . . . . . . . . . . . . . . . . . .
8
2.2.1
EFEU-Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.2
Esh-Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
Konzept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
2.3.1
Konfigurationsparameter laden . . . . . . . . . . . . . . . . . . . . . . . . .
12
2.3.2
Befehle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
2.3.3
Zusatzinformationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
Konfigurationsdatei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.4.1
16
2.3
2.4
Standardoptionen
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Grundkurs esh
3.1
3.2
19
Syntaktische Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.1.1
Ausdrücke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.1.2
Präprozessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
3.1.3
Systemaufrufe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
Konstanten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
3.2.1
Ganzzahlwerte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
3.2.2
Zeichenketten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
3.2.3
Gleitkommawerte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2
INHALTSVERZEICHNIS
3.3
3
Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
3.3.1
Namen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
3.4
Funktionen und Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
3.5
Kontrollstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
3.5.1
Schleifen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
3.5.2
Switch-Anweisung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
Programmumgebung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.6.1
Programmargumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.6.2
Umgebungsvariablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.6
Kommandos
efeuscript – Installation von Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Impressum
27
28
31
Kapitel 1
Einleitung
1.1
Entwicklung des EFEU-Interpreters
Die EFEU-Shell esh steht nicht nur für das Kommando gleichen Namens, sondern auch für einen
Interpreter, der über C-Bibliotheksfunktion aufgerufen wird. Er nimmt nicht nur eine zentrale
Stellung im Rahmen von EFEU ein, sondern ist insbesonders ein wichtiges Werkzeug für die Datenanalysen von Synthesis.
Mein erster Versuch einen Befehlsinterpreter zu schreiben reicht weit zurück. Anfang der 80-er
Jahre habe ich – weniger aus Notwendigkeit als aus Lust am Programmieren – am Rechner des
physikalischen Institutes in Wien meine erste Version eines Befehlsinterpreters geschrieben. Damals
kannte ich UNIX und C noch nicht und ich verwendete Fortran. Von dieser Version sind, außer
Erinnerungen, keine Spuren zurückgeblieben.
Anfang der 90-er Jahre arbeitete ich an der automatischen Generierung von Berichten aus Datenmatrizen. In den dafür verwendeten Skripten zur Datenaufbereitung reichten einfache Datenabfragen nicht mehr aus, es waren auch Berechnungen notwendig. Ich brauchte also schnell einen
Befehlsinterpreter. Dieser war, motiviert von Erfahrungen mit PostScript, zunächst stackorientiert.
Ein stackorientierter Interpreter läßt sich schnell implementieren. Seine Verwendung ist allerdings
nicht benutzerfreundlich. Die Auflösung von Termen und die richtige Abfolge der Funktionsaufrufe verbleibt beim Anwender. Auch muß man sich immer wieder Gedanken machen, in welcher
Reihenfolge die Daten am Stack liegen, wie sie der nächste Funktionsaufruf benötigt und welche
Umordnungen notwendig sind.
Daher begann ich wieder an einem Befehlsinterpreter zu arbeiten. Da ich bereits langjährige Erfahrung in C hatte und diese Sprache lieben gelernt habe, wollte ich einen C-ähnlichen Interpreter
schreiben. Primär sollte er von C-Programmen zur Auswertung von Konfigurationsskripts eingesetzt werden. Daher wollte ich, dass vom Interpreter direkt auf C-Datenstrukturen zugegriffen
werden kann und einfache Schnittstellen zu C-Bibliotheksfunktionen bestehen.
Im Jahr 1994 war der EFEU-Interpreter einsetzbar, und es stand auch das esh-Kommando zur
Verfügung. Seine erste wichtige Anwendung war die Umstellung des Wohnungsmarktmodelles auf
esh. Dabei kommt eine Version des Interpreters mit zusätzlichen Funktionen speziell für das Wohnungsmarktmodell zum Einsatz. Hier erwies sich auch die Nähe zu C als sehr nützlich. Zeitaufwendige Algorithmen konnten schrittweise durch C-Funktionen ersetzt werden, um die Laufzeit des
Wohnungsmarktmodelles zu verbessern.
In den nächsten Jahren wurde der Interpreter zunehmend um Funktionen erweitert. So wurde eine
Reihe von Hilfsprogrammen zur Manipulation von Datenmatrizen in esh-Skripts umgewandelt.
4
KAPITEL 1. EINLEITUNG
5
Treibende Kraft dafür war einerseits das Wohnungsmarktmodell und andererseits die Berichtsgenerierung. Mit der Entwicklung von texmerge im Jahr 1996 wurde der weiterhin noch verwendete
stackorientierte Interpreter endgültig durch esh ersetzt.
Ich habe mich mit C++ und objektorientierter Programmierung auseinandergesetzt, ohne aber
auf C++ umzusteigen1
Die Gründe dafür lagen zunächst in der Verfügbarkeit – C ist im Gegensatz zu C++
Bestandteil eines jeden UNIX-Systems – und im Overhead von C++ gegenüber von C.
Später hatte ich bereits soviele objektorientierte Techniken und Hilfsfunktionen für C
entwickelt, dass ein Umstieg nicht mehr angesagt war.
. Der esh-Interpreter hat aber deutlich davon profitiert, er wurde um objektorientierte Sprachelemente erweitert. In seiner heutigen Form stellt er durchaus eine Alternative zu Programmen in
C++ dar, wenn Laufzeit (Interpreter!) kein Problem darstellt.
1.2
Verwendung als Tischrechner
Die Einsatzmöglichkeiten von esh sind vielfältig, so eignet er sich hervorragend als Tischrechner.
Wird esh ohne Argumente aufgerufen, startet er im interaktiven Mode und meldet sich mit dem
Prompt esh: “. Im folgenden ist ein typischer Dialog mit esh dargestellt (Zeilen ohne Prompt
”
sind Ausgaben von esh):
esh: 3*5
15
esh: double x = sqrt(2)
1.41
esh: float_prec = 5
5
esh: x
1.41421
esh:
Beendet wird esh durch Eingabe des Dateiendezeichens (^D) am Prompt. Ein esh-Skript kann
auch mit der Funktion exit(n) beendet werden. Das Argument n bestimmt den Rückgabewert
des Kommandos.
Mit der ersten Befehlszeile wird der Ausdruck 3*5 berechnet. Die zweite Befehlszeile definiert die
Variable x vom Type double und initialisiert sie mit der Quadratwurzel von 2. In der dritten
Zeile wird die interne Variable float prec auf 5 gesetzt. Am Ende wird der Wert der Variablen x
abgefragt.
Anders als in anderen Skriptsprachen müssen Variablen vor ihrer Verwendung deklariert werden.
Die Deklaration kann aber an beliebiger Stelle erfolgen und gleich mit einer Wertzuweisung (wie
im obigen Beispiel) verbunden werden. Auch kommen in esh die unterschiedlichsten Datentypen
zum Einsatz. Andere Skriptsprachen verwenden oft nur Zeichenketten und Gleitkommazahlen.
Eine Befehlszeile wird wahlweise mit einem Zeilenvorschub oder einem Strichpunkt abgeschlossen.
Bei einem Strichpunkt wird die Befehlszeile ausgewertet, aber das Resultat nicht ausgegeben. Diese
Konzeption habe ich octave2
Dabei handelt es sich um eine Skriptsprache für numerische Berechnungen. Ich habe
sie eine Zeit lang zur Berechnung von Regressionen verwendet, bevor ich diese Funktionalität in esh eingebaut habe.
1
2
KAPITEL 1. EINLEITUNG
6
abgeschaut.
Falls esh in einer Endlosschleife hängt oder man das Ende einer längeren Berechnung nicht abwarten will, kann das Kommando auch mit einem Interrupt (^C) abgebrochen werden.
1.2.1
Editieren der Befehlszeilen
Im interaktiven Modus verwendet esh Readline zur Eingabe von Befehlszeilen. Damit können Befehlszeilen erneut abgerufen und editiert werden. Readline wird auch von der bash und anderen
interaktiven Kommandos wie gdb, gnuplot oder octave verwendet. Ich setze die Editiermöglichkeiten der bash als bekannt vor und gehe daher hier nicht weiter darauf ein. Eine ausführliche
Referenz findet sich in [2, A.16, Seite 1047].
Analog zur bash können History-Zeilen nicht nur über Editierzeichen, sondern auch über eingebaute
Kommandos aktiviert werden. Sie sind im folgenden aufgelistet:
!h[istory] [n]
listet die letzen n Befehle auf. Die Voreinstellung für n ist 10.
!h[istory] n k
listet die History-Zeilen n bis k auf.
!r [n [k ]]
führt die History-Zeilen n bis k erneut aus. Fehlt die Angabe von k wird Zeile n ausgeführt,
fehlt auch n, wird die letzte Zeile ausgeführt.
!fc [n [k ]]
ladet die History-Zeilen n bis k in einem Editor (Standardkonfiguration: vi) und führt sie
nach dem Speichern aus.
Zusätzlich gibt es noch den eingebauten Befehl !eof, der wie die Eingabe des Dateiendezeichens
wirkt. Die Befehle !history, !r, !fc und !eof müssen unmittelbar am Zeilenanfang eingegeben
werden und stehen nur im interaktiven Modus zur Verfügung.
Die History-Zeilen werden nur dann gesichert, wenn esh mit dem Dateiendezeichen (^D) beendet
wird. Bei einer Beendigung mit exit oder einem Abbruch mit Interrupt (^C) werden sie nicht
ausgegeben.
Eine esh-spezifische Vervollständigung von Befehlszeilen ist derzeit noch nicht implementiert.
Aufgabe1-1. Rufen sie esh auf und geben sie einzelne Terme ein.
Aufgabe1-2. Wiederholen sie einzelne Befehlszeilen unter Zuhilfenahme der History Funktionen.
1.3
Hello World
Viele Bücher zur Programmentwicklung, insbesonders in der UNIX-Welt beginnen mit dem bekanntesten aller Programme, nämlich Hello World“.
”
Hier ist der Quellcode der Datei hello1.c, die klassische Variante von Hello World“.
”
#include <stdio.h>
int main (int argc, char **argv)
{
printf("Hello World!\n");
return 0;
KAPITEL 1. EINLEITUNG
7
}
Kompiliert wird das Programm mit dem Befehl
cc -o hello1 hello1.c
Sehen wir uns nun die Datei hello2.esh an, die Esh-Version von Hello World“.
”
printf("Hello World!\n");
Aufgerufen wird das Skript mit
esh hello2.esh
Achtung: Der Strichpunkt am Ende der Zeile ist notwendig, da sonst der Rückgabewert von printf
– die Zahl der ausgegebenen Zeichen – ebenfalls ausgegeben wird.
1.3.1
Ausführbarkeit von Skripts
Um ein esh-Skript ausführbar zu machen, benötigt es als erste Zeile einen speziellen Eintrag der
Form:
#!/bindir /esh
der das Betriebssystem darüber informiert, dass das Skript vom Kommando esh interpriert werden
soll. Für bindir muss aber der absolute Pfadname des Installationsverzeichnisses von esh angegeben
werden. Da aber EFEU an den verschiedensten Stellen im System installiert sein kann, sind solche
Skripts auf andere Rechner nicht übertragbar. Daher wird ein Trick angewendet und folgende Zeile
eingefügt:
#!/usr/bin/env esh
Das Kommando env dient eigentlich dazu, ein Kommando in veränderter Umgebung ausführen zu
lassen. Diese Funktionalität wird zwar nicht benötigt, aber es erlaubt den Start des esh-Interpreters
ohne absolute Pfadangabe.
Damit das Skript auch ausführbar ist, muß noch der Dateimodus mit dem Befehl chmod geändert
werden:
chmod a+x hello2.esh
Alternativ dazu können diese Schritte mit dem Hilfsprogramm efeuscript durchgeführt werden.
Es dient zur Installation eines Skriptfiles und wird in der Regel in Makefiles verwendet. Eine genaue
Beschreibung des Kommandos findet sich im Anhang.
Ein Esh-Skript wird mit den Optionen -e -c esh installiert. Falls das Sourcefile den Filezusatz
.esh“ enthält, sind keine Optionen notwendig, die Einstellungen werden automatisch an Hand
”
des Filenamens ermittelt. Das obige Programmbeispiel kann also folgend installiert werden:
efeuscript hello2.esh bindir /hello2
Kapitel 2
Programmkonfiguration
2.1
Allgemeines
Die X/Open-Spezifikation definiert eine standardisierte Verwendung von Kommandozeilenoptionen. Daneben bietet sie eine standardisierte Programmierschnittstelle für die Bereitstellung von
Kommandozeilenschaltern in C-Programmen: die Funktion getopt.
In EFEU wird ein ähnlicher Weg gegangen, jedoch wird die Konfiguration der Programmargumente
gleichzeitig mit ihrer Dokumentation verbunden. Weiters werden zusätzlich Umgebungsvariablen
und Argumente mit einbezogen.
Die Formatierung der Beschreibungstexte erfolgt mit efeudoc. Dokumente können damit in mehreren Formaten (roff, LATEX, HTML, . . . ) generiert werden. Weiters besteht die Möglichkeit, die
Aufrufsyntax direkt in eine längere Programmdokumentation einzubauen.
In der EFEU-Spezifikation können ähnlich wie in der GNU-Version von getopt Optionen an beliebiger Stelle, also auch nach den Argumenten, angegeben werden. Das Flag POSIXLY CORRECT, das
bei der GNU-Version von getopt diese Erweiterung deaktiviert, wird von EFEU nicht unterstützt.
Shell-Skripts und einzelne Kommandos, die für ihre Arbeiten keine Funktionen der EFEUBibliotheken benötigen, verwenden weiterhin getopt bzw. getopts. X11-Kommandos setzen
auf den X11-Standards zur Kontrolle der Programmargumente auf. Näheres dazu kann in den
einschlägigen Handbüchern1 Die Online-Handbücher sollten unter Linux verfügbar sein.
Eine gedruckte Version gibt es von O’Reilly unter dem Titel The X Window System“.
”
nachgelesen werden.
2.2
Konfigurierbare Version von Hello World
Zur Veranschaulichung der Programmkonfiguration wollen wir uns nun der konfigurierbaren Version des Programmbeispiels Hello World“ widmen. Diese erlaubt die Bestimmung von Ausgabe”
format und Ausgabetext über Kommandozeilenparameter.
Der Ausgabetext wird dabei durch das erste (optionale) Argument festgelegt, während das Ausgabeformat über die folgenden zwei Optionen gesteuert wird:
Der Ausgabetext wird unter Anführung gestellt.
-q
1
8
KAPITEL 2. PROGRAMMKONFIGURATION
9
-f fmt
Das Ausgabeformat kann beliebig vorgegeben werden.
Hier ist der Quellcode der Datei vhello1.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern int optind;
extern char *optarg;
int main (int argc, char **argv)
{
char *fmt = "%s";
char *label = "Hello World!";
int opt;
while ((opt = getopt(argc, argv, "qf:")) != -1)
{
switch (opt)
{
case ’q’:
fmt = "\"%s\"";
break;
case ’f’:
fmt = optarg;
break;
default:
exit(1);
}
}
if
(optind < argc) label = argv[optind];
printf(fmt, label);
putchar(’\n’);
exit(0);
}
Die Abfrage der Optionen erfolgt mit der Bibliotheksfunktion getopt(3). Ihre genaue Funktionsweise wird hier nicht weiter erläutert. Sie kann dem entsprechenden Handbuch entnommen werden,
oder bei [1, Kapitel 4] nachgelesen werden.
2.2.1
EFEU-Version
Nun wollen wir uns die Implementation von Hello World“ unter EFEU anschauen. Hier gibt es
”
eine Trennung zwischen Funktionalität eines Kommandos und seiner Oberfläche. Die Aufrufsyntax
wird in einer eigenen Konfigurationsdatei festgelegt, die erst beim Start des Kommandos geladen
wird. Das nächste Kapitel wird sich ausführlich mit der Konfiguration beschäftigen.
Sehen wir uns zuerst den Quellcode der Datei vhello2.c an:
#include <EFEU/Resource.h>
int main (int argc, char **argv)
KAPITEL 2. PROGRAMMKONFIGURATION
10
{
char *fmt, *label;
SetVersion("vhello2.c 1.0");
ParseCommand(&argc, argv);
fmt = GetResource("Format", "%s");
label = GetResource("Label", "Hello World!");
printf(fmt, label);
putchar(’\n’);
exit(EXIT_SUCCESS);
}
Die Funktion ParseCommand lädt die oben genannte Konfigurationsdatei, analysiert die Kommandoargumente und setzt Resourcen“ in einer internen Struktur. Der Argumentvektor argv wird
”
dabei umgeschrieben, nur argv [0] wird dabei nicht verändert.
Die Abfrage der Resourcen“ erfolgt mit der Funktion GetResource, wobei das erste Argument
”
den Namen der Resource angibt und das zweite Argument den Vorgabewert bestimmt, falls die
Resource nicht definiert wurde.
In EFEU-Programmen wird exit grundsätzlich nur mit einem der beiden (ANSI C) Makros
EXIT SUCCESS bzw. EXIT FAILURE aufgerufen. Diese sind in der automatisch immer eingebundenen
Headerdatei <stdlib.h> definiert.
Kompiliert wird das Programm mit dem Befehl
efeucc -o vhello2 vhello2.c -lefm
Das Kommando efeucc implementiert cc und sorgt dafür, das die Suchpfade für Headerdateien
und Programmbibliotheken entsprechend von EFEU erweitert werden. Abgesehen von der Angabe
der Programmbibliothek efm und dem anderen Kompilernamen gibt es hier keine Überraschungen.
Ohne Konfigurationsdatei – diese haben den gleichen Basisnamen wie das Kommando und den Zusatz .cnf“ – verhält sich das Kommando wie hello1. Im folgenden ist nun die Konfigurationsdatei
”
vhello2.cnf abgebildet, die nun für die gleiche Syntax wie vhello1 sorgt:
# Programmbeispiel: Hello World
# $Copyright (C) 2001 Erich Frühstück
Format = "%s"
Formatierungsanweisung für den Ausgabetext.
Label = "Hallo Welt!"
Ausgabetext.
q|-quote|Format = "\"%s\""
Gibt den Ausgabetext unter Anführung aus.
f:fmt|-format:fmt|Format
Setzt das Ausgabeformat, die Vorgabe ist |{Format}|.
::arg|Label
Bestimmt den Ausgabetext, die Vorgabe ist <"{Label}">.
Das erste Kommentar in der Konfigurationsdatei wird gesondert behandelt. Alle Zeilen bis zur
ersten Leerzeile bestimmen die Resource Ident (Programmtitel).
Beginnt eine der folgenden Zeilen mit der Kennung $C oder $c, bestimmt der Rest der Zeile
(Inklusive dem C oder c aber ohne $) die Resource Copyright.
KAPITEL 2. PROGRAMMKONFIGURATION
11
Damit können diese beiden Resourcen über das Kommentar gesetzt werden. Der Titel kann auch
mehrsprachig spezifiziert werden. Details dazu koönnen unter langfilter(3) nachgeschlagen werdenDie genaue Syntaxbeschreibung der Konfigurationsdatei folgt im nächsten Kapitel.
Die Vorteile der EFEU-Version werden sichtbar, wenn eines der folgenden Kommandozeilen ausgeführt wird:
vhello2 -?
gibt einen Überblick über die zulässigen Optionen und Argumente;
vhello2 --help
generiert einen Handbucheintrag für das Kommando;
vhello2 --help=lp
schickt den Handbucheintrag zum Drucker;
vhello2 --version
liefert die Versionsinformationen zum Kommando;
eis -p vhello2
erlaubt eine Abfrage der Kommandoparameter mit eis.
2.2.2
Esh-Version
Zum Abschluß wird hier die Esh-Version vom konfigurierbaren Hello World“ vorgestellt.
”
#!/usr/bin/env esh
/*
Programmbeispiel: Hello World!
$Copyright (C) 2002 Erich Frühstück
*/
pconfig !
Version = "vhello3.esh 1.0"
Format = "%s"
Formatierungsanweisung für den Ausgabetext.
Label = "Hallo Welt!"
Ausgabetext.
q|-quote|Format = "\"%s\""
Gibt den Ausgabetext unter Anführung aus.
f:fmt|-format:fmt|Format
Setzt das Ausgabeformat, die Vorgabe ist |{Format}|.
::arg|Label
Bestimmt den Ausgabetext, die Vorgabe ist <"{Label}">.
!
str fmt = getres("Format", "%s");
str label = getres("Label", "Hello World!");
printf(fmt, label);
putc(’\n’);
Die Konfiguration des Kommandos ist mit der speziellen Kontrollstruktur
KAPITEL 2. PROGRAMMKONFIGURATION
12
pconfig !
Konfigurationszeilen
!
im Skript integriert. Diese ruft nach der Interpretation der Konfigurationszzeilen automatisch die
Funktion ParseCommand auf. Die nachfolgenden Befehlszeilen unterscheiden sich kaum von der
C-Verson vhello2.c. Im Verhalten des Kommandos gibt es keinen Unterschied zu vhello2.
Auch hier wird das erste Kommemtar im Skript zur Bestimmung von Ident und Copyright herangezogen.
2.3
Konzept
Alle konfigurierbaren Parameter eines Kommandos werden in einer Resourcetabelle abgelegt. Jeder
Eintrag in diese Tabelle besteht aus einem Namen, einem Wert und einem Beschreibungstext. Die
einzelnen Komponenten sind Zeichenketten.
Für einen Namen sind grundsätzlich alle Zeichen zugelassen, jedoch empfiehlt es sich, nur Buchstaben, Zahlen, Unterstreichungszeichen und Punkte zu verwenden. Namen, die mit einem Punkt
beginnen, sind für eine interne Verwendungen reserviert und sollten nicht für einen Kommandoparameter verwendet werden.
Die einzelnen Resourcen werden im Programm mit der Funktion GetResource abgefragt. Dabei
wird der Resourcename und ein Vorgabewert angegeben. Dieser wird verwendet, wenn die Resource
nicht definiert ist oder einen Nullpointer als Wert zugewiesen hat.
Die Zuweisung von Werten zu den einzelnen Resourcen erfolgt bei der Analyse der Programmumgebung (Umgebungsvariablen) und der Befehlszeilenparameter (Optionen und Argumente). Gesteuert wird diese Zuweisung über Kommandodefinitionen. Diese setzen sich aus Kennungen (bestimmen die Aktivierung) und Befehlen (Verändern die Resourcen) zusammen. Die Kommandodefinitionen werden aus speziellen Konfigurationsdateien geladen.
2.3.1
Konfigurationsparameter laden
Das Laden der Konfigurationsparameter und die Analyse der Umgebungsvariablen, Optionen und
Argumente wird von der Funktion ParseCommand durchgeführt. Als Parameter wird ein Pointer auf
die Zahl der Argumente und der Argumentvektor selbst übergeben. Bei der Abfrage der Parameter
wird der Argumentvektor umgeschrieben. Im Regelfall besteht er nur mehr aus dem Aufrufnamen
des Kommandos.
Die Funktion ParseCommand lädt zwei Konfigurationsdateien: efm.cnf und name.cnf, wobei name
der Basisname des aufgerufenen Kommandos ist. Gesucht werden die Konfigurationsdateien in den
folgenden Verzeichnissen (TOP verweist auf die Hauptbibliothek der EFEU-Installation):
• in der aktuellen Bibliothek;
• im Verzeichnisnamen des Aufrufnamens (falls definiert);
• in den durch die Umgebungsvariable APLLPATH definierten Verzeichnissen;
• im Verzeichnis TOP /lib/efeu/$LANG/config, falls die Umgebungsvariable LANG definiert
ist;
• im Verzeichnis TOP /lib/efeu/config;
• im Verzeichnis $HOME/lib/efeu/config.
KAPITEL 2. PROGRAMMKONFIGURATION
13
Zu jeder Kennung gehört ein Parameterwert. Bei Umgebungsvariablen ist es der Wert der Umgebungsvariablen, ansonsten das Argument. Bei Optionen ohne Argument ist es ein Nullpointer.
Kennungen können einen Vorgabewert enthalten, der immer dann eingesetzt wird, wenn der Parameterwert ein Nullpointer ist.
Bestehen Definitionszeilen nur aus Befehlen, werden diese sofort beim Laden ausgewertet und
nicht gespeichert. Als Parameterwert wird ein Nullpointer verwendet. Meist werden mit solchen
Definitionszeilen Resourcen initialisiert.
Optionen sind Kommandozeilenargumente, die mit einem Minus - gekennzeichnet sind. In der
X/Open-Spezifikation handelt es sich um Einzeichenoptionen, EFEU erlaubt ähnlich wie der GNUStandard auch lange Optionskennungen. Lange Optionskennungen müssen nicht vollständig angegeben werden, ein signifikanter Teil der Kennung genügt. Lange Optionen beginnen üblicherweise
mit einem zusätzlichen Minus, bei EFEU handelt es sich hier aber im Gegensatz zu GNU nur um
eine Konvention.
Optionen können zwingende oder optionale Argumente besitzen. Einzeichenoptionen können in
einem Optionsstring kombiniert werden. Davon darf aber nur die letzte Option ein optionales oder
zwingendes Argument besitzen.
Ein optionales Argument muß unmittelbar an die Optionskennung angehängt werden, ein zwingendes Argument kann wahlweise an die Optionskennung angehängt oder das nächste Kommandozeilenargument sein. Bei langen Optionskennungen muß vor einem angehängten Argument das
Zuweisungszeichen =“ stehen.
”
Argumente sind alle Kommandozeilenargumente, die keine Option oder kein Optionsargument
sind. Es besteht die Möglichkeit, einen Teil der Argumente über reguläre Ausdrücke abzutesten.
Falls der reguläre Ausdruck ein Teilmuster enthält, wird für den Parameterwert nur der entsprechende Teil des Argumentes verwendet. Reguläre Ausdrücke werden hauptsächlich zur Abfrage von
Argumenten der Form name=val“ verwendet. Der entsprechende reguläre Ausdruck ist .*=.*“
”
”
Im EFEU-Standard wird ein Argument, das nur aus einem Minuszeichen -“ besteht, durch
”
einen Nullpointer ersetzt. Meist wird ein einzelnes Minus anstelle eines Dateinamens stellvertretend für die Standardeingabe bzw. Standardausgabe verwendet. Beginnt ein Argument mit einem
Schrägstrich, wird er entfernt und das darauffolgende Zeichen wird nicht interpretiert.
Diese Regeln gelten auch für Argumente von Optionen, aber nicht für Umgebungsvariablen und
reguläre Ausdrücke. Weiters erfolgt diese Interpretation nur, wenn das Argument abgefragt und
nicht nur geprüft wird. Siehe weiter unten!
Die Auswertung der Kommandodefinitionen erfolgt nach den folgenden Richtlinien:
• Zuerst werden die Umgebungsvariablen ausgewertet. Die zugehörigen Befehle werden nur
ausgeführt, wenn die Umgebungsvariable existiert oder die Kennung einen Vorgabewert verschieden von NULL enthält. Die Abfrage erfolgt in der Reihenfolge der Definition.
• Im nächsten Schritt wird die Kommandozeile nach Optionen analysiert. Die Abfrage erfolgt
in der Reihenfolge des Auftretens.
• Schlußendlich werden die Argumente in der Reihenfolge der Definition abgefragt. Hier gibt
es eine Besonderheit: Enthält die zugehörige Kommandodefinition keine Befehle, verbleibt
das Argument im Argumentvektor, sein Vorhandensein wird aber geprüft.
• Am Ende wird geprüft, ob alle Argumente des Argumentvektors verwendet wurden.
Bezieht sich eine Kennung auf mehrere Argumente (regulärer Ausdruck, variable Argumentliste),
werden die Befehle für jedes Argument einzeln aufgerufen.
Wurde das Kommando mit zu wenigen oder zu vielen Argumenten aufgerufen, wird eine kurze
Syntaxbeschreibung ausgegeben und das Kommando abgebrochen.
KAPITEL 2. PROGRAMMKONFIGURATION
2.3.2
14
Befehle
Die einzelnen Befehle werden durch den Namen der zugehörigen Programmresource, einer Auswertungsfunktion und einem optionalen Funktionsargument definiert.
Falls der Befehl nur aus dem Resourcenamen besteht, wird die Resource auf den Parameterwert
gesetzt. Eine weitere Spezialform ist die Zuweisung: Hier wird die Resource mit dem Wert des
Funktionsarguments belegt, der Parameterwert wird ignoriert. Diese kommen bei der Initialisierung
von Resourcen oder bei Flags (Optionen ohne Argumente) zum Einsatz.
Folgende Funktionen sind definiert:
message fmt
gibt eine Meldung am Standardfehlerkanal aus.
set fmt
setzt den Wert der Resourcevariablen entsprechend der Formatdefinition fmt .
insert delim
fügt den Parameterwert am Anfang der Resourcedefinition mit Trennzeichen delim ein.
append delim
hängt den Parameterwert mit Trennzeichen delim ans Ende der Resourcedefinition.
config name
ladet die Konfigurationsdatei mit Namen name.
usage fmt
generiert eine Aufrufverwendung entsprechend der Formatanweisung fmt und schreibt sie auf
den Standardfehlerkanal.
manpage name
generiert einen Handbucheintrag und schreibt in nach name. Dabei handelt es sich in der
Regel um eine Pipeline mit Formatierungskommandos.
info name
ruft spezifische Informationseinträge über das Kommando ab.
exit val
bricht das Kommando mit Exit-Status val ab. Wird meist mit Informationsabfragen über
das Kommando kombiniert.
break
bricht die Optionsabfrage ab. Diese Funktion ist nicht für den Standardgebrauch gedacht,
da ParseCommand nicht zwischen Fehler und Abbruch unterscheidet, es gibt aber Low-Level
Funktionen, mit denen das möglich ist.
Mit Ausnahme von insert, append und exit wird das Argument der Auswertungsfunktion mit
CmdPar psub überarbeitet. Dabei werden Parameterwerte und Recourcewerte im Argument eingefügt.
Falls das Funktionsargument NULL ist, wird es durch den Parameterwert ersetzt.
Ein Dollar $ leitet eine Parametersubstitution im Sinne von parsub(3) ein. Die möglichen Formate
sind konfigurationsabhängig. Ein Ausdruck Substitutionsdefinitionen der Form {name} wird durch
den Resourcewert von name ersetzt. Ein leerer Ausdruck {} wird durch den Parameterwert der
Kennung ersetzt. Eine Resourceabfrage kann beliebige Substiutionen enthalten, eine Parametersubstitution kann aber nicht geschachtel werden.
Bei der Ersetzung werden Anführungen und Attribute kontrolliert und einzelne Zeichen bei Bedarf
geeignet maskiert. Vergleiche dazu CmdPar psub(3).
KAPITEL 2. PROGRAMMKONFIGURATION
2.3.3
15
Zusatzinformationen
Sämtliche Konfigurationsparameter werden in einer Struktur vom Type CmdPar gespeichert. Die
Funktionen ParseCommand und GetResource arbeiten nur mit einer global definierten Struktur
dieses Types. Es besteht aber die Möglichkeit, mehrere solcher Strukturen zu verwalten und auszuwerten. Detailierte Informationen dazu können in den entsprechenden Handbucheinträgen der efmProgrammbibliothek nachgeschlagen werden. Vergleiche dazu CmdPar(3), CmdParCall(3), CmdParDef(3), CmdParEval(3), CmdParKey(3), CmdParVar(3), CmdPar eval(3), CmdPar list(3),
CmdPar load(3), CmdPar psub(3), CmdPar usage(3), CmdPar write(3), Resource(3) und CmdPar(7).
Die Liste der Auswertungsfunktionen kann erweitert werden. So wird bei der Initialisierung des eshInterpreters die Funktion eval definiert, die das Funktionsargument nach der üblichen Parametersubstitution als esh-Ausdruck auswertet. Die Erweiterung muß vor dem Aufruf von ParseCommand
erfolgen.
2.4
Konfigurationsdatei
Eine Konfigurationsdatei für Programmparameter ist zeilenweise aufgebaut und setzt sich aus den
folgenden Zeilentypen zusammen:
• Kommentare: Diese sind mit einem Gittersymbol in der ersten Spalte gekennzeichnet.
• Beschreibungstexte: Diese sind durch einen Tabulator in der ersten Spalte gekennzeichnet.
Aufeinanderfolgende Beschreibungstexte gehören zusammen. Beschreibungstexte nach einem
Kommentar oder einer Leerzeile werden ignoriert.
• Definitionszeilen: Das sind alle anderen Zeilen, die nicht mit einem Gittersymbol oder einem
Tabulator beginnen.
Eine Definitionszeile besteht aus einer Liste von Kennungen, gefolgt von einer Liste von Befehlen. Die einzelnen Kennungen werden von einem Pipesymbol | begrenzt, die Befehle durch einen
Strichpunkt ; oder den Zeilenvorschub am Ende einer Zeile.
Eine allgemeine Definitionszeile ist damit folgend aufgebaut:
. . . [Kennung |] [Kennung |] Befehl [; Befehl ] . . .
Aufeinanderfolgende Leerzeichen und Tabulatoren vor und nach einem Trennzeichen werden ignoriert, innerhalb einer Kennung oder eines Befehles werden sie auf ein Leerzeichen reduziert.
Folgende Kennungen sind definiert:
@name
Umgebungsvariable name,
name
Option -name ohne Argument,
name:arg
Option -name mit zwingendem Argument,
name::arg
Option -name mit optionalem Argument,
:arg
notwendiges Argument,
KAPITEL 2. PROGRAMMKONFIGURATION
16
::arg
optionales Argument,
$arg
letztes Argument,
*arg
variable Argumentliste mit beliebig vielen Argumenten,
+arg
variable Argumentliste mit mindestens einem Argument,
/regex /arg
Argument, das dem regulären Ausdruck regex entspricht.
Der Parameter arg wird für die Darstellung der Kommandosyntax verwendet. Er wird standardmäßig in kursiv gesetzt, bei regulären Ausdrücken wird Schreibmaschinenschrift verwendet.
Jede Kennung kann einen Vorgabewert enthalten. Dieser wird in eckigen Klammern gesetzt und
am Ende der Kennung angegeben. Der Vorgabewert kommt zum Einsatz, wenn bei einer Option
mit optionalem Argument dieses nicht angegeben wurde, oder wenn anstelle eines Arguments ein
einzelnes Minuszeichen steht.
Optionen, die aus mehr als einem Zeichen bestehen, sollten mit einem Minuszeichen -“ beginnen.
”
Damit werden einerseits Konflikte mit Einzeichenoptionen vermieden und die Kommandosyntax
ist GNU-kompatibel.
Befehlskennungen sind folgend aufgebaut:
name
Der Befehl besteht nur aus dem Resourcenamen name.
[name] = [val ]
Bei dem Befehl handelt es sich um eine Zuweisung.
[name] : func [arg]
Hier handelt es sich um eine allgemeine Befehlskennung. Der Resourcename name ist optional,
aber das Trennzeichen :“ muß zwingend vorhanden sein. Das Funktionsargument arg ist
”
durch Leerzeichen oder Tabulatoren vom Funktionsnamen func zu trennen.
Beachte den Unterschied zwischen der Zuweisung name = val“ und der Befehlskennung name:
”
”
set val“. Im ersten Fall erhält name den Wert von val ohne, im zweiten Fall mit Substitution von
Parameterwerten.
Der Beschreibungstext nach einer Definitionszeile dient zur Erläuterung der einzelnen Befehlszeilen
und wird zur Konstruktion des Handbucheintrages verwendet. Folgt ein Beschreibungstext einer
Definitionszeile ohne einer Kennung, dient er zur Beschreibung der Resourcevariablen des letzten
Befehls.
Obwohl der Vorgabewert einer Kennung am Ende stehen sollte, wird er an jeder beliebigen Position akzeptiert. Die Interpretation der Leerzeichen oder der speziellen Trennzeichen kann durch
Setzen von Anführungszeichen (einfach oder doppelt) oder mit dem Backslash als Fluchtsymbol
unterbunden werden.
2.4.1
Standardoptionen
Eine Reihe von Optionen ist bereits vordefiniert. Im folgenden wird die Datei efm.cnf aufgelistet,
die von jedem Kommando automatisch geladen wird:
KAPITEL 2. PROGRAMMKONFIGURATION
# :*:common options of EFEU-commands
# :de:Basisoptionen für EFEU-Kommandos
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
Copyright (C) 2001 Erich Frühstück
This file is part of EFEU.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.Library.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
# :*:predefined resources
# :de:Vordefinierte Resourcen
Ident = ":*:command:de:Kommando:_: $!"
:*:short description of command
:de:Kurzbeschreibung des Kommandos
Version
:*:command version
:de:Versions/Revisionsnummer des Kommandos
Copyright
:*:copyright information
:de:Copyright-Informationen
Debug = note
:*:debug level for messages
:de:Debug-Level für Meldungsausgabe
GZIP = "-n1"
:*:compression mode for gzip
:de:Komprimierungsgrad für gzip
# :*:dummy entries for direct evaluated environments
# :de:Dummy-Einträge für direkt abgefragte Umgebungsvariablen
@APPLPATH|
:*:path for configuration files.
:de:definiert zusätzliche Verzeichnisse für Konfigurationsdateien.
@LANG|
:*:locale information
:de:bestimmt die Sprache für Meldungen und Hilfetexte.
:config help
# :*:info interface
# :de:Info - Schnittstelle
17
KAPITEL 2. PROGRAMMKONFIGURATION
18
-info::entry|:info; :exit 0
:*:show command information
:de:listet verfügbare Informationseinträge des Kommandos auf.
# :*:debug-level
# :de:Debug-Modus
-debug::mode[.debug]|Debug
:*:set debug level for command
See \mref{LogConfig(3)} for details.
:de:setzt den Protokollmodus für das Kommando.
Vergleiche dazu \mref{LogConfig(3)}.
-verbose|Debug = .info
:*:set debug level to |.info|.
:de:setzt den Debug-Level auf |.info|.
Aufgabe2-1. Schreiben sie ein Skript, dass möglichst alle Options- und Argumentdefinitionen
verwendet und die entsprechenden Parameter ausgibt. Kombinieren sie mehrere Optionskennungen
(z.B: Einbuchstabenkennung und langer Optionsname) zur Setzung eines Parameters. Setzen sie
mehrere Parameter mit einer Optionsdefinition.
Kapitel 3
Grundkurs esh
3.1
Syntaktische Grundlagen
Die Eingabezeilen werden durch einen Präprozessor gefiltert und können Kommentare enthalten.
Die Direktiven (Präprozessorbefehle) werden mit einem Gittersymbol #“ eingeleitet und enden
”
beim nächsten Zeilenvorschub.
Kommentare können wie in C++ Programmen wahlweise durch /* . . . */ oder // . . . Zeilenvorschub gekapselt werden.
3.1.1
Ausdrücke
Ausdrücke beginnen entweder mit einem Schlüsselwort oder stellen einen Block oder Term dar.
Die Schlüsselwörter generieren Kontrollstrukturen oder spezielle syntaktische Konstruktionen. Sie
werden später noch detailiert dargestellt.
Ein Block wird mit geschwungenen Klammern { . . . } abgegrenzt und besteht aus einer Liste von
Ausdrücken. Blöcke kommen in der Regel bei Funktionsrumpfen, Schleifen und Testblöcken zum
Einsatz.
Ein Ausdruck, der nicht mit einer geschwungenen Klammer beginnt, wird als Term gelesen. Terme
sind Kombinationen von Konstanten, Variablen und Funktionsaufrufen mit Operatoren, z.B:
3 *
3 *
x =
int
a <
5
(x + 5)
sqrt(7)
x = 13
5 || b > 10
Ein Term wird entweder mit einem Strichpunkt oder einem Zeilenvorschub aufgerufen. Wird ein
Term der äußersten Ebene mit einem Zeilenvorschub abgeschlossen, wird das Ergebnis des Terms
ausgegeben. Ergebnisse von Termen, die mit einem Strichpunkt abgeschlossen werden oder innerhalb eines Blocks stehen, werden nicht ausgewertet.
Terme der äußersten Ebene werden unmittelbar nach dem Lesen ausgewertet. Blöcke werden
erst ausgeführt, nachdem sie vollständig gelesen wurden. Einzige Ausnahme: Terme, denen das
Schlüsselwort const oder static vorangestellt wird, werden immer sofort nach dem Lesen ausgeführt. Die Verwendung von static wird bei der Beschreibung der Variablen 3.3.1 auf Seite 22
erklärt.
19
KAPITEL 3. GRUNDKURS ESH
20
Die automatische Ausgabe von Berechnungsergebnissen dient primär der interaktiven Verarbeitung. In Skripts empfiehlt es sich, jeden Term mit einem Strichpunkt abzuschließen und Ausgaben
über Ausgabefunktionen zu steuern.
3.1.2
Präprozessor
Der verwendete Präprozessor hat eine ähnliche Syntax wie der C-Präprozessor. Es gibt jedoch
einen wesentlichen Unterschied: Der Präprozessor wird nicht zur Vorverarbeitung der gesamten
Datei verwendet, sondern ist zeilenweise implementiert und arbeitet direkt mit dem Befehlsinterpreter zusammen. Insbesonders kann durch verändern von Variablen im Befehlsmodus auch die
Verarbeitung nachfolgender Präprozessorzeilen beeinflußt werden.
Eine Direktive, bei der nach dem Startzeichen #“ ein Sonderzeichen folgt, wird ebenfalls als
”
Kommentarzeile betrachtet. Insbesonders gilt das auch für die Zeile:
#!/efeu/bin/env esh
Durch Einfügen dieser Zeile zu Beginn der Datei kann ein Skript ausführbar gemacht werden. Diese
Eigenschaft des Präprozessors sollte ausschließlich für den eben dargestellten Zweck und nicht für
allgemeine Kommentare verwendet werden.
Die folgenden Präprozessordirektiven können verwendet werden:
#include <file>
Einbinden der Datei file. Die Suche erfolgt in den durch die Variable IncPath definierten
Verzeichnissen.
#include "file"
Wie oben, jedoch zusätzliche Suche im aktuellen Verzeichnis, falls dieses nicht im Suchpfad
enthalten ist.
#if expr
Falls der Ausdruck expr logisch wahr liefert, werden die nachfolgenden Zeilen interpretiert,
ansonsten übersprungen.
#elif expr
Falls kein vorangegangener Ausdruck einer #if oder #elif Anweisung logisch wahr war und
expr einen logisch wahren Ausdruck liefert, werden die nachfolgenden Statements ausgeführt.
#else
Falls kein vorangegangener Ausdruck einer #if oder #elif Anweisung logisch wahr war,
werden die nachfolgenden Statements ausgeführt.
#endif
Ende eines Abfrageblockes.
#define name repl
Definiert einen Makro name der durch repl ersetzt wird.
#define name(arglist ) repl
Definiert einen Makro name mit Argumenten. Die öffnende Klammer muß unmittelbar nach
dem Namen folgen.
#undef name
Löscht die Definition des Makros name
#ifdef name
Testet, ob der angegebene Makro definiert ist.
KAPITEL 3. GRUNDKURS ESH
21
#ifndef name
Testet, ob der angegebene Makro nicht definiert ist.
#error Text
Liefert eine Fehlermeldung.
3.1.3
Systemaufrufe
Systemaufrufe können direkt in EFEU-Skripts eingebaut werden. Jede Zeile, die mit einem !
beginnt, wird als Systemaufruf interpretiert. Ausnahmen davon sind nur readline-Kommandos im
interaktiven Modus. In die Befehlszeile können Parameter mit der üblichen Parametersubstitution
eingebaut werden (Vergleiche dazu parsub). Alternativ dazu steht die Funktion system() zur
Verfügung.
3.2
Konstanten
3.2.1
Ganzzahlwerte
Wie in C gibt es auch in esh eine Reihe von Ganzzahldatentypen. Es gibt jedoch einige Unterschiede:
bool
ist ein Ganzzahltyp für logische Ergebnisse mit den Ausprägungen 0 (false) und 1 (true). Sie
sind über den C-Datentyp int implementiert.
byte
ist ein Ganzzahltyp mit einem Wertebereich von −128 bis 127. Er entspricht dem C-Datentyp
signed char.
short
entspricht dem C-Datentyp short.
int
entspricht dem C-Datentyp int.
long
entspricht dem C-Datentyp long int.
unsigned
entspricht dem C-Datentyp unsigned int.
size t
entspricht dem C-Datentyp long unsigned int, der in der Regel mit dem C-Datentyp
size t kompatibel sein sollte, aber nicht immer so definiert ist.
In Esh sind long und unsigned Datentypen, während es sich in C nur um Typmodifikatoren
handelt. Die Bytelängen der Ganzzahldatentyp sind architekturabhängig, sie entsprechen aber
immer dem gleichwertigen Datentyp in C.
In C wird für boolsche Werte der Datentyp int verwendet. In esh wird int vom Datentyp bool
abgeleitet (Vererbung) und kann damit immer auch anstelle eines boolschen Wertes eingesetzt
werden.
Ganzzahlkonstanten können wahlweise Dezimal, Oktal oder Hexadezimal angegeben werden. Eine
Hexadezimalzahl beginnt mit 0x“, gefolgt von den Hexadezimalziffern (0−9, a-f). Die Buchstaben
”
können wahlweise groß oder klein geschrieben werden. Eine Oktalzahl wird von einer Dezimalzahl
KAPITEL 3. GRUNDKURS ESH
22
durch eine führende 0 unterschieden. Sollte aber eine der Ziffern 8 oder 9 vorkommen, wird die
Konstante als Dezimalzahl interpretiert.
Ein nachgestelltes l“ symbolisiert einen langen Datenwert, ein nachgestelltes u“ einen vorzei”
”
chenfreien Datenwert. Diese beiden Flags können beliebig kombiniert werden und wahlweise groß
oder klein geschrieben werden.
Boolsche Konstanten werden durch die Schlüsselwörter true und false dargestellt. Es gibt keine
Ganzzahlkonstanten vom Typ byte oder short.
3.2.2
Zeichenketten
Ein einzelnes Zeichen wird durch einfache Anführungszeichen definiert, eine Zeichenkette (String)
durch doppelte Anführungszeichen. Eine Zeichendefinition darf mehrere Zeichen enthalten, es wird
aber nur das erste Zeichen verwendet.
Für sehr lange Zeichenketten gibt es eine alternative Konstruktion über das Schlüsselwort string
in Kombination mit ! als Begrenzungsmarke.
Teil des Ausdrucks vor der Zeichenkette string !
Zeichenkette
! Rest des Ausdrucks nach der Zeichenkette
Zwischen string und ! können beliebige Leerzeichen oder Tabulatoren stehen, nach ! muss ein
Zeilenvorschub folgen. Die Zeichenkette endet beim ersten ! unmittelbar am Zeilenbeginn.
Innerhalb der Zeichenkettendefinition werden Zeichen normal interpretiert, Präprozessordirektiven
(z.B. #include) und Kommentare werden interpretiert. Eine so definierte Zeichenkette ist immer
mit einem Zeilenvorschub abgeschlossen.
3.2.3
Gleitkommawerte
double
normale Gleitkommawerte.
float
kurze Gleitkommawerte.
Gleitkommakonstanten sind immer vom Typ double. Sie werden von Ganzzahlkonstanten durch die
Anwesenheit eines Dezimalpunktes oder eines Exponenten unterschieden. Alle Rechenoperationen
werden mit double ausgeführt. Bei großen Vektoren kann damit Speicherplatz auf Kosten der
Genauigkeit gespart werden.
3.3
3.3.1
Variablen
Namen
Ein Name besteht aus einer Folge von Buchstaben und Ziffern. Das erste Zeichen muß ein Buchstabe
sein. Ein Unterstreichungszeichen “ gilt als Buchstabe.
”
Mit Hilfe des Schlüsselwortes operator können auch beliebige Namen angesprochen werden. Der
Name wird dabei entweder unter doppelte Anführung gesetzt oder durch Leerzeichen bzw. Tabulatoren begrenzt. Nach dem Schlüsselwort dürfen Leerzeichen und Tabulatoren stehen. Obwohl diese
Konstruktion allgemein verwendet werden kann, sollte sie nur zur Definition von Operatorfunktionen (Funktionen, deren Aufruf durch einen Operator bewirkt wird) verwendet werden.
KAPITEL 3. GRUNDKURS ESH
23
Variablendefinitionen, denen das Schlüsselwort static vorangestellt ist, werden sofort beim Parsen
der Befehlszeilen eingerichtet. Innerhalb eines Blocks wird für statische Variablen eine andere
Variablentabelle als für dynamische Variablen (solche die erst bei der Abarbeitung des Blocks
angelegt werden) verwendet.
Die innerhalb eines Blocks definierten Variablen (statisch oder dynamisch) sind außerhalb des
Blocks nicht sichtbar.
Steht vor einer Variablendefinition das Schlüsselwort const, wird damit eine Konstante eingerichtet. Der mit der Zuweisung festgelegte Wert kann nicht mehr verändert werden.
3.4
Funktionen und Operatoren
Eine Funktionsdefinition hat die allgemeine Form
type name ( arglist )
expr
Normalerweise ist expr ein Block von Ausdrücken, in $! kann aber auch ein einzelner (nicht leerer) Ausdruck stehen. Falls die Funktion keinen Wert zurückliefern soll, ist als Datentyp void zu
verwenden.
Die folgenden Funktionsdefinitionen sind gleichwertig:
int f (int x) x + 1;
int f (int x) return x + 1;
inline int f (int x) { return x + 1; }
Im EFEU-Befehlsinterpreter hat das Schlüsselwort inline primär etwas mit Sichtbarkeit zu tun.
Eine inline Funktion sieht alle Variablentabellen, die auch in der Zeile mit dem Funktionsaufruf
sichtbar waren. Alle Funktionen, die nur aus einem einzelnen Ausdruck bestehen, gelten als inline
Funktionen.
Wie in C++ können Funktionsargumente Vorgabewerte besitzen. Diese müssen dann beim Aufruf
nicht angegeben werden. Die allgemeine Form eines Funktionsarguments ist:
type [ & ] name [ = value ]
Das & zeigt an, dass das Argument ein gültiger L-Wert sein muss. Eine Tilde ... anstelle des
Funktionsarguments steht für eine variable Argumentliste. Auf sie kann innerhalb der Funktion
unter dem Namen va list zugegriffen werden.
Virtuelle Funktionen
Wie in C++ können Funktionen mit verschiedenen Argumentlisten überladen werden. Überladene
Funktionen werden mit dem Schlüsselwort virtual deklariert. Der Datentyp solcher Funktionen
ist VirFunc. Jede Funktion kann in eine virtuelle Funktion konvertiert werden.
Eine virtuelle Funktion kann auch in eine gewöhnliche Funktion umgewandelt werden. Dies gechieht
mit einem Prototype-Cast wie im folgendem Beispiel:
Func f = operator+ (int a, int b);;
Nun kann f zur Addition von zwei Ganzzahlwerten verwendet werden. Beachte die zwei Strichpunkte am Ende der Zuweisung: Der erste gehört zum Prototype (und unterscheidet ihn von einer
Funktionsdefinition, der zweite schließt den Ausdruck ab.
Typgebundene Funktionen
Funktionen können auch an einen Datentyp gebunden werden. Sie haben die allgemeine Form:
KAPITEL 3. GRUNDKURS ESH
24
type btype::name [ & ] ( arglist )
expr
Falls nach dem Funktionsnamen ein & steht, kann die Funktion nur für L-Werte verwendet werden.
Eine gebundene Funktion wird folgend aufgerufen:
obj .name(args)
Dabei ist obj ein Objekt vom Type btype. Der Datentyp einer typgebundenen Funktion ist ObjFunc.
Dabei kann es sich sowohl um eine virtuelle, als auch um eine gewöhnliche Funktion handeln.
In gebundenen Funktionen kann mit dem Schlüsselwort this auf das zugehörige Datenobjekt
zugegriffen werden.
Operatoren
Operatoren werden intern wie Funktionen behandelt. Mit dem Schlüsselwort operator kann ein
Operatorname direkt angesprochen werden. Folgende Schreibweisen sind zulässig:
operator op
operator "op"
Bei der ersten Schreibweise muß nach op ein Leerzeichen folgen, vor op kann ein Leerzeichen stehen.
Damit linke Operatoren von rechten unterscheidbar sind, werden sie intern mit dem Zusatz ()
versehen (z.B: -() für die Negation. Dies ist bei der Definition von Funktionen zu beachten.
Folgende Terme sind gleichwertig:
a + b
operator+ (a, b)
Operatoren sind in der Regel virtuelle Funktionen. Alle Zuweisungsoperatoren sind gebundene,
virtuelle Funktionen.
Spezielle Funktionen
Funktionen, die den gleichen Namen wie ein zuvor definierter Datentyp haben, definieren Konstruktoren und Konverter. Konverter werden meist indirekt bei Zuweisungen, der Wertübergabe
bei Funktionsaufrufen oder durch explizite Typumwandlungen (casts) aufgerufen.
Konstruktoren haben die Form
virtual type type ( arglist )
Die spezielle Form
type type ()
wird Copy-Konstruktor genannt. Ist er definiert, wird er jedesmal beim Kopieren eines Datenelementes aufgerufen.
Im Gegensatz dazu ist
type type (void)
ein gewöhnlicher Konstruktor ohne Argumente.
Konverter haben die Form
KAPITEL 3. GRUNDKURS ESH
25
tg type src type ()
mit einer leeren Argumentliste.
Die Ausgangsdaten werden unter dem Namen this referiert. Falls der Zieldatentype void ist,
definiert die Funktion den Destruktor für den Datentyp, der jedesmal aufgerufen wird, wenn ein
Objekt diesen Types gelöscht wird.
Copy-Konstruktor und Destruktor können als Spezalfall eines Konverters gesehen werden. Wegen
der internen Speicherbereinigung werden sie kaum benötigt. Bei ihrer Definition ist besondere
Vorsicht notwendig: Sobald ein Objekt dieses Types kopiert wird (z.B. bei der Weitergabe an eine
andere Funktion), führt der Aufruf dieser Funktion zu einer endlosen Rekursion.
3.5
Kontrollstrukturen
3.5.1
Schleifen
while (cond ) cmd
do cmd while (cond )
Definiert eine Schleife. Der Ausdruck cmd wird solange ausgeführt, wie cond logisch wahr
ist. Bei cmd handelt es sich entweder um eine einfache Befehlszeile oder einen Block. Bei der
zweiten Form wird cmd zumindest einmal ausgeführt.
for (a; cond ; b) cmd
Zu Beginn der Verarbeitung wird a ausgeführt. Der Ausdruck cmd wird solange ausgeführt,
wie cond wahr ist. Nach jedem Schleifendurchlauf wird b ausgeführt.
for (name in list ) cmd
Für jedes Element der Liste list wird cmd ausgeführt. Name ist der Name einer temporären
Variablen, die das aktuelle Element der Liste enthält. Anstelle von list kann auch ein einzelnes
Objekt stehen, das in eine Liste konvertierbar ist (z.B: ein Vektor).
Bei Schleifen kann ein Block vorzeitig mit der break Anweisung verlassen werden. Die continue
Anweisung startet einen neuen Zyklus.
Bedingungen
if (cond ) cmd1
if (cond ) cmd1 else cmd2
Falls die Bedingung cond wahr ist, wird cmd1 ausgeführt, ansonsten wird, falls das Schlüsselwort else angegeben ist, cmd2 ausgeführt.
3.5.2
Switch-Anweisung
Ein Switch-Statement hat die Syntax:
switch (expr )
{
label :
cmdlist
label :
KAPITEL 3. GRUNDKURS ESH
26
cmdlist
...
}
Bei label handelt es sich um einen Label der Form case val oder default. Der Ausdruck val wird
bereits beim Lesen des Switch-Statements berechnet. Der Ausdruck expr wird der Reihe nach mit
allen Labels verglichen. Stimmt er mit val überein, wird die nachfolgende Liste von Ausdrücken
ausgewertet. Falls in der Liste keine break-, continue- oder return-Anweisung vorkommt, werden
die Ausdrücke des nachfolgenden Labels mit ausgewertet. Stimmt expr mit keinem Wert val der
Labels überein, werden die Ausdrücke von default verwendet.
Anders als in C sind in esh beliebige Datentypen für Switch-Statements erlaubt. Die einzige Bedingung ist, daß der Operator == für diesen Datentype definiert ist. So können in esh z.B. Zeichenketten
oder Reguläre Ausdrücke in Switch-Statements verwendet werden. Nicht jeder Datentyp eignet sich
gut für Switch-Statements.
3.6
Programmumgebung
3.6.1
Programmargumente
Wird ein esh-Skript aufgerufen, können zusätzliche Argumente zur Steuerung des Skripts übergeben werden. Dazu stehen die Variablen argc und argv zur Verfügung. Bei argc handelt es sich um
einen Ganzzahlwert mit der Zahl der übergebenen Argumente, während argv der Vektor mit den
Argumenten ist. Das erste Element argv[0] enthält immer den Aufrufnamen des Skripts, argc ist
immer größer oder gleich 1.
Die Funktion shift mit dem optionalen Parameter n = 1 löscht n Argumente an der Position 1
aus dem Argumentvektor. Das erste Argument argv[0] bleibt dabei unverändert. Die Zahl der
Argumente argc wird entsprechend angepaßt.
3.6.2
Umgebungsvariablen
Umgebungsvariablen können mit der Funktion getenv abgefragt werden. Die Syntax ist:
str getenv (str name, str def = NULL)
Dabei bestimmt name den Namen der Umgebungsvariable und def ist der Vorgabewert, falls die
Umgebungsvariable nicht definiert ist.
Beispiele:
getenv("HOME")
getenv("LANG", "us")
Das nächste Kapitel beschäftigt sich ausführlicher mit der Abfrage von Programmargumenten.
Kommandos
27
efeuscript(1)
28
BEZEICHNUNG
efeuscript – Installation von Scripts
ÜBERSICHT
efeuscript [ --help[=type] ] [ --version ] [ -u ] [ -g ] [ -e ] [ -r ] [ -s /expr/repl/ ] [ -c name ]
src tg
BESCHREIBUNG
Das Kommando ergänzt das Skript src mit einer Interpreterkennung. Dabei wird der vollständige
Pfad des Interpreters automatisch ermittelt.
Falls bereits eine Interpreterkennung vorhanden ist, wird diese nur geprüft und nicht verändert.
Die folgenden Optionen und Argumente werden vom Kommando efeuscript akzeptiert:
--help[=type]
generiert eine Beschreibung des Kommandos. Der zusätzliche Parameter type bestimmt die
Formatierung und die Ausgabe der Beschreibung.
term
Terminalausgabe (default)
raw
Rohformat für efeudoc
man
nroff/troff Sourcen für man
lp
Ausgabe zum Drucker
--version
gibt die Versionsnummer des Kommandos aus.
-u
Nur Eigentümer erhält Ausführungsrechte
-g
Nur Eigentümer und Gruppe erhalten Ausführungsrechte
-e
/usr/bin/env zum Start des Interpreters verwenden
-r
exec zum Start des Interpreters verwenden
-s /expr/repl/
Verwende sed zum Ersetzen von expr durch repl . Mehrfachangaben sind möglich. Anstelle
von / kann auch ein anderes Trennzeichen verwendet werden.
-c name
Name des Befehlsinterpreters, Vorgabe cmd
src
Pfadname des Quellskripts
tg
Pfadname des Zielskripts
COPYRIGHT
Copyright (C) 2001 Erich Frühstück
Literaturverzeichnis
[1] Neil Mathew, Richard Stones. Linux Programmierung, Bonn: MITP-Verlag, 2000
[2] Karsten Günther, Kestler Grelck, Thorsten Zilm. Linux – Die User-Befehlsreferenz, Bonn:
MITP-Verlag, 1999
[3] Bjarne Stroustrup. Die C++ Programmiersprache, Addison.Wesely, Bonn 1992
[4] Erich Frühstück. Make und Co, EFEU–Handbuch
[5] Erich Frühstück. Die Programmbibliothek efm, EFEU–Handbuch
[6] Erich Frühstück. Die Readline-Schnittstelle, EFEU–Handbuch
[7] Erich Frühstück. Die Programmbibliothek md, EFEU–Handbuch
29
Index
!eof, 6
!fc, 6
!history, 6
!r, 6
#, 19
$HOME/lib/efeu/config, 12
^C, 6
^D, 5, 6
Abbruch von esh, 6
APLLPATH, 12
argc, 26
Argumente, 13
Argumentvektor, 12
argv, 26
Auswertungsfunktion, 14
Beenden von esh, 5
Befehlszeilenparameter, 12
Beschreibungstext, 15, 16
CmdPar, 15
CmdPar psub, 14
const, 23
Datenmatrizen, 4
Definitionszeile, 15
Direktiven, 19
EFEU, 1
efeudoc, 8
EFEU-Spezifikation, 8
efm.cnf, 12
esh-Interpreter, 15
exit, 5, 6
Filezusatz .cnf“, 10
”
float prec, 5
Funktionsargument, 14
Kommandodefinitionen, 12
Kommentar, 15
Konfigurationsdatei, 15
LANG, 12
name.cnf, 12
operator, 22
Optionen, 13
Parameterwert, 13
ParseCommand, 12, 14, 15
POSIXLY CORRECT, 8
Präprozessor, 19
Programmdokumentation, 8
regulärer Ausdruck, 16
Resourceabfrage, 12
Resourcetabelle, 12
shift, 26
stackorientierter Interpreter, 4
static, 23
Substitution, 14, 16
Substitutionsdefinition, 14
texmerge, 5
Tischrechner, 5
TOP /lib/efeu/$LANG/config, 12
TOP /lib/efeu/config, 12
Vorgabewert, 16
Wohnungsmarktmodell, 4
X/Open-Spezifikation, 8, 13
Zugriff auf History-Zeilen, 6
Zuweisung, 14
Generierung von Berichten, 4
getenv, 26
getopt, 8
getopts, 8
GetResource, 12
IncPath, 20
30
Impressum
Eigentümer und Verleger:
Erich Frühstück
A-3423 St.Andrä/Wördern
Für den Inhalt verantwortlich:
Erich Frühstück
Herstellung und Redaktion:
Erich Frühstück
Wördern 2001
31
Herunterladen