DIRECTORY Ascii USING [NUL], CLibraryDefs USING [cNULL, Error, exit, open], UnixDefs USING [numOpenFiles, fileInfo, openFiles], MFile USING [Error, Handle, ReadOnly], MStream USING [Handle], MLoader USING [Handle, Run], Heap USING [systemZone], Put USING [Line, LongString], Tool USING [Create, MakeTTYSW, MakeSWsProc, UnusedLogName], ToolWindow USING [TransitionProcType], TTY USING [EchoClass], TTYSW USING [SetEcho, GetLine], Window USING [Handle]; UnixImpl: PROGRAM IMPORTS MFile, MLoader, CLibraryDefs, Heap, Put, Tool, TTYSW, UnixDefs EXPORTS UnixDefs = { DataHandle: TYPE = LONG POINTER TO Data; Data: TYPE = MACHINE DEPENDENT RECORD [ ttySW(0): Window.Handle ← NIL ]; -- Variable declarations ttyWindow: PUBLIC Window.Handle; openFiles: PUBLIC ARRAY [0..UnixDefs.numOpenFiles) OF UnixDefs.fileInfo; argcT: LONG INTEGER ← 0; argvT: LONG POINTER TO LONG POINTER TO INTEGER ← NIL; argvRef: ARRAY [0..10) OF LONG POINTER TO INTEGER ← ALL[NIL]; argvRefRef: ARRAY [0..10) OF ARRAY [0..30) OF INTEGER ← ALL[ALL[0]]; p: PROCESS RETURNS []; toolData: DataHandle ← NIL; wh: Window.Handle; -- Tool's window WatchTTY: PROCEDURE = { -- Do the tasks necessary to execute a form subwindow command. -- Again, if the command will take a long time, then one might FORK a PROCESS to do it. oldEcho: TTY.EchoClass; userInput: LONG STRING ← [100]; fileName: LONG STRING ← [50]; iLine, iArg, iChar, commandLength: CARDINAL; redirect: INTEGER; commandFile: MFile.Handle; commandHandle: MLoader.Handle; Put.Line[toolData.ttySW, "Simple Shell Starting."L]; oldEcho ← TTYSW.SetEcho[ttyWindow, plain]; DO -- forever -- reset the standard input, output and error UnixDefs.openFiles[0].windowHandle ← toolData.ttySW; UnixDefs.openFiles[0].type ← window; UnixDefs.openFiles[1].windowHandle ← toolData.ttySW; UnixDefs.openFiles[1].type ← window; UnixDefs.openFiles[2].windowHandle ← toolData.ttySW; UnixDefs.openFiles[2].type ← window; -- put out the shell prompt and get a command line of input Put.LongString[toolData.ttySW, "% "L]; TTYSW.GetLine[ttyWindow, userInput]; -- parse the command line arguments userInput.text[userInput.length] ← ' ; -- blank at end iArg ← 0; iLine ← 0; argcT ← 0; WHILE iLine < userInput.length DO WHILE userInput.text[iLine] = ' DO -- skip blanks iLine ← iLine + 1; ENDLOOP; iChar ← 0; redirect ← -1; IF userInput.text[iLine] = '< THEN { redirect ← 0; iLine ← iLine + 1; } ELSE IF userInput.text[iLine] = '> THEN { redirect ← 1; iLine ← iLine + 1; }; WHILE userInput.text[iLine] # ' DO -- copy word argvRefRef[iArg][iChar] ← userInput.text[iLine]-0C; iLine ← iLine + 1; iChar ← iChar + 1; ENDLOOP; argvRefRef[iArg][iChar] ← Ascii.NUL-0C; IF iArg = 0 THEN commandLength ← iLine; SELECT redirect FROM -1 => iArg ← iArg + 1; 0, 1 => { UnixDefs.openFiles[redirect].type ← unused; IF CLibraryDefs.open[argvRef[iArg], 2] # redirect THEN CLibraryDefs.Error[ "Can't open redirected input or output file.\n"L]; }; ENDCASE => ERROR; ENDLOOP; argcT ← iArg; userInput.text[commandLength] ← '.; userInput.text[commandLength+1] ← 'b; userInput.text[commandLength+2] ← 'c; userInput.text[commandLength+3] ← 'd; userInput.length ← commandLength+4; { commandFile ← MFile.ReadOnly[userInput, [] ! MFile.Error => { GO TO BadCommand; }; ]; commandHandle ← MLoader.Run[commandFile]; EXITS BadCommand => Put.Line[toolData.ttySW, "Command not found."L]; }; userInput.length ← 0; CLibraryDefs.exit[0]; ENDLOOP; -- later we should put this back in -- MLoader.Unload[commandHandle]; }; ClientTransition: ToolWindow.TransitionProcType = { SELECT TRUE FROM old = inactive => { IF toolData = NIL THEN toolData ← Heap.systemZone.NEW[Data ← []]; argvT ← @argvRef[0]; FOR i: CARDINAL IN [0..10) DO argvRef[i] ← @argvRefRef[i][0]; ENDLOOP; }; new = inactive => IF toolData # NIL THEN { Heap.systemZone.FREE[@toolData]}; ENDCASE; }; Init: PROCEDURE = { wh ← Tool.Create[ makeSWsProc: MakeSWs, initialState: default, initialBox: [[0, 70], [500, 600]], clientTransition: ClientTransition, name: "Unix"L, tinyName1: "Unix"L]; }; MakeSWs: Tool.MakeSWsProc = { logName: STRING ← [40]; Tool.UnusedLogName[unused: logName, root: "Unix.log"L]; toolData.ttySW ← Tool.MakeTTYSW[window: window, name: logName]; ttyWindow ← toolData.ttySW; }; GetArgs: PUBLIC PROCEDURE [argc: LONG POINTER TO LONG INTEGER, argv: LONG POINTER TO LONG POINTER TO LONG POINTER TO INTEGER] = { argv↑ ← argvT; argc↑ ← argcT; }; -- Mainline code Init[]; FOR i: CARDINAL IN [0..UnixDefs.numOpenFiles) DO UnixDefs.openFiles[i].type ← unused; UnixDefs.openFiles[i].windowHandle ← NIL; UnixDefs.openFiles[i].streamHandle ← NIL; ENDLOOP; p ← FORK WatchTTY[]; }...