/* Diese Version ist die letzte Version, in der noch die Groessenparameter im Vektor abgelegt wurden und auf Mehrfachnennungen ueberpruft wurde. Die Version sollte laufen. */ #include /* Teil 1: Definitionen zur Parsierung der Kommandozeilenoptionen */ typedef char * String; typedef enum { nein, ja } Praedikat; /* Globalmachung der Kommandozeilenargumente vermindert die Zahl der zu uebergebenden Argumente an Hilfsfunktionen */ int Argumente, Index, Markierung; String Token, * Kommandozeile; Praedikat weiter (void) /* ist wahr, wenn noch ein weiteres Argument folgt, schiebt als Seiteneffekt Fenster weiter*/ { return ( ++ Index < Argumente && (Token = Kommandozeile [Index] )); } Praedikat zurueck (void) /* hebt den Seiteneffekt eines weiter()s auf und liefert immer nein (das hat einen praktischen Nutzen, siehe unten) */ { Token = Kommandozeile [-- Index]; return nein; } /* Teil 2: Definitionen zur Erkennung der Schluesselwoerter */ typedef enum { linksbuendig, rechtsbuendig, ausgeglichen, auf, die, in, bei, mit, ohne, Seiten, der, Laenge, Spalten, dazwischen, Papierbreite, Rand, links, rechts, oben, unten, Datei, Warnungen} Wort; struct { String abgekuerzt, ausgeschrieben; } Schluesselwort [] = { "lb","linksbuendig", "rb","rechtsbuendig", "as","ausgeglichen", "a", "auf", "d", "die", "i", "in", "b", "bei", "m", "mit", "o", "ohne", "S", "Seiten", "d", "der", "L", "Laenge", "Sp","Spalten", "zw","dazwischen", "P", "Papierbreite", "R", "Rand", "l", "links", "r", "rechts", "o", "oben", "u", "unten", "D", "Datei", "W", "Warnungen" }; /* Vorsicht bei Aenderungen: - die Reihenfolge der enum Schluesselwort muss stets mit der Schluesselworttabelle uebereinstimmen, - saemtliche Woerter, die direkt nach tippe erscheinen duerfen, (linksbuendig bis ohne) muessen zusammenstehen, - Die Richtungen links bis unten sollten in der Ordnung bleiben, so dass sie mit linkerRand bis untererRand korrespondieren. */ Praedikat ist (Wort zupruefen) /* Die Funktion ist(zupruefen) ueberprueft, ob das aktuelle Token, das zu pruefende Schluesselwort ist, ausgeschrieben oder abgekuerzt. */ { return (!strcmp (Token, Schluesselwort[zupruefen].abgekuerzt) || !strcmp (Token, Schluesselwort[zupruefen].ausgeschrieben)); } Wort Fund; Praedikat unter (von, bis) Wort von, bis; /* Untersuche alle Schalter des Aufzaehlungstyps in [von,bis]. Fund enthaelt erstes gefundenes Schluesselwort, sofern vorhanden Returnwert: vorhanden? ja/nein */ { for ( ; von <= bis ; ++ von) if (ist (Fund = von)) return ja; return nein; } int Wert; Praedikat Zahl (void) /* Zahl () ist wahr, wenn das aktuelle Token nur aus Ziffern besteht. Wert ist dann der Zahlenwert. */ { register char Ziffer, * Quelle; Quelle = Token; for (Wert = 0; Ziffer = * Quelle++ ; Wert = 10 * Wert + Ziffer) if ((Ziffer -= '0') < 0 || Ziffer > 9) return nein; return ja; } /* Teil 3: Definitionen zur Einstellung der variablen Groessen */ typedef enum { Satzrichtung, Warnungsanzeige, Gesamtbreite, Spaltenzahl, Zwischenraum, Seitenzahl, Seitenlaenge, linkerRand, rechterRand, obererRand, untererRand, Eingabedateiname, Ausgabedateiname, GN} Groesse; long Parameter [GN] = { ausgeglichen, ja, 80, 1, 4, 1, 1000, 0, 0, 0, 0, 0, 1 }; /* In Parameter [] stehen nach der Kommandozeileninterpretation die eingestellten Optionen, mit denen der Text formatiert werden kann, an und fuer sich braeuchte sich der werte Herr Setzer keine Gedanken darueber zu machen, wie ich die da hereinbekomme. In long koennen auch Stringpointer und Aufzaehlungstypen gespeichert werden. Die Initialisierung sorgt fuer linksbuendigen 1-spaltigen Satz auf einem 80-spaltigen Schirm mit Warnungen, alle anderen Groessen sind defaultmaessig 0 */ String Bezeichnung [GN] = {"Satzrichtung", "Warnungsanzeige", "Papierbreite", "Spaltenzahl", "Zwischenraum", "Seiten", "Seitenlaenge", "linker Rand", "rechter Rand", "oberer Rand", "untererRand", "Eingabedatei", "Ausgabedatei" }; /* Um Mehrfachangaben derselben Groesse zu erkennen, existiert ...*/ Praedikat gestellt [GN]; /* sollte ueberall auf nein initialisiert sein */ void stelle (Groesse Gr, long Wert) /* Parameter [Gr] wird auf den Wert gesetzt und Flag gehisst */ { if (gestellt [Gr]) { fprintf (stderr, "%s mehrfach angegeben!\n", Bezeichnung [Gr]); exit (1); } Parameter [Gr] = Wert; gestellt [Gr] = ja; } void Anzeige (void) /* Testfunktion, zeigt die verstandenen Parameter */ { Groesse Gr; for (Gr = 0; Gr < GN; Gr ++) printf ("%15s = (%s) %d\n", Bezeichnung[Gr], (gestellt[Gr] ? "angegeben" : "default"), Parameter[Gr]); } void unverstaendlich (void) /* bricht mit Fehlermeldung ab */ { if (Index == Argumente) fprintf (stderr, "Noch mehr Argumente erwartet!\n"); else fprintf (stderr, "Das Argument %s ist unverstaendlich!\n", Token); exit (1); } void Zahlerwartet (void) { fprintf (stderr, "Zahl erwartet nach %s anstelle von %s!\n", Token, Kommandozeile [Index - 1]); exit (1); } /* Teil 4: Interpretieren der Kommandozeilenargumente */ void Parameterzerlegung(void) { while (weiter()) { if (! unter (linksbuendig, ohne)) unverstaendlich (); switch (Fund) { case linksbuendig: case rechtsbuendig: case ausgeglichen: /* Blocksatz */ stelle (Satzrichtung, Fund); break; case auf: /* auf [n] Seiten ... | auf /dev/ttyp2 */ if (! weiter()) unverstaendlich(); if (ist (Seiten)) stelle (Seitenzahl, 20); else if (Zahl() && weiter() && (ist (Seiten) || zurueck())) stelle (Seitenzahl, Wert); else { stelle (Ausgabedateiname, (long) Token); break; } Markierung = Index; if (weiter() && ist (der) && weiter() && ist (Laenge)) if (weiter() && Zahl()) stelle (Seitenlaenge, Wert); else Zahlerwartet (); else Index = Markierung; break; case die: /* tippe die Datei eingabe.txt */ if ((weiter() || zurueck ()) && ist (Datei) && weiter()) stelle (Eingabedateiname, (long) Token); else unverstaendlich(); break; case in: /* in [n] Spalten */ if (! weiter()) unverstaendlich(); if (ist (Spalten)) stelle (Spaltenzahl, 2); else if (Zahl() && weiter() && ist (Spalten)) stelle (Spaltenzahl, Wert); else unverstaendlich(); if (weiter() && (ist (dazwischen) || zurueck())) if (weiter() && Zahl()) stelle (Zwischenraum, Wert); else Zahlerwartet (); break; case bei: /* bei Papierbreite n */ if (weiter() && ist (Papierbreite) && weiter()) if (Zahl()) stelle (Gesamtbreite, Wert); else Zahlerwartet(); else unverstaendlich(); break; case mit: case ohne: /* mit Rand | ohne Warnungen ... */ { Praedikat war_mit, spezielleKanten, WortZahlFolge; Groesse R; war_mit = (Fund == mit); if (! weiter()) unverstaendlich(); if (ist (Warnungen)) { stelle (Warnungsanzeige, war_mit); break; } if (! ist (Rand)) unverstaendlich (); WortZahlFolge = nein; do { spezielleKanten = nein; while (weiter() && (unter (links, unten) || zurueck())) { Markierung = Index; if (ist (ohne) && weiter() && (ist (Warnungen) || ist (Rand))) { Index = Markierung - 1; break; } Index = Markierung; spezielleKanten = ja; stelle (Fund - links + linkerRand, -1); } if (WortZahlFolge) { if (!spezielleKanten) break; if (!weiter () || !Zahl()) Zahlerwartet (Token); } else if (war_mit) if (weiter() && (Zahl() || zurueck())) WortZahlFolge = spezielleKanten; else Wert = 4; else Wert = 0; for (R = linkerRand; R <= untererRand; ++ R) if (! spezielleKanten) stelle (R, Wert); else if (Parameter [R] == -1) Parameter [R] = Wert; } /* mit Rand oben 0 links rechts 10 o W */ while (WortZahlFolge); break; } } } } int main (argc, argv) int argc; String argv[]; { Argumente = argc; Kommandozeile = argv; Index = 0; Parameterzerlegung (); Anzeige (); exit (0); }