DIRECTORY Ascii, IO, PseudoTerminal, Rope, SymTab, UnixSysCalls, UnixTypes, UXStrings; PseudoTerminalImpl: CEDAR PROGRAM IMPORTS IO, Rope, SymTab, UnixSysCalls, UXStrings EXPORTS PseudoTerminal ~ BEGIN OPEN PseudoTerminal; ROPE: TYPE ~ Rope.ROPE; Error: PUBLIC ERROR [code: ATOM, msg: ROPE] ~ CODE; inUse: SymTab.Ref ~ SymTab.Create[]; -- Don't try things that are probably in use anyway Allocate: PUBLIC PROCEDURE [] RETURNS [PseudoTerminal] ~ { pseudoTerminal: PseudoTerminal ¬ NEW[PseudoTerminalRep ¬ []]; ptyGroupNames: ROPE ~ "pqrs"; ptyLineNames: ROPE ~ "0123456789abcdef"; ptyGroups: NAT ~ ptyGroupNames.Length[]; ptyLines: NAT ~ ptyLineNames.Length[]; ptyCount: NAT ~ ptyGroups * ptyLines; PTYName: PROCEDURE [nth: NAT, controller: BOOLEAN] RETURNS [ROPE] ~ { group: NAT ~ nth / ptyLines MOD ptyGroups; line: NAT ~ nth MOD ptyLines; name: ROPE ~ IO.PutFR["/dev/%gty%g%g", [character[IF controller THEN 'p ELSE 't]], [character[ptyGroupNames.Fetch[group]]], [character[ptyLineNames.Fetch[line]]]]; RETURN [name]; }; TryOpening: PROCEDURE [name: ROPE] RETURNS [UnixTypes.FileDescriptor] ~ { IF SymTab.Insert[inUse, name, $TRUE] THEN { nameString: UXStrings.CString ~ UXStrings.Create[from: name]; descriptor: UnixTypes.FileDescriptor ~ UnixSysCalls.Open[ path: nameString, flags: [excl: true, access: RDWR], mode: []]; RETURN [descriptor]; } ELSE RETURN [UnixTypes.FileDescriptor.error] }; THROUGH [0..2) DO FOR pty: NAT IN [0 .. ptyCount) DO pseudoTerminal.controllerName ¬ PTYName[nth: pty, controller: TRUE]; pseudoTerminal.controllerFD ¬ TryOpening[name: pseudoTerminal.controllerName]; IF pseudoTerminal.controllerFD # UnixTypes.FileDescriptor.error THEN { pseudoTerminal.slaveName ¬ PTYName[nth: pty, controller: FALSE]; EXIT; } ENDLOOP; IF pseudoTerminal.controllerFD = UnixTypes.FileDescriptor.error THEN SymTab.Erase[inUse] -- Retry - some may have come free ELSE EXIT; ENDLOOP; IF pseudoTerminal.controllerFD = UnixTypes.FileDescriptor.error THEN { ERROR Error[ code: $CantAllocatePseudoTerminal, msg: "unable to allocate pseudo-terminal (/dev/pty* all in use)"]; }; RETURN [pseudoTerminal]; }; Close: PUBLIC PROCEDURE [pty: PseudoTerminal] ~ { IF pty.controllerFD # UnixTypes.FileDescriptor.error THEN { [] ¬ UnixSysCalls.Close[fd: pty.controllerFD]; pty.controllerFD ¬ UnixTypes.FileDescriptor.error; [] ¬ SymTab.Delete[inUse, pty.controllerName]; }; }; END. ’ PseudoTerminalImpl.mesa Copyright Σ 1989, 1990, 1991 by Xerox Corporation. All rights reserved. Brent Welch, September 26, 1990 10:00 am PDT -- extracted from Plumber Michael Plass, September 24, 1991 2:31 pm PDT Allocate loops through the available names for ptys until it finds an unused one. It opens the master end of the pty and returns the name for the corresponding slave tty device. ΚO•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ Πerœ=™HK™FK™-K™—KšΟk œžœC˜VK˜KšΟnœžœž˜!Kšžœžœ'˜1Kšžœ˜šœž˜K˜Kšžœ˜Kšžœžœžœ˜K˜š Ÿœžœžœžœžœžœ˜3K˜——šΟbœ«™³šœ%Οc3˜XK˜—šŸœžœžœ˜:Kšœ!žœ˜=Kšœžœ ˜šœžœ˜(Kšœ žœ˜(Kšœ žœ˜&Kšœ žœ˜%—š Ÿœž œžœžœžœžœ˜EKšœžœžœ ˜*Kšœžœžœ ˜šœžœžœ˜'Kšœ žœ žœžœ˜+Kšœ(˜(Kšœ'˜'—Kšžœ˜K˜—šŸ œž œžœžœ˜Išžœ"˜$šžœ˜Kšœ=˜=šœ9˜9Kšœ.žœ ˜?—Kšžœ˜Kšœ˜—Kšžœžœ!˜,—Kšœ˜—šžœž˜šžœžœžœž˜"Kšœ>žœ˜DKšœN˜Nšžœ>žœ˜FKšœ9žœ˜@Kšžœ˜K˜—Kšžœ˜—šžœ=˜?Kšžœ‘"˜;Kšžœžœ˜ —Kšžœ˜—šžœ>žœ˜Fšžœ˜ Kšœ#˜#KšœB˜B—K˜—Kšžœ˜Kšœ˜K˜—šŸœžœ˜1šžœ3žœ˜;Kšœ.˜.Kšœ2˜2Kšœ.˜.Kšœ˜—Kšœ˜K˜—Kšžœ˜—K˜K˜—…— X9