home *** CD-ROM | disk | FTP | other *** search
- (*$U-*) { Compiler-Option, die bewirkt, dass das nach- }
- { folgende Programm als Systemprogramm ueber- }
- { setzt wird. Gleichzeitig werden auch die }
- { folgenden Optionen gesetzt: }
- {(*$R-*) Bereichsueberschreitungen erlaubt }
- {(*$V-*) keine Pruefung der Stringlaengen }
- {(*$I-*) I/O-Fehler werden nicht geprueft }
- {(*$G+*) GOTO-Anweisung erlaubt }
-
- SEGMENT Pascalsystem;(* Segment 0 *)
-
- (******************************************)
- (* *)
- (* M E N U Revision [0.5b] *)
- (* *)
- (* Auswahl und Start von Programmen *)
- (* *)
- (*$C von Klaus Seiler, Februar 1986 *)
- (* *)
- (******************************************)
-
- CONST MaxUnit = 20; (* Max. physikalische Unit-# *)
- VidLeng = 7; (* Laenge des Volumenamens *)
- FNamLeng = 23; (* Laenge des Filenamens *)
-
- TYPE UnitNum = 0..MaxUnit;
- Vid = STRING[VidLeng ];
- FilNam = STRING[FNamLeng];
-
- VAR SysVars1 : ARRAY[1..125 ] OF INTEGER;
- UnitTable : (* Geraetetabelle des Betriebssystems *)
- ARRAY[UnitNum] OF RECORD
- UVid : Vid
- CASE UisBlkd : BOOLEAN OF
- TRUE : (UEovBlk : INTEGER)
- END;
- SysVars2 : ARRAY[252..281] OF INTEGER;
- OldNextCode : FilNam; (* UCSD-Pascal Version II.1 *)
- (* Apple-Pascal Version 1.1 *)
- SysVars3 : ARRAY[294..327] OF INTEGER;
- NewNextCode : FilNam; (* Apple-Pascal Version 1.2 *)
-
- (*========================================================*)
- (* Eigentliches Benutzerprogramm *)
- (* Normalerweise: PROGRAM Menu(INPUT,OUTPUT); *)
-
- SEGMENT PROCEDURE Menu (Xinput, Xoutput : INTEGER);
- (* Segment 1 *)
-
- CONST SystemID = -16607; (* Version des Systems *)
- FBlkSize = 512; (* Disketten-Block Laenge *)
- MaxDir = 77; (* Max. Katalogeintraege *)
- DirBlk = 2; (* erster phys. Dir.-Block *)
- TidLeng = 15; (* Laenge der Titel-ID *)
- Width = 79; (* Bildschirm-Weite *)
- Height = 23; (* Bildschirm-Hoehe *)
- BEL = 7; (* Glocke *)
- VT = 11; (* bis Seitenende loeschen *)
- EM = 25; (* Home-Kontrollzeichen *)
- ESC = 27; (* Escape-Zeichen *)
- GS = 29; (* bis Zeilenende loeschen *)
- NoError = 0; (* I/O-Result *)
-
- TYPE (* Format des UCSD-Inhaltsverzeichnisses *)
- DirRange = 0..MaxDir;
- Tid = STRING [TidLeng];
- ByteArray = PACKED ARRAY[0..0] OF 0..255;
- BytePtr = ^ByteArray;
- FileKind = (UntypedFile, XdskFile, CodeFile,
- TextFile, InfoFile, DataFile,
- GrafFile, FotoFile, SecureDir);
- DateRec = PACKED RECORD
- Dummy : 0..256;
- Year : 0..100
- END;
- DirEntry = PACKED RECORD
- DLastBlk,
- DFirstBlk : INTEGER
- CASE DFKind : FileKind OF
- SecureDir,
- UntypedFile :
- (Filler1 : 0..4095;
- DVid : Vid;
- DEovBlk : INTEGER;
- DNumFiles : DirRange;
- Dummy : REAL);
- XdskFile,
- CodeFile,
- TextFile,
- InfoFile,
- DataFile,
- GrafFile,
- FotoFile :
- (Filler2 : 0..2047;
- Status : BOOLEAN;
- DTid : Tid;
- DLastByte : 1..FBlkSize;
- DAccess : DateRec)
- END;(* DirEntry *)
- Directory = ARRAY [DirRange] OF DirEntry;
- DirP = ^Directory;
-
- VAR EdiEsc, EraseEol,
- EraseEos, Home : CHAR; (* Kontrollzeichen *)
- LastUnit : UnitNum; (* Versionsbedingung *)
- Switch : BytePtr; (* Zeiger auf SystemID *)
- GDirP : DirP; (* Zeiger auf Katalog *)
-
- (*--------------------------------------------------------*)
- (* Inhaltsverzeichnis des Geraets FUnit lesen und ab der *)
- (* Adresse GDirP abspeichern. *)
-
- FUNCTION FetchDir (FUnit : UnitNum) : BOOLEAN;
-
- VAR Indx : DirRange;
- Ok : BOOLEAN;
-
- BEGIN
- Mark (GDirP);
- (* keinen Speicherplatz reservieren *)
- (* new (GDirP) geht auch *)
-
- unitread (FUnit, GDirP^, SizeOf (Directory), DirBlk);
- Ok := IOResult = NoError;
- WITH GDirP^[0], UnitTable [FUnit] DO BEGIN
- IF Ok THEN BEGIN (* Lesen war erfolgreich, Directory untersuchen *)
- Ok := (DFirstBlk = 0) AND
- (DFKind IN [UntypedFile, SecureDir]) AND
- (Length (DVid) IN [1..VidLeng]) AND
- (DNumFiles >= 0) AND (DNumFiles <= MaxDir);
- IF DVid <> UVid THEN BEGIN (* neues Volume in Unit *)
- Indx := 1;
- WHILE (Indx <= DNumFiles) OR NOT Ok DO
- WITH GDirP^[Indx] DO (* Eintraege testen *)
- IF NOT (Length (DTid) IN [1..TidLeng]) OR
- (DLastBlk < DFirstBlk) OR
- (DLastByte > FBlkSize) OR
- (DLastByte <= 0) OR
- (DAccess.Year >= 100) THEN
- Ok := FALSE
- ELSE
- Indx := Indx + 1;
- IF Ok THEN BEGIN (* in Geraetetabelle aufnehmen *)
- UVid := DVid;
- UEovBlk := DEovBlk
- END
- END
- END;
- FetchDir := Ok;
- IF NOT Ok THEN BEGIN (* aus Geraetetabelle loeschen *)
- UVid := '';
- UEovBlk := MaxInt;
- GDirP := NIL
- END
- END (* with *)
- END;(* FetchDir *)
-
- (*--------------------------------------------------------*)
- (* Ein zulaessiges Zeichen einlesen *)
-
- FUNCTION GetChar (LastCh : CHAR) : CHAR;
-
- VAR Ch : CHAR;
- Ok : BOOLEAN;
-
- BEGIN
- REPEAT
- Read(keyboard, Ch);
- (* keyboard entspricht der Datei KBD in Turbo-Pascal *)
-
- IF (LastCh >= 'A') AND (LastCh <= 'Z') AND
- (Ch >= 'a') AND (Ch <= 'z') THEN
- Ch := Chr (Ord (Ch) - Ord ('a') + Ord ('A'));
- Ok := (Ch = EdiEsc) OR
- ((Ch >= 'A') AND (Ch <= 'Z')) OR
- ((Ch >= 'a') AND (Ch <= 'z')) OR
- ((Ch >= '0') AND (Ch <= '9') AND (LastCh <= '9'));
- IF NOT Ok THEN Write (Chr (BEL))
- UNTIL Ok;
- GetChar := Ch
- END;(* GetChar *)
-
- (*--------------------------------------------------------*)
- (* Naechstes Code-File aussuchen *)
-
- PROCEDURE Get (VAR NextCodeFile : FilNam);
-
- VAR FCount : INTEGER;
- LNumFiles : DirRange;
- SelCh : CHAR;
- Ch : CHAR;
- Select : ARRAY['0'..'z'] OF DirRange;
- LDir : Directory;
-
-
-
- (*- - - - - - - - - - - - - - - - - - - - - - - - - -*)
- (* Geraet auswaehlen *)
-
- FUNCTION WhichUnit : UnitNum;
-
- VAR LUnit : INTEGER;
- Ok : BOOLEAN;
-
- BEGIN
- GotoXY (0,4);
- WriteLn (EraseEos, 'Unit-Tabelle:');
- WriteLn;
- FOR LUnit := 4 TO LastUnit DO
- WITH UnitTable [LUnit] DO
- IF UisBlkd AND (Length (UVid) > 0) THEN
- WriteLn ('#',LUnit:2,': ',UVid,':');
- Ok := FALSE;
- REPEAT
- Write (Home,
- 'Welche Unit ? # [<esc> verlassen]',
- EraseEol);
- GotoXY (15,0);
- Read (LUnit);
- IF IOResult <> NoError THEN (* Fehler im Eingabeformat *)
- Exit(Get); (* z. B <esc> *)
- ReadLn; (* "integer" besser mit "readln" lesen *)
- IF (LUnit < 4) OR (LUnit > LastUnit) THEN
- Write ('4..', LastUnit, ' erwartet')
- ELSE
- IF NOT UnitTable [LUnit].UisBlkd THEN
- Write ('Unit #', LUnit,' nicht block-strukturiert')
- ELSE
- Ok := TRUE;
- Write (EraseEol)
- UNTIL Ok;
- WhichUnit := LUnit;
- END;(* WhichUnit *)
-
-
-
- (*- - - - - - - - - - - - - - - - - - - - - - - - - -*)
- (* Inhaltsverzeichnis durchstoebern und alle Pro- *)
- (* gramme sortiert auf dem Bildschirm anzeigen. *)
-
- FUNCTION GetFiles (LUnit : UnitNum;
- VAR Dir : Directory) : BOOLEAN;
-
- (*- - - - - - - - - - - - - - - - - - - - - - - - -*)
- (* Inhaltsverzeichnis sortieren *)
- (* Anm.: Der Compiler muss rekursiven Code *)
- (* erzeugen koennen. *)
-
- PROCEDURE QuickSort (VAR d : Directory; l, r : INTEGER);
-
- VAR i, j : INTEGER;
- Pivot : Tid;
- Entry : DirEntry;
-
- BEGIN
- IF r > l THEN BEGIN
- i := l;
- j := Pred (r);
- Pivot := d[r].DTid; (* Pivot-Element *)
- REPEAT (* Zwei Bereiche so bilden, dass der eine Teil, *)
- (* gemessen am Pivot-Element, nur kleine, der *)
- (* andere Teil nur grosse Elemente enthaelt. *)
- WHILE d[i].DTid < Pivot DO i := Succ (i);
- WHILE (d[j].DTid > Pivot)
- AND (j >= l) DO (* fuer den Fall, dass das Pivot-Element *)
- (* von alphabetisch kleinster Ordnung ist *)
- j := Pred (j);
- IF i < j THEN BEGIN (* Elemente vertauschen *)
- Entry := d[i];
- d[i] := d[j];
- d[j] := Entry;
- i := Succ (i);
- j := Pred (j)
- END
- UNTIL i >= j; (* i ist Pivot-Position; *)
- Entry := d[i]; (* an diese Stelle das *)
- d[i] := d[r]; (* Pivot-Element ablegen *)
- d[r] := Entry;
- QuickSort (d, l, Pred (i));(* Nun beide Stapel *)
- QuickSort (d, Succ (i), r) (* getr. sortieren. *)
- END
- END;(* QuickSort *)
-
-
- BEGIN (* GetFiles *)
- GetFiles := FALSE;
- IF NOT FetchDir (LUnit) THEN BEGIN
- Write ('Kann Katalog von Unit #',LUnit, ' nicht lesen');
- Exit (GetFiles) (* auf ein Neues *)
- END;
- Dir := GDirP^; (* auf zu neuen Taten *)
- WITH Dir[0] DO BEGIN
- WriteLn;
- WriteLn (EraseEos, DVid,': in #',LUnit,' mit ',DNumFiles,' File(s)');
- IF DNumFiles = 0 THEN BEGIN
- Write ('Diskette leer');
- Exit (GetFiles) (* wieder nicht's *)
- END;
- QuickSort (Dir, 1, DNumFiles)
- END;
- GetFiles := TRUE (* jetzt aber ! *)
- END; (* GetFiles *)
-
- BEGIN (* Get *)
- NextCodeFile := '';
- REPEAT
- REPEAT UNTIL GetFiles (WhichUnit, LDir);
- SelCh := Pred ('A');
- LNumFiles := 0;
- FCount := -1;
- REPEAT (* alle Code-Files anzeigen *)
- LNumFiles := LNumFiles + 1;
- IF LDir[LNumFiles].DFKind = CodeFile THEN BEGIN
- FCount := FCount + 1;
- IF SelCh = 'Z' THEN (* Nachfolger finden *)
- SelCh := 'a'
- ELSE
- IF SelCh = 'z' THEN
- SelCh := '0'
- ELSE
- SelCh := Succ(SelCh);
- GotoXY (FCount DIV (Height-4) * 20,
- FCount MOD (Height-4) + 4);
- Write ('(',SelCh,') ', LDir[LNumFiles].DTid);
- Select[SelCh] := LNumFiles
- END
- UNTIL (SelCh = '9') OR (LNumFiles = LDir[0].DNumFiles);
- Ch := EdiEsc;
- IF FCount < 0 THEN
- Write ('kein Code-File gefunden')
- ELSE BEGIN (* Es wird doch noch was *)
- Write (Home, 'Welches Programm starten ? (A..',
- SelCh, ') <esc> verlassen', EraseEol);
- Ch := GetChar (SelCh)
- END;
- Page (Output)
- UNTIL Ch <> EdiEsc; (* Dann nochmal von vorne *)
- NextCodeFile := Concat (LDir[0].DVid, ':',
- LDir[Select[Ch]].DTid);
- IF Length (NextCodeFile) < FNamLeng THEN (* keinen Suffix anhaengen *)
- Insert('.', NextCodeFile, Length (NextCodeFile) + 1);
- WriteLn (NextCodeFile, ' ausfuehren...')
- END;
-
- (*--------------------------------------------------------*)
-
- BEGIN (* Menu *)
- Switch := NIL; {(*$R-*) notwendig }
- IF Switch^[SystemID] = 3 THEN { Pascal 1.2 ! }
- LastUnit := 20 { Anzahl der max. }
- ELSE { moeglichen Units, }
- LastUnit := 12;
- EdiEsc := Chr (ESC); { Bildschirm- und }
- Home := Chr (EM); { Eingabesteuer- }
- EraseEol := Chr (GS); { zeichen setzen }
- EraseEos := Chr (VT);
- Page(Output);
- IF LastUnit = MaxUnit THEN { Pascal 1.2 ? }
- Get (NewNextCode)
- ELSE
- Get (OldNextCode)
- END; (* Menu *)
-
- (*========================================================*)
-
- BEGIN (* PascalSystem *)
- (* Dummyblock des Pascalsystems kann mit dem *)
- (* dem Dienstprogramm LIBRARY.CODE geloescht *)
- (* werden, indem nur das Segment MENU (S# 1) *)
- (* auf ein neues File kopiert wird. *)
- END. (* PascalSystem *)
-
-